Skip to content

Commit

Permalink
Netmap zero-copy (and some other improvements).
Browse files Browse the repository at this point in the history
* Netmap supports zero copy packet transfer (on single threaded
  machines).
* Allow --with-netmap=NETMAPDIRECTORY.
* Improve some configury help messages.
* Fix ToDevice bug.
  • Loading branch information
kohler committed Feb 21, 2012
1 parent 6128b00 commit 6c7c3f2
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 133 deletions.
2 changes: 1 addition & 1 deletion click-buildtool.in
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,7 @@ EOF
shortensyms)
shift 1; shortensyms "$@"; exit 0;;
--cf|--cfl|--cfla|--cflag|--cflags|--d|--de|--def|--defs)
echo @PROPER_INCLUDES@ @PCAP_INCLUDES@ -I@includedir@; exit 0;;
echo @PROPER_INCLUDES@ @PCAP_INCLUDES@ @NETMAP_INCLUDES@ -I@includedir@; exit 0;;
--o|--ot|--oth|--othe|--other|--otherl|--otherli|--otherlib|--otherlibs)
echo @PROPER_LIBS@ @PCAP_LIBS@ @DL_LIBS@ @SOCKET_LIBS@ @PTHREAD_LIBS@ @POSIX_CLOCK_LIBS@;
exit 0;;
Expand Down
2 changes: 1 addition & 1 deletion click-compile.in
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ while true; do
--dr=*|--dri=*|--driv=*|--drive=*|--driver=*)
driver=`echo "$1" | sed 's/[-a-z]*=//'`; shift 1;;
--c|--cf|--cfl|--cfla|--cflag|--cflags|--de|--def|--defs)
echo @PROPER_INCLUDES@ @PCAP_INCLUDES@ -I$includedir
echo @PROPER_INCLUDES@ @PCAP_INCLUDES@ @NETMAP_INCLUDES@ -I$includedir
exit=y; shift 1;;
--l|--li|--lib|--libs)
echo -L$libdir -lclick @PROPER_LIBS@ @PCAP_LIBS@ @DL_LIBS@ @SOCKET_LIBS@ @PTHREAD_LIBS@ @POSIX_CLOCK_LIBS@
Expand Down
58 changes: 43 additions & 15 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ EXPAT_INCLUDES
XML2CLICK
PROPER_LIBS
PROPER_INCLUDES
NETMAP_INCLUDES
PCAP_LIBS
PCAP_INCLUDES
TOOL_TARGETS
Expand Down Expand Up @@ -809,6 +810,7 @@ enable_dmalloc
enable_valgrind
enable_schedule_debugging
enable_intel_cpu
with_netmap
with_proper
with_expat
'
Expand Down Expand Up @@ -1442,11 +1444,13 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-userlevel disable user-level driver
--enable-user-multithread support userlevel multithreading
--enable-select=[select|poll|kqueue] set file descriptor wait mechanism
--disable-select do not use select()
--disable-poll do not use poll()
--disable-kqueue do not use kqueue()
--enable-user-multithread
support userlevel multithreading
--enable-select=[select|poll|kqueue]
set file descriptor wait mechanism
--disable-select do not use select()
--disable-poll do not use poll()
--disable-kqueue do not use kqueue()
--disable-linuxmodule disable Linux kernel driver
--disable-fixincludes do not patch Linux kernel headers for C++
--enable-multithread support kernel multithreading
Expand Down Expand Up @@ -1500,6 +1504,7 @@ Optional Packages:
--with-linux-map[=FILE] filename for Linux System.map [LINUXDIR/System.map]
--with-freebsd[=SRC,INC] FreeBSD source code is in SRC [/usr/src/sys],
include directory is INC [/usr/include]
--with-netmap enable netmap [no]
--with-proper[=PREFIX] use PlanetLab Proper library (optional)
--with-expat[=PREFIX] locate expat XML library (optional)
Expand Down Expand Up @@ -6194,7 +6199,7 @@ fi
if test "${enable_select+set}" = set; then :
enableval=$enable_select; :
else
enable_select='select poll kqueue'
enable_select="select poll kqueue"
fi

