Discussion:
code available: netmap support for libpcap
Luigi Rizzo
2014-02-15 20:17:27 UTC
Permalink
I have created a repo with a cloned copy of the pcap repository
with netmap support:

https://code.google.com/p/netmap-libpcap

With that, you can easily have tcpdump (and any libpcap application)
process 10-15Mpps with a single thread through NICs in netmap mode
(see http://info.iet.unipi.it/~luigi/netmap/ ) ports of the VALE
software switch (part of netmap), or "netmap pipes".

To try it, fetch the netmap code (for Linux and FreeBSD) is at

https://code.google.com/p/netmap

You don't need a 10G interface, you can simply test across VALE
ports or netmap pipes using the pkt-gen traffic generator in the
netmap distribution, and tcpdump using the new libpcap:

# send on the master side of a netmap pipe called vale:p0
# pkt-gen produces udp traffic
pkt-gen -i vale:p}0 -f tx
# receive from the slave side of the pipe with tcpdump
# tcpdump -nlei vale:p{0 tcp

and enjoy the counters on the sender side (the pipe is blocking,
so the numbers on the sender side reflect the speed of the receiver).

I would like to understand if there is interest for this stuff,
obviously I'd rather see this integrated in the main distribution
than have to point people to our repo.

Diff attached for the curious.

cheers
luigi

diff --git a/Makefile.in b/Makefile.in
index 47f5a06..5e90533 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -83,7 +83,7 @@ YACC = @V_YACC@
@rm -f $@
$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c

-PSRC = pcap-@***@.c @USB_SRC@ @BT_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@
+PSRC = pcap-@***@.c @USB_SRC@ @BT_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ @NETMAP_SRC@
FSRC = fad-@***@.c
SSRC = @SSRC@
CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \
@@ -314,6 +314,7 @@ EXTRA_DIST = \
pcap-namedb.h \
pcap-netfilter-linux.c \
pcap-netfilter-linux.h \
+ pcap-netmap.c \
pcap-nit.c \
pcap-null.c \
pcap-pf.c \
diff --git a/config.h.in b/config.h.in
index c6bc68e..09c8557 100644
--- a/config.h.in
+++ b/config.h.in
@@ -268,6 +268,9 @@
/* target host supports netfilter sniffing */
#undef PCAP_SUPPORT_NETFILTER

+/* target host supports netmap */
+#undef PCAP_SUPPORT_NETMAP
+
/* target host supports USB sniffing */
#undef PCAP_SUPPORT_USB

diff --git a/configure b/configure
index 07c2d33..a602df5 100755
--- a/configure
+++ b/configure
@@ -632,6 +632,8 @@ CANUSB_SRC
PCAP_SUPPORT_CANUSB
BT_SRC
PCAP_SUPPORT_BT
+NETMAP_SRC
+PCAP_SUPPORT_NETMAP
NETFILTER_SRC
PCAP_SUPPORT_NETFILTER
USB_SRC
@@ -744,6 +746,7 @@ with_flex
with_bison
enable_universal
enable_shared
+enable_netmap
enable_bluetooth
enable_canusb
enable_can
@@ -1379,6 +1382,8 @@ Optional Features:
--disable-universal don't build universal on OS X
--enable-shared build shared libraries [default=yes, if support
available]
+ --enable-netmap enable netmap support [default=yes, if support
+ available]
--enable-bluetooth enable Bluetooth support [default=yes, if support
available]
--enable-canusb enable canusb support [default=yes, if support
@@ -7995,6 +8000,35 @@ esac



+# Check whether --enable-netmap was given.
+if test "${enable_netmap+set}" = set; then :
+ enableval=$enable_netmap;
+else
+ enable_netmap=yes
+fi
+
+
+if test "x$enable_netmap" != "xno" ; then
+ ac_fn_c_check_header_compile "$LINENO" "net/netmap_user.h" "ac_cv_header_net_netmap_user_h" "$ac_includes_default
+
+"
+if test "x$ac_cv_header_net_netmap_user_h" = xyes; then :
+
+$as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h
+
+ NETMAP_SRC=pcap-netmap.c
+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is supported" >&5
+$as_echo "$as_me: netmap is supported" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is not supported" >&5
+$as_echo "$as_me: netmap is not supported" >&6;}
+fi
+
+
+
+
+fi
+
# Check whether --enable-bluetooth was given.
if test "${enable_bluetooth+set}" = set; then :
enableval=$enable_bluetooth;
diff --git a/configure.in b/configure.in
index 42cbe9b..86b7a74 100644
--- a/configure.in
+++ b/configure.in
@@ -1452,6 +1452,24 @@ esac
AC_SUBST(PCAP_SUPPORT_NETFILTER)
AC_SUBST(NETFILTER_SRC)

+AC_ARG_ENABLE([netmap],
+[AC_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])],
+ [],
+ [enable_netmap=yes])
+
+if test "x$enable_netmap" != "xno" ; then
+ dnl check for netmap support
+ AC_CHECK_HEADER(net/netmap_user.h,
+ [ AC_DEFINE(PCAP_SUPPORT_NETMAP, 1, [target host supports netmap])
+ NETMAP_SRC=pcap-netmap.c
+ AC_MSG_NOTICE(netmap is supported)],
+ AC_MSG_NOTICE(netmap is not supported),
+ AC_INCLUDES_DEFAULT
+ )
+ AC_SUBST(PCAP_SUPPORT_NETMAP)
+ AC_SUBST(NETMAP_SRC)
+fi
+
AC_ARG_ENABLE([bluetooth],
[AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])],
[],
diff --git a/inet.c b/inet.c
index c699658..d132507 100644
--- a/inet.c
+++ b/inet.c
@@ -883,6 +883,10 @@ pcap_lookupnet(device, netp, maskp, errbuf)
#ifdef PCAP_SUPPORT_USB
|| strstr(device, "usbmon") != NULL
#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ || !strncmp(device, "netmap:", 7)
+ || !strncmp(device, "vale", 4)
+#endif
#ifdef HAVE_SNF_API
|| strstr(device, "snf") != NULL
#endif
diff --git a/pcap-netmap.c b/pcap-netmap.c
new file mode 100644
index 0000000..df2d01c
--- /dev/null
+++ b/pcap-netmap.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2014 Luigi Rizzo. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``S IS''AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <poll.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NETMAP_WITH_LIBS
+#include <net/netmap_user.h>
+
+#include "pcap-int.h"
+
+/*
+ * This code is meant to build also on older versions of libpcap.
+ *
+ * older libpcap miss p->priv, use p->md.device instead (and allocate).
+ * Also opt.timeout was in md.timeout before.
+ * Use #define PCAP_IF_UP to discriminate
+ */
+#ifdef PCAP_IF_UP
+#define NM_PRIV(p) ((struct pcap_netmap *)(p->priv))
+#define the_timeout opt.timeout
+#else
+#define HAVE_NO_PRIV
+#define NM_PRIV(p) ((struct pcap_netmap *)(p->md.device))
+#define SET_PRIV(p, x) p->md.device = (void *)x
+#define the_timeout md.timeout
+#endif
+
+#if defined (linux)
+/* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh.
+ * remap to IFF_PROMISC on linux
+ */
+#define IFF_PPROMISC IFF_PROMISC
+#define ifr_flagshigh ifr_flags
+#endif /* linux */
+
+struct pcap_netmap {
+ struct nm_desc *d; /* pointer returned by nm_open() */
+ pcap_handler cb; /* callback and argument */
+ u_char *cb_arg;
+ int must_clear_promisc; /* flag */
+ uint64_t rx_pkts; /* # of pkts received before the filter */
+};
+
+static int
+pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+
+ ps->ps_recv = pn->rx_pkts;
+ ps->ps_drop = 0;
+ ps->ps_ifdrop = 0;
+ return 0;
+}
+
+static void
+pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
+{
+ pcap_t *p = (pcap_t *)arg;
+ struct pcap_netmap *pn = NM_PRIV(p);
+
+ ++pn->rx_pkts;
+ if (bpf_filter(p->fcode.bf_insns, buf, h->len, h->caplen))
+ pn->cb(pn->cb_arg, h, buf);
+}
+
+static int
+pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user)
+{
+ int ret;
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 };
+
+ pn->cb = cb;
+ pn->cb_arg = user;
+
+ for (;;) {
+ if (p->break_loop) {
+ p->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ /* nm_dispatch won't run forever */
+ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p);
+ if (ret != 0)
+ break;
+ poll(&pfd, 1, p->the_timeout);
+ }
+ return ret;
+}
+
+/* XXX need to check the NIOCTXSYNC/poll */
+static int
+pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
+{
+ struct nm_desc *d = NM_PRIV(p)->d;
+
+ return nm_inject(d, buf, size);
+}
+
+static int
+pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ struct ifreq ifr;
+ int error, fd = d->fd;
+
+#ifdef linux
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Error: cannot get device control socket.\n");
+ return -1;
+ }
+#endif /* linux */
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name));
+ switch (what) {
+ case SIOCSIFFLAGS:
+ ifr.ifr_flags = *if_flags;
+ ifr.ifr_flagshigh = *if_flags >> 16;
+ break;
+ }
+ error = ioctl(fd, what, &ifr);
+ fprintf(stderr, "%s %s ioctl 0x%lx returns %d\n", __FUNCTION__,
+ d->req.nr_name, what, error);
+ if (error)
+ return -1;
+ switch (what) {
+ case SIOCGIFFLAGS:
+ *if_flags = ifr.ifr_flags | (ifr.ifr_flagshigh << 16);
+ }
+ return 0;
+}
+
+static void
+pcap_netmap_close(pcap_t *p)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ uint32_t if_flags = 0;
+
+ if (pn->must_clear_promisc) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (if_flags & IFF_PPROMISC) {
+ if_flags &= ~IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ nm_close(d);
+#ifdef HAVE_NO_PRIV
+ free(pn);
+ SET_PRIV(p, NULL); // unnecessary
+#endif
+ pcap_cleanup_live_common(p);
+}
+
+static int
+pcap_netmap_activate(pcap_t *p)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = nm_open(p->opt.source, NULL, 0, NULL);
+ uint32_t if_flags = 0;
+
+ if (d == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "netmap open: cannot access %s: %s\n",
+ p->opt.source, pcap_strerror(errno));
+#ifdef HAVE_NO_PRIV
+ free(pn);
+ SET_PRIV(p, NULL); // unnecessary
+#endif
+ pcap_cleanup_live_common(p);
+ return (PCAP_ERROR);
+ }
+ fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n",
+ __FUNCTION__, p->opt.source, d, d->fd,
+ d->first_rx_ring, d->last_rx_ring);
+ pn->d = d;
+ p->fd = d->fd;
+ if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (!(if_flags & IFF_PPROMISC)) {
+ pn->must_clear_promisc = 1;
+ if_flags |= IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ p->linktype = DLT_EN10MB;
+ p->selectable_fd = p->fd;
+ p->read_op = pcap_netmap_dispatch;
+ p->inject_op = pcap_netmap_inject,
+ p->setfilter_op = install_bpf_program;
+ p->setdirection_op = NULL;
+ p->set_datalink_op = NULL;
+ p->getnonblock_op = pcap_getnonblock_fd;
+ p->setnonblock_op = pcap_setnonblock_fd;
+ p->stats_op = pcap_netmap_stats;
+ p->cleanup_op = pcap_netmap_close;
+ return (0);
+}
+
+pcap_t *
+pcap_netmap_create(const char *device, char *ebuf, int *is_ours)
+{
+ pcap_t *p;
+
+ *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
+ if (! *is_ours)
+ return NULL;
+#ifdef HAVE_NO_PRIV
+ {
+ void *pn = calloc(1, sizeof(struct pcap_netmap));
+ if (pn == NULL)
+ return NULL;
+ p = pcap_create_common(device, ebuf);
+ if (p == NULL) {
+ free(pn);
+ return NULL;
+ }
+ SET_PRIV(p, pn);
+ }
+#else
+ p = pcap_create_common(device, ebuf, sizeof (struct pcap_netmap));
+ if (p == NULL)
+ return (NULL);
+#endif
+ p->activate_op = pcap_netmap_activate;
+ return (p);
+}
diff --git a/pcap.c b/pcap.c
index b2b5da6..beda714 100644
--- a/pcap.c
+++ b/pcap.c
@@ -104,6 +104,10 @@
#include "pcap-dbus.h"
#endif