# Check whether --enable-poll was given.
Expand Down Expand Up @@ -7361,7 +7366,7 @@ else

ac_cv_endian=0
cat > conftest.$ac_ext <<EOF
#line 7364 "configure"
#line 7369 "configure"
#include "confdefs.h"
#include <$endian_hdr>
#ifdef __BYTE_ORDER
Expand Down Expand Up @@ -10162,14 +10167,31 @@ done
fi



# Check whether --with-netmap was given.
if test "${with_netmap+set}" = set; then :
withval=$with_netmap; use_netmap=$withval
else
use_netmap=no
fi


if test "$use_netmap" != "yes" -a "$use_netmap" != "no"; then
if test "${NETMAP_INCLUDES-NO}" != NO; then
:
elif test -f "$use_netmap/net/netmap.h"; then
NETMAP_INCLUDES="-I$use_netmap"
elif test -f "$use_netmap/include/net/netmap.h"; then
NETMAP_INCLUDES="-I$use_netmap/include"
fi
fi
saveflags="$CPPFLAGS"
CPPFLAGS="$saveflags $NETMAP_INCLUDES"

HAVE_NETMAP=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for net/netmap.h" >&5
$as_echo_n "checking for net/netmap.h... " >&6; }
if ${ac_cv_net_netmap_header_path+:} false; then :
$as_echo_n "(cached) " >&6
else

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <net/netmap.h>
_ACEOF
Expand All @@ -10179,9 +10201,9 @@ else
ac_cv_net_netmap_header_path="not found"
fi
rm -f conftest.err conftest.i conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_net_netmap_header_path" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_net_netmap_header_path" >&5
$as_echo "$ac_cv_net_netmap_header_path" >&6; }

if test "$ac_cv_net_netmap_header_path" = "found"; then
HAVE_NETMAP=yes
fi
Expand Down Expand Up @@ -10209,12 +10231,14 @@ $as_echo "$ac_cv_working_net_netmap_h" >&6; }
test "$ac_cv_working_net_netmap_h" != yes && HAVE_NETMAP=
fi

if test "$HAVE_NETMAP" = yes; then
CPPFLAGS="$saveflags"
if test "$HAVE_NETMAP" = yes -a "$use_netmap" != no; then

$as_echo "#define HAVE_NET_NETMAP_H 1" >>confdefs.h

fi


if test "$HAVE_PCAP" != yes -a "$HAVE_NETMAP" != yes -a "$ac_cv_under_linux" != yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
=========================================
Expand Down Expand Up @@ -12424,6 +12448,10 @@ if test $ac_have_linux_kernel = y; then
fi
fi

if test "x$HAVE_NETMAP" = xyes; then
provisions="$provisions netmap"
fi

if test "x$HAVE_PCAP" = xyes; then
provisions="$provisions pcap"
fi
Expand Down
27 changes: 21 additions & 6 deletions configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ dnl

dnl userlevel driver and features

AC_ARG_ENABLE(userlevel, [ --disable-userlevel disable user-level driver], :, enable_userlevel=yes)
AC_ARG_ENABLE([userlevel],
[AS_HELP_STRING([--disable-userlevel], [disable user-level driver])],
[:], [enable_userlevel=yes])

AC_ARG_ENABLE(user-multithread, [[ --enable-user-multithread support userlevel multithreading]], :, [enable_user_multithread=no])
AC_ARG_ENABLE([user-multithread],
[AS_HELP_STRING([ --enable-user-multithread], [support userlevel multithreading])],
[:], [enable_user_multithread=no])

PTHREAD_LIBS=""
AC_SUBST(PTHREAD_LIBS)
Expand All @@ -93,10 +97,16 @@ Can't find -lpthread and/or <pthread.h>, so I can't compile with
LIBS="$SAVE_LIBS"
fi

AC_ARG_ENABLE([select], [ --enable-select=[[select|poll|kqueue]] set file descriptor wait mechanism
--disable-select do not use select()], [:], [enable_select='select poll kqueue'])
AC_ARG_ENABLE([poll], [ --disable-poll do not use poll()], [:], [enable_poll=yes])
AC_ARG_ENABLE([kqueue], [ --disable-kqueue do not use kqueue()], [:], [enable_kqueue=yes])
AC_ARG_ENABLE([select],
[AS_HELP_STRING([ --enable-select=[[select|poll|kqueue]]], [set file descriptor wait mechanism])
AS_HELP_STRING([ --disable-select], [do not use select()])],
[:], [enable_select="select poll kqueue"])
AC_ARG_ENABLE([poll],
[AS_HELP_STRING([ --disable-poll], [do not use poll()])],
[:], [enable_poll=yes])
AC_ARG_ENABLE([kqueue],
[AS_HELP_STRING([ --disable-kqueue], [do not use kqueue()])],
[:], [enable_kqueue=yes])

if test "$enable_select" = yes; then
enable_select='select poll kqueue'
Expand Down Expand Up @@ -1746,6 +1756,11 @@ if test $ac_have_linux_kernel = y; then
fi
fi

dnl add 'netmap' if netmap support is available
if test "x$HAVE_NETMAP" = xyes; then
provisions="$provisions netmap"
fi

dnl add 'pcap' if libpcap is available
if test "x$HAVE_PCAP" = xyes; then
provisions="$provisions pcap"
Expand Down
105 changes: 35 additions & 70 deletions elements/userlevel/fromdevice.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Copyright (c) 2001 International Computer Science Institute
* Copyright (c) 2005-2007 Regents of the University of California
* Copyright (c) 2011 Meraki, Inc.
* Copyright (c) 2012 Eddie Kohler
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -272,56 +273,6 @@ FromDevice::open_pcap(String ifname, int snaplen, bool promisc,
}
#endif

#if FROMDEVICE_ALLOW_NETMAP
int
FromDevice::netmap_type::open(const String &ifname,
bool always_error, ErrorHandler *errh)
{
ErrorHandler *initial_errh = always_error ? errh : ErrorHandler::silent_handler();

int fd = ::open("/dev/netmap", O_RDWR);
if (fd < 0) {
initial_errh->error("/dev/netmap: %s", strerror(errno));
return -1;
}

struct nmreq req;
memset(&req, 0, sizeof(req));
strncpy(req.nr_name, ifname.c_str(), sizeof(req.nr_name));
req.nr_ringid = 0;
int r;
if ((r = ioctl(fd, NIOCGINFO, &req))) {
initial_errh->error("netmap %s: %s", ifname.c_str(), strerror(errno));
error:
close(fd);
return -1;
}

memsize = req.nr_memsize;
if ((r = ioctl(fd, NIOCREGIF, &req))) {
errh->error("netmap register %s: %s", ifname.c_str(), strerror(errno));
goto error;
}

mem = (char *) mmap(0, memsize, PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) {
errh->error("netmap allocate %s: %s", ifname.c_str(), strerror(errno));
mem = 0;
goto error;
}

nifp = NETMAP_IF(mem, req.nr_offset);
ring_begin = 0;
ring_end = req.nr_numrings;

// XXX timestamp off
for (unsigned i = ring_begin; i != ring_end; ++i)
NETMAP_RXRING(nifp, i)->flags = NR_TIMESTAMP;
return fd;
}
#endif