+#ifdef PCAP_SUPPORT_NETMAP
+pcap_t* pcap_netmap_create(const char *device, char *ebuf, int *is_ours);
+#endif
+
int
pcap_not_initialized(pcap_t *pcap _U_)
{
@@ -307,6 +311,9 @@ struct capture_source_type {
int (*findalldevs_op)(pcap_if_t **, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
+#ifdef PCAP_SUPPORT_NETMAP
+ { NULL, pcap_netmap_create },
+#endif
#ifdef HAVE_DAG_API
{ dag_findalldevs, dag_create },
#endif
Michael Richardson
2014-02-15 21:15:59 UTC
Permalink
So, basically if we use a device name like "netmap:" or "vale",
then we would get support for it. Are there dependancies that would
piss off distros that we should worry about? You say that we need netmap,
but I don't see where in the build it references some new library.

Fork, and push your branch to github, and let's see what travis-CI says.
You may want to update .travis.yml to include netmap....

--
] Never tell me the odds! | ipv6 mesh networks [
] Michael Richardson, Sandelman Software Works | network architect [
] ***@sandelman.ca http://www.sandelman.ca/ | ruby on rails [
Luigi Rizzo
2014-02-15 21:24:27 UTC
Permalink
Post by Michael Richardson
So, basically if we use a device name like "netmap:" or "vale",
then we would get support for it. Are there dependancies that would
piss off distros that we should worry about? You say that we need netmap,
but I don't see where in the build it references some new library.
There isn't any new library, which eases distributing binaries.

./configure checks for the presence of the netmap headers,
and if so compiles the extra file.

At runtime, netmap only uses open(), ioctl(), mmap() and poll().

Data structures are simple enough that a few macros
or inline functions in netmap_user.h are all is needed
to access the port and do I/O.

cheers
luigi
Guy Harris
2014-02-15 21:37:03 UTC
Permalink
Post by Luigi Rizzo
At runtime, netmap only uses open(), ioctl(), mmap() and poll().
...and nm_dispatch(). Is that an inline function defined in the headers?
Luigi Rizzo
2014-02-15 21:40:45 UTC
Permalink
Post by Guy Harris
Post by Luigi Rizzo
At runtime, netmap only uses open(), ioctl(), mmap() and poll().
...and nm_dispatch(). Is that an inline function defined in the headers?
yes, same as nm_open() and a few others: this is what
i meant when I said

Data structures are simple enough that a few macros
or inline functions in netmap_user.h are all is needed
to access the port and do I/O.




cheers
luigi
--
-----------------------------------------+-------------------------------
Prof. Luigi RIZZO, ***@iet.unipi.it . Dip. di Ing. dell'Informazione
http://www.iet.unipi.it/~luigi/ . Universita` di Pisa
TEL +39-050-2211611 . via Diotisalvi 2
Mobile +39-338-6809875 . 56122 PISA (Italy)
-----------------------------------------+-------------------------------
Michael Richardson
2014-02-15 21:44:21 UTC
Permalink
Luigi Rizzo <***@iet.unipi.it> wrote:
mcr> So, basically if we use a device name like "netmap:" or "vale",
mcr> then we would get support for it.  Are there dependancies that would
mcr> piss off distros that we should worry about?  You say that we need
mcr> netmap,
mcr> but I don't see where in the build it references some new library.
Post by Luigi Rizzo
There isn't any new library, which eases distributing binaries.
./configure checks for the presence of the netmap headers,
and if so compiles the extra file.
where do those headers come from? Would it make sense to just include
those headers with libpcap? That way netmap would always be available.
Post by Luigi Rizzo
At runtime, netmap only uses open(), ioctl(), mmap() and poll().
Data structures are simple enough that a few macros
or inline functions in netmap_user.h are all is needed
to access the port and do I/O.
Are there any issues if someone makes tcpdump (or wireshark, or some other
libpcap using program) setuid? (I don't see any call to popen()...)

--
] Never tell me the odds! | ipv6 mesh networks [
] Michael Richardson, Sandelman Software Works | network architect [
] ***@sandelman.ca http://www.sandelman.ca/ | ruby on rails [
Guy Harris
2014-02-15 21:59:48 UTC
Permalink
Post by Michael Richardson
where do those headers come from? Would it make sense to just include
those headers with libpcap? That way netmap would always be available.
There's "netmap", which is available only if the kernel includes netmap support; as long as all systems with a kernel with netmap also provide the headers (at least if you have a "developer package" for the OS installed if necessary), the headers aren't an issue for the availability of netmap.

There's also "netmap support in libpcap", which would only be available if the headers are available on the system on which libpcap is built; that's also the case for some other OS features libpcap can use. If the OS kernel doesn't include netmap support by default, and we want the user to be able to add it to the kernel *and* have libpcap automatically be able to use it without having to rebuild libpcap, the headers *are* an issue.
Post by Michael Richardson
Are there any issues if someone makes tcpdump (or wireshark, or some other
libpcap using program) setuid? (I don't see any call to popen()...)
(I.e., is there any code in the netmap support that could be tricked into doing Bad Things, including handing off privileges to arbitrary programs if the program using libpcap is privileged?)
Luigi Rizzo
2014-02-15 22:24:28 UTC
Permalink
Post by Guy Harris
Post by Michael Richardson
where do those headers come from? Would it make sense to just include
those headers with libpcap? That way netmap would always be available.
There's "netmap", which is available only if the kernel includes netmap support; as long as all systems with a kernel with netmap also provide the headers (at least if you have a "developer package" for the OS installed if necessary), the headers aren't an issue for the availability of netmap.
first of all, thanks all for the feedback.

I think what Michael means is that if we include net/netmap.h and
net/netmap_user.h in the libpcap distribution, we can have the support
always compiled in and postpone the decision at compile time.

This seems a very interesting idea actually.
We can make the build privilege system headers if available
(in case something changes) and fall back to the one included
in the libpcap distribution otherwise.
Post by Guy Harris
There's also "netmap support in libpcap", which would only be available if the headers are available on the system on which libpcap is built; that's also the case for some other OS features libpcap can use. If the OS kernel doesn't include netmap support by default, and we want the user to be able to add it to the kernel *and* have libpcap automatically be able to use it without having to rebuild libpcap, the headers *are* an issue.
Post by Michael Richardson
Are there any issues if someone makes tcpdump (or wireshark, or some other
libpcap using program) setuid? (I don't see any call to popen()...)
(I.e., is there any code in the netmap support that could be tricked into doing Bad Things, including handing off privileges to arbitrary programs if the program using libpcap is privileged?)
apart from bugs, the nm_* functions in the headers only call open/ioctl/mmap,
nothing else. Auditing the headers will certainly help figure out if there
are bugs.

The netmap module gives access to raw packets, and potentially
disconnect a NIC from the system, so normally access is reserved to those
who have access to /dev/netmap (which defaults to -rw------ root root on linux,
and something similar on FreeBSD).
So in this respect things are not much different from what happens with
bpf or equivalent, if you make tcpdump setuid hopefully there are
other restrictions in place that limit who can run tcpdump and
see everyone's traffic.

cheers
luigi
Luigi Rizzo
2014-02-15 22:27:49 UTC
Permalink
On Sat, Feb 15, 2014 at 11:24:28PM +0100, Luigi Rizzo wrote:
...
Post by Luigi Rizzo
I think what Michael means is that if we include net/netmap.h and
net/netmap_user.h in the libpcap distribution, we can have the support
always compiled in and postpone the decision at compile time.
^^^^^^^

clearly i meant "run" time,

cheers
luigi
Guy Harris
2014-02-15 21:41:41 UTC
Permalink
Post by Luigi Rizzo
+ p->linktype = DLT_EN10MB;
So this either

1) only works on Ethernet devices and devices that supply Ethernet headers

or

2) generates Ethernet headers that replace the native link-layer headers for devices that don't supply Ethernet headers?
Post by Luigi Rizzo
@@ -307,6 +311,9 @@ struct capture_source_type {
int (*findalldevs_op)(pcap_if_t **, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
+#ifdef PCAP_SUPPORT_NETMAP
+ { NULL, pcap_netmap_create },
+#endif
#ifdef HAVE_DAG_API
{ dag_findalldevs, dag_create },
#endif
This means that "tcpdump -D/tshark -D" and the Wireshark GUI won't show netmap or vale devices; for command-line tools, this means you have to enter those devices manually, but it might make it impossible to capture on those devices in the Wireshark GUI.

Can you enumerate the netmap and vale devices? If so, you should have a findalldevs routine.
Luigi Rizzo
2014-02-15 22:10:05 UTC
Permalink
Post by Guy Harris
Post by Luigi Rizzo
+ p->linktype = DLT_EN10MB;
So this either
1) only works on Ethernet devices and devices that supply Ethernet headers
or
2) generates Ethernet headers that replace the native link-layer headers for devices that don't supply Ethernet headers?
it is #1.
Post by Guy Harris
Post by Luigi Rizzo
@@ -307,6 +311,9 @@ struct capture_source_type {
int (*findalldevs_op)(pcap_if_t **, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
+#ifdef PCAP_SUPPORT_NETMAP
+ { NULL, pcap_netmap_create },
+#endif
#ifdef HAVE_DAG_API
{ dag_findalldevs, dag_create },
#endif
This means that "tcpdump -D/tshark -D" and the Wireshark GUI won't show netmap or vale devices; for command-line tools, this means you have to enter those devices manually, but it might make it impossible to capture on those devices in the Wireshark GUI.
Can you enumerate the netmap and vale devices? If so, you should have a findalldevs routine.
Netmap works at least on any interface visible to the OS
(in native or emulated mode, the latter with some limitations
e.g not when the interface is bound to a switch),
but ports of VALE switches and netmap pipes are dynamically created
so any name that starts with netmap: and vale results in a
valid netmap port.

Also, when a port is in netmap mode is temporarily disconnected from
the host stack, so you want to be careful on where you use it.
The monitoring folks (bro, suricata...) will probably love this
feature but for others it might be more problematic.

I did have a findalldevs routine in earlier versions of the code
(mostly copying the one in pcap-bpf; perhaps i could even hook
on those),
but removed it because it can only return a partial list of ports
and i thought it would not be very useful.

cheers
luigi
Michael Richardson
2014-02-15 22:13:24 UTC
Permalink
Post by Luigi Rizzo
Also, when a port is in netmap mode is temporarily disconnected from
the host stack, so you want to be careful on where you use it.
The monitoring folks (bro, suricata...) will probably love this
feature but for others it might be more problematic.
yes, many people have wanted monitor ports that the host can't interact with
at all, and so far it has been hard to do.... the worst is IPv6 RAs that the
kernel sees and configures, or ARP requests for IP addresses on other
interfaces that the kernel might respond to...
Post by Luigi Rizzo
but removed it because it can only return a partial list of ports
and i thought it would not be very useful.
The GUI (wireshark) people would really like it... if it has a bug that
limits what it can return, it's probably still better than nothing,and
perhaps someone else will fix the bug.

--
] Never tell me the odds! | ipv6 mesh networks [
] Michael Richardson, Sandelman Software Works | network architect [
] ***@sandelman.ca http://www.sandelman.ca/ | ruby on rails [
Guy Harris
2014-02-27 19:24:51 UTC
Permalink
Post by Luigi Rizzo
Netmap works at least on any interface visible to the OS
(in native or emulated mode, the latter with some limitations
e.g not when the interface is bound to a switch),
So if I want to capture on eth0 in netmap mode, what interface name do I use?
Luigi Rizzo
2014-02-27 19:26:54 UTC
Permalink
Post by Guy Harris
Post by Luigi Rizzo
Netmap works at least on any interface visible to the OS
(in native or emulated mode, the latter with some limitations
e.g not when the interface is bound to a switch),
So if I want to capture on eth0 in netmap mode, what interface name do I use?
netmap:eth0
--
-----------------------------------------+-------------------------------
Prof. Luigi RIZZO, ***@iet.unipi.it . Dip. di Ing. dell'Informazione
http://www.iet.unipi.it/~luigi/ . Universita` di Pisa
TEL +39-050-2211611 . via Diotisalvi 2
Mobile +39-338-6809875 . 56122 PISA (Italy)
-----------------------------------------+-------------------------------
Guy Harris
2014-02-27 19:44:38 UTC
Permalink
Post by Luigi Rizzo
Netmap works at least on any interface visible to the OS
(in native or emulated mode, the latter with some limitations
e.g not when the interface is bound to a switch),
but ports of VALE switches and netmap pipes are dynamically created
so any name that starts with netmap: and vale results in a
valid netmap port.
Is there any reason why dynamically creating a VALE switch or netmap port *as a result of opening a device in libpcap* would be useful? libpcap is generally used to capture and inject network traffic on already-existing interfaces; if you create a VALE switch or netmap port by opening netmap:helloworld in libpcap, what traffic will you see, and where will injected traffic go?
Guy Harris
2014-02-27 21:05:39 UTC
Permalink
this can be used to plumb things together.
If you want to plumb things together, do you need libpcap?
Say you want to interconnect two VMs,
Why would I use libpcap for that?
or a traffic generator and a firewall/ids/monitor
that you want to test for performance, etc.
But wouldn't I create a netmap pipe using something other than libpcap, and only use libpcap if I want to watch the traffic on that pipe?

I.e., what would be lost if, for example, libpcap only supported capturing on existing netmap devices, and didn't support creating new ones on the fly?
Luigi Rizzo
2014-02-27 21:16:26 UTC
Permalink
Post by Guy Harris
this can be used to plumb things together.
If you want to plumb things together, do you need libpcap?
the plumbing is done by netmap/vale/netmap pipes.

libpcap is "only" a shim layer that can be used by
tools that only speak libpcap so you do not need
to recompile them.

But it is a crucially important shim layer that
gives you a lot of flexibility.
Post by Guy Harris
Say you want to interconnect two VMs,
Why would I use libpcap for that?
or a traffic generator and a firewall/ids/monitor
that you want to test for performance, etc.
But wouldn't I create a netmap pipe using something other than libpcap,
and only use libpcap if I want to watch the traffic on that pipe?
I.e., what would be lost if, for example, libpcap only supported capturing
on existing netmap devices, and didn't support creating new ones on the fly?
Well you would lose the ability to connect to a
VALE switch or a pipe (which only support dynamically
created endpoints).

Most importantly, you would need additional code to
disable the functionality, because if you look
at the pcap-netmap.c everything is handled in the
nm_open() call.

cheers
luigi
--
-----------------------------------------+-------------------------------
Prof. Luigi RIZZO, ***@iet.unipi.it . Dip. di Ing. dell'Informazione
http://www.iet.unipi.it/~luigi/ . Universita` di Pisa
TEL +39-050-2211611 . via Diotisalvi 2
Mobile +39-338-6809875 . 56122 PISA (Italy)
-----------------------------------------+-------------------------------
Guy Harris
2014-02-27 22:41:16 UTC
Permalink
Post by Luigi Rizzo
Post by Guy Harris
this can be used to plumb things together.
If you want to plumb things together, do you need libpcap?
the plumbing is done by netmap/vale/netmap pipes.
"By", or "with"? I.e., are there other APIs that would do the plumbing, and possibly tools that use those APIs?
Post by Luigi Rizzo
libpcap is "only" a shim layer that can be used by
tools that only speak libpcap so you do not need
to recompile them.
But it is a crucially important shim layer that
gives you a lot of flexibility.
What flexibility do you have by having to go through libpcap that you don't have by going directly to a lower-level API? I'd expect code to be able to do *more* by bypassing libpcap than by using libpcap.
Post by Luigi Rizzo
Post by Guy Harris
I.e., what would be lost if, for example, libpcap only supported capturing on existing netmap devices, and didn't support creating new ones on the fly?
Well you would lose the ability to connect to a
VALE switch or a pipe (which only support dynamically
created endpoints).
"Connect to a VALE switch or a pipe" sounds as if it means "connect to a VALE switch or a pipe that already exists".

If that's the case, I don't see why there's anything to dynamically create - the switch or pipe *already exists* and, if it has a name, you just use that name as the device name in the libpcap call, and it attaches to that already existing switch or pipe.

If that's *not* the case, if you create the switch or pipe at the time you open it with libpcap, what traffic will there be on the switch or pipe to capture, and where will packets injected into the switch or pipe go? If there's no traffic to capture, and the injected packets don't go anywhere, unless further plumbing of some sort needs to be done, what's the point in creating the switch or pipe using tcpdump or Wireshark or snort or... rather than creating it, doing the other plumbing, and then starting a capture on the now-existing device?
Post by Luigi Rizzo
Most importantly, you would need additional code to
disable the functionality, because if you look
at the pcap-netmap.c everything is handled in the
nm_open() call.
OK, then, if it's possible to:

1) determine which regular network interfaces can be captured on using netmap

and

2) get a list of names of existing VALE switches and netmap pipes

add code to either the create or activate routine that checks against those names and rejects other names, so that, for example, if somebody's fingers slip and they try to capture on "eht0" rather than "eth0", they get an error rather than a capture on a newly-created device that might not be used by anything other than the capturing program and thus might not actually get any traffic.
Loading...