int
FromDevice::initialize(ErrorHandler *errh)
{
Expand Down Expand Up @@ -443,12 +394,8 @@ FromDevice::cleanup(CleanupStage stage)
if (stage >= CLEANUP_INITIALIZED && !_sniffer)
KernelFilter::device_filter(_ifname, false, ErrorHandler::default_handler());
#if FROMDEVICE_ALLOW_NETMAP
if (_fd >= 0 && _method == method_netmap) {
munmap(_netmap.mem, _netmap.memsize);
ioctl(_fd, NIOCUNREGIF, (struct nmreq *) 0);
close(_fd);
_netmap.mem = 0;
}
if (_fd >= 0 && _method == method_netmap)
_netmap.close(_fd);
#endif
#if FROMDEVICE_ALLOW_LINUX
if (_fd >= 0 && _method == method_linux) {
Expand All @@ -469,11 +416,8 @@ FromDevice::cleanup(CleanupStage stage)

#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
void
FromDevice::emit_packet_data(const unsigned char *buf, int len, int fulllen,
const Timestamp &ts)
FromDevice::emit_packet(WritablePacket *p, int extra_len, const Timestamp &ts)
{
WritablePacket *p = Packet::make(_headroom, buf, len, 0);

// set packet type annotation
if (p->data()[0] & 1) {
if (EtherAddress::is_broadcast(p->data()))
Expand All @@ -485,7 +429,7 @@ FromDevice::emit_packet_data(const unsigned char *buf, int len, int fulllen,
// set annotations
p->set_timestamp_anno(ts);
p->set_mac_header(p->data());
SET_EXTRA_LENGTH_ANNO(p, fulllen - len);
SET_EXTRA_LENGTH_ANNO(p, extra_len);

if (!_force_ip || fake_pcap_force_ip(p, _datalink))
output(0).push(p);
Expand All @@ -503,8 +447,9 @@ FromDevice_get_packet(u_char* clientdata,
const u_char* data)
{
FromDevice *fd = (FromDevice *) clientdata;
fd->emit_packet_data(data, pkthdr->caplen, pkthdr->len,
Timestamp::make_usec(pkthdr->ts.tv_sec, pkthdr->ts.tv_usec));
WritablePacket *p = Packet::make(fd->_headroom, data, pkthdr->caplen, 0);
fd->emit_packet(p, pkthdr->len - pkthdr->caplen,
Timestamp::make_usec(pkthdr->ts.tv_sec, pkthdr->ts.tv_usec));
}
}
CLICK_DECLS
Expand All @@ -517,18 +462,38 @@ FromDevice::netmap_dispatch()
int n = 0;
for (unsigned ri = _netmap.ring_begin; ri != _netmap.ring_end; ++ri) {
struct netmap_ring *ring = NETMAP_RXRING(_netmap.nifp, ri);
//click_chatter("netmap dispatch %s %u %u %u %u", _ifname.c_str(), ri, ring->cur, ring->reserved, ring->avail);

while (ring->reserved > 0 && NetmapInfo::refill(ring))
/* click_chatter("Refilled") */;

if (ring->avail == 0)
continue;

int nzcopy = (int) (ring->num_slots / 2) - (int) ring->reserved;

while (n != _burst && ring->avail > 0) {
unsigned i = ring->cur;
unsigned buf_idx = ring->slot[i].buf_idx;
unsigned cur = ring->cur;
unsigned buf_idx = ring->slot[cur].buf_idx;
if (buf_idx < 2)
break;
unsigned char *buf = (unsigned char *) NETMAP_BUF(ring, buf_idx);
emit_packet_data(buf, ring->slot[i].len, ring->slot[i].len, ring->ts);
ring->cur = NETMAP_RING_NEXT(ring, i);
ring->avail--;
n++;

WritablePacket *p;
if (nzcopy > 0) {
p = Packet::make(buf, ring->slot[cur].len, NetmapInfo::buffer_destructor);
++ring->reserved;
--nzcopy;
} else {
p = Packet::make(_headroom, buf, ring->slot[cur].len, 0);
unsigned res1idx = NETMAP_RING_FIRST_RESERVED(ring);
ring->slot[res1idx].buf_idx = buf_idx;
}
ring->cur = NETMAP_RING_NEXT(ring, ring->cur);
--ring->avail;
++n;

emit_packet(p, 0, ring->ts);
}
}
return n;
Expand Down Expand Up @@ -671,5 +636,5 @@ FromDevice::add_handlers()
}

CLICK_ENDDECLS
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter)
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter NetmapInfo)
EXPORT_ELEMENT(FromDevice)
Loading

0 comments on commit 6c7c3f2

Please sign in to comment.