diff --git a/configure b/configure index 43549a3e9..f3842857d 100755 --- a/configure +++ b/configure @@ -767,6 +767,8 @@ COMPILE_FRAGROUTE_FALSE COMPILE_FRAGROUTE_TRUE LDNETLIB LDNETINC +COMPILE_NETMAP_FALSE +COMPILE_NETMAP_TRUE NETMAPFLAGS NETMAPINCDIR NETMAPUSERINC @@ -5169,13 +5171,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:5172: $ac_compile\"" >&5) + (eval echo "\"\$as_me:5174: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:5175: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:5177: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:5178: output\"" >&5) + (eval echo "\"\$as_me:5180: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -6381,7 +6383,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 6384 "configure"' > conftest.$ac_ext + echo '#line 6386 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7907,11 +7909,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7910: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7912: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7914: \$? = $ac_status" >&5 + echo "$as_me:7916: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -8246,11 +8248,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8249: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8251: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8253: \$? = $ac_status" >&5 + echo "$as_me:8255: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -8351,11 +8353,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8354: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8356: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8358: \$? = $ac_status" >&5 + echo "$as_me:8360: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8406,11 +8408,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8409: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8411: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8413: \$? = $ac_status" >&5 + echo "$as_me:8415: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10790,7 +10792,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10793 "configure" +#line 10795 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10886,7 +10888,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10889 "configure" +#line 10891 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -14191,11 +14193,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14194: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14196: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14198: \$? = $ac_status" >&5 + echo "$as_me:14200: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14290,11 +14292,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14293: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14295: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14297: \$? = $ac_status" >&5 + echo "$as_me:14299: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14342,11 +14344,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14345: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14347: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14349: \$? = $ac_status" >&5 + echo "$as_me:14351: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -18463,9 +18465,10 @@ fi have_netmap=no +enable_netmap=no trynetmapdir=/opt/netmap -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Netmap socket sending support" >&5 -$as_echo_n "checking for Netmap socket sending support... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for netmap socket sending support" >&5 +$as_echo_n "checking for netmap socket sending support... " >&6; } # Check whether --with-netmap was given. if test "${with_netmap+set}" = set; then : @@ -18479,12 +18482,14 @@ for testdir in $trynetmapdir /usr/src/netmap-release /usr/src/netmap /usr/local/ NETMAPUSERINC="${testdir}/sys/net/netmap_user.h" NETMAPINCDIR="${testdir}/sys" have_netmap="yes $testdir" + enable_netmap=yes else if test -f "${testdir}/net/netmap.h" ; then NETMAPINC="${testdir}/net/netmap.h" NETMAPUSERINC="${testdir}/net/netmap_user.h" NETMAPINCDIR="${testdir}" have_netmap="yes $testdir" + enable_netmap=yes fi fi @@ -18501,6 +18506,7 @@ for testdir in $trynetmapdir /usr/src/netmap-release /usr/src/netmap /usr/local/ $as_echo "#define HAVE_NETMAP 1" >>confdefs.h have_netmap="yes $testdir" + enable_netmap=yes break; fi if test "$trynetmapdir" != /opt/netmap ; then @@ -18510,6 +18516,15 @@ done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_netmap" >&5 $as_echo "$have_netmap" >&6; } + if test x$enable_netmap = xyes ; then + COMPILE_NETMAP_TRUE= + COMPILE_NETMAP_FALSE='#' +else + COMPILE_NETMAP_TRUE='#' + COMPILE_NETMAP_FALSE= +fi + + OLDCPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -DNETMAP_WITH_LIBS -DND -I$NETMAPINCDIR" @@ -18527,9 +18542,13 @@ fi done + +have_nm_open=no +have_nm_nr_reg_mask=no +have_nm_nr_flags=no +have_nmring_head_tail=no if test "$have_netmap" != no ; then - have_nm_open=no - ac_fn_c_check_decl "$LINENO" "nm_open" "ac_cv_have_decl_nm_open" " + ac_fn_c_check_decl "$LINENO" "nm_open" "ac_cv_have_decl_nm_open" " #include #include \"${NETMAPUSERINC}\" @@ -18538,12 +18557,120 @@ if test "x$ac_cv_have_decl_nm_open" = x""yes; then : have_nm_open=yes fi - if test "$have_nm_open" = yes ; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for netmap NR_REG_MASK definition" >&5 +$as_echo_n "checking for netmap NR_REG_MASK definition... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + #include + +int +main () +{ + + #ifdef NR_REG_MASK + /* OK */ + #else + # error NR_REG_MASK not found + #endif + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_nm_nr_reg_mask=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_nm_nr_reg_mask" >&5 +$as_echo "$have_nm_nr_reg_mask" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for netmap nr_flags definition" >&5 +$as_echo_n "checking for netmap nr_flags definition... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + #include + +int +main () +{ + + struct nmreq nmr; + nmr.nr_flags = 0; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_nm_nr_flags=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_nm_nr_flags" >&5 +$as_echo "$have_nm_nr_flags" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for netmap ring head/tail definitions" >&5 +$as_echo_n "checking for netmap ring head/tail definitions... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + #include + +int +main () +{ + + struct netmap_ring r; + r.head = r.tail = 0; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_nmring_head_tail=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_nmring_head_tail" >&5 +$as_echo "$have_nmring_head_tail" >&6; } + +fi + +if test "$have_nm_open" = yes ; then $as_echo "#define HAVE_NETMAP_NM_OPEN 1" >>confdefs.h - fi fi +if test "$have_nm_nr_reg_mask" = yes ; then + +$as_echo "#define HAVE_NETMAP_NR_REG 1" >>confdefs.h + +fi +if test "$have_nm_nr_flags" = yes ; then + +$as_echo "#define HAVE_NETMAP_NR_FLAGS 1" >>confdefs.h + +fi +if test "$have_nmring_head_tail" = yes ; then + +$as_echo "#define HAVE_NETMAP_RING_HEAD_TAIL 1" >>confdefs.h + +fi + CPPFLAGS="$OLDCPPFLAGS" have_pf=no @@ -21089,6 +21216,10 @@ if test -z "${COMPILE_TCPLIVEPLAY_TRUE}" && test -z "${COMPILE_TCPLIVEPLAY_FALSE as_fn_error "conditional \"COMPILE_TCPLIVEPLAY\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${COMPILE_NETMAP_TRUE}" && test -z "${COMPILE_NETMAP_FALSE}"; then + as_fn_error "conditional \"COMPILE_NETMAP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${COMPILE_FRAGROUTE_TRUE}" && test -z "${COMPILE_FRAGROUTE_FALSE}"; then as_fn_error "conditional \"COMPILE_FRAGROUTE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/configure.ac b/configure.ac index cc5c6a761..3bfde377c 100644 --- a/configure.ac +++ b/configure.ac @@ -852,8 +852,9 @@ dnl ##################################################### dnl Check for netmap support dnl ##################################################### have_netmap=no +enable_netmap=no trynetmapdir=/opt/netmap -AC_MSG_CHECKING(for Netmap socket sending support) +AC_MSG_CHECKING(for netmap socket sending support) AC_ARG_WITH(netmap, AC_HELP_STRING([--with-netmap=DIR], [Use netmap in DIR]), [trynetmapdir=$withval]) @@ -864,12 +865,14 @@ for testdir in $trynetmapdir /usr/src/netmap-release /usr/src/netmap /usr/local/ NETMAPUSERINC="${testdir}/sys/net/netmap_user.h" NETMAPINCDIR="${testdir}/sys" have_netmap="yes $testdir" + enable_netmap=yes else if test -f "${testdir}/net/netmap.h" ; then NETMAPINC="${testdir}/net/netmap.h" NETMAPUSERINC="${testdir}/net/netmap_user.h" NETMAPINCDIR="${testdir}" have_netmap="yes $testdir" + enable_netmap=yes fi fi @@ -885,6 +888,7 @@ for testdir in $trynetmapdir /usr/src/netmap-release /usr/src/netmap /usr/local/ AC_DEFINE([HAVE_NETMAP], [1], [Do we have netmap support?]) have_netmap="yes $testdir" + enable_netmap=yes break; fi if test "$trynetmapdir" != /opt/netmap ; then @@ -893,23 +897,100 @@ for testdir in $trynetmapdir /usr/src/netmap-release /usr/src/netmap /usr/local/ done AC_MSG_RESULT($have_netmap) +AM_CONDITIONAL(COMPILE_NETMAP, [test x$enable_netmap = xyes ]) + dnl ########################################################### -dnl Check for nm_open() function available in netmap version 10 +dnl Check for nm_open() function available in netmap version 5 +dnl Also check for other version-specific netmap definitions and structures dnl ########################################################### OLDCPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -DNETMAP_WITH_LIBS -DND -I$NETMAPINCDIR" AC_CHECK_HEADERS(stdio.h net/netmap_user.h) + +have_nm_open=no +have_nm_nr_reg_mask=no +have_nm_nr_flags=no +have_nmring_head_tail=no if test "$have_netmap" != no ; then - have_nm_open=no + dnl check for nm_open() AC_CHECK_DECL([nm_open],[have_nm_open=yes], , [[ #include #include "${NETMAPUSERINC}" ]]) - if test "$have_nm_open" = yes ; then - AC_DEFINE([HAVE_NETMAP_NM_OPEN], [1], [Does netmap have nm_open function?]) - fi + + dnl check for #define NR_REG_MASK + AC_MSG_CHECKING(for netmap NR_REG_MASK definition) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #include + #include + #include + ]], + [[ + #ifdef NR_REG_MASK + /* OK */ + #else + # error NR_REG_MASK not found + #endif + ]]) + ], + [have_nm_nr_reg_mask=yes], + []) + AC_MSG_RESULT($have_nm_nr_reg_mask) + + dnl check for nr_flags in struct nmreq + AC_MSG_CHECKING(for netmap nr_flags definition) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #include + #include + #include + ]], + [[ + struct nmreq nmr; + nmr.nr_flags = 0; + ]]) + ], + [have_nm_nr_flags=yes], + []) + AC_MSG_RESULT($have_nm_nr_flags) + + dnl check for head/tail in struct netmap_ring + AC_MSG_CHECKING(for netmap ring head/tail definitions) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #include + #include + #include + ]], + [[ + struct netmap_ring r; + r.head = r.tail = 0; + ]]) + ], + [have_nmring_head_tail=yes], + []) + AC_MSG_RESULT($have_nmring_head_tail) + +fi + +if test "$have_nm_open" = yes ; then + AC_DEFINE([HAVE_NETMAP_NM_OPEN], [1], [Does netmap have nm_open function?]) fi +if test "$have_nm_nr_reg_mask" = yes ; then + AC_DEFINE([HAVE_NETMAP_NR_REG], [1], [Does netmap have NR_REG_MASK defined?]) +fi +if test "$have_nm_nr_flags" = yes ; then + AC_DEFINE([HAVE_NETMAP_NR_FLAGS], [1], [Does netmap struct nmreq have nr_flags defined?]) +fi +if test "$have_nmring_head_tail" = yes ; then + AC_DEFINE([HAVE_NETMAP_RING_HEAD_TAIL], [1], [Does structure netmap_ring have head/tail defined?]) +fi + CPPFLAGS="$OLDCPPFLAGS" have_pf=no diff --git a/docs/CHANGELOG b/docs/CHANGELOG index fe9b73463..394872ef4 100644 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -1,4 +1,6 @@ 06/21/2014 Version 4.0.5beta1 + - Make --netmap version agnostic (#106) + - Fix netmap hang in FreeBSD 11 (#103) - Fix netmap hang if network cables unplugged (#96) - Support for Vale Switch (#91) - Prevent file retransmissions when selecting multiple files (#86) diff --git a/src/common/Makefile.am b/src/common/Makefile.am index e4b94a6cb..1e3b8750f 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -21,6 +21,10 @@ if ENABLE_TCPDUMP libcommon_a_SOURCES += tcpdump.c endif +if COMPILE_NETMAP +libcommon_a_SOURCES += netmap.c +endif + AM_CFLAGS = -I.. -I../.. $(LNAV_CFLAGS) @LDNETINC@ if ! SYSTEM_STRLCPY diff --git a/src/common/Makefile.in b/src/common/Makefile.in index cc7b4c0cd..b01882d8d 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -37,6 +37,7 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @ENABLE_TCPDUMP_TRUE@am__append_1 = tcpdump.c +@COMPILE_NETMAP_TRUE@am__append_2 = netmap.c subdir = src/common DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in @@ -56,15 +57,17 @@ libcommon_a_AR = $(AR) $(ARFLAGS) am__libcommon_a_SOURCES_DIST = cidr.c err.c list.c cache.c services.c \ get.c fakepcap.c fakepcapnav.c fakepoll.c xX.c utils.c timer.c \ git_version.c sendpacket.c dlt_names.c mac.c interface.c \ - flows.c txring.c tcpdump.c + flows.c txring.c tcpdump.c netmap.c @ENABLE_TCPDUMP_TRUE@am__objects_1 = tcpdump.$(OBJEXT) +@COMPILE_NETMAP_TRUE@am__objects_2 = netmap.$(OBJEXT) am_libcommon_a_OBJECTS = cidr.$(OBJEXT) err.$(OBJEXT) list.$(OBJEXT) \ cache.$(OBJEXT) services.$(OBJEXT) get.$(OBJEXT) \ fakepcap.$(OBJEXT) fakepcapnav.$(OBJEXT) fakepoll.$(OBJEXT) \ xX.$(OBJEXT) utils.$(OBJEXT) timer.$(OBJEXT) \ git_version.$(OBJEXT) sendpacket.$(OBJEXT) dlt_names.$(OBJEXT) \ mac.$(OBJEXT) interface.$(OBJEXT) git_version.$(OBJEXT) \ - flows.$(OBJEXT) txring.$(OBJEXT) $(am__objects_1) + flows.$(OBJEXT) txring.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) libcommon_a_OBJECTS = $(am_libcommon_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -242,7 +245,7 @@ BUILT_SOURCES = git_version.c libcommon_a_SOURCES = cidr.c err.c list.c cache.c services.c get.c \ fakepcap.c fakepcapnav.c fakepoll.c xX.c utils.c timer.c \ git_version.c sendpacket.c dlt_names.c mac.c interface.c \ - git_version.c flows.c txring.c $(am__append_1) + git_version.c flows.c txring.c $(am__append_1) $(am__append_2) AM_CFLAGS = -I.. -I../.. $(LNAV_CFLAGS) @LDNETINC@ @SYSTEM_STRLCPY_FALSE@libcommon_a_LIBADD = ../../lib/libstrl.a noinst_HEADERS = cidr.h err.h list.h cache.h services.h get.h \ @@ -314,6 +317,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sendpacket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/services.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpdump.Po@am__quote@ diff --git a/src/common/interface.c b/src/common/interface.c index aa3c00366..1e8c10063 100644 --- a/src/common/interface.c +++ b/src/common/interface.c @@ -31,6 +31,9 @@ #include "defines.h" #include "common.h" #include "interface.h" +#ifdef HAVE_NETMAP +#include "common/netmap.h" +#endif #ifdef DEBUG extern int debug; @@ -43,20 +46,14 @@ extern int debug; * which use horrifically long interface names * * Returns NULL on error - * - * On success, it *may* malloc() memory equal to the length of *alias. */ char * get_interface(interface_list_t *list, const char *alias) { interface_list_t *ptr; - char *name; assert(alias); - if (strncmp("vale", alias, 4) == 0) - goto vale; - if (list != NULL) { ptr = list; @@ -70,13 +67,8 @@ get_interface(interface_list_t *list, const char *alias) ptr = ptr->next; } while (ptr != NULL); - } else { -vale: - name = (char *)safe_malloc(strlen(alias) + 1); - strlcpy(name, alias, sizeof(name)); - return(name); } - + return(NULL); } @@ -92,6 +84,13 @@ get_interface_list(void) int i = 0; DIR *dir; struct dirent *dirdata; +#ifdef HAVE_NETMAP + int fd = -1; + nmreq_t nmr; +#endif +#if defined HAVE_LIBPCAP_NETMAP || defined HAVE_NETMAP + u_int32_t netmap_version = -1; +#endif #ifndef HAVE_WIN32 /* Unix just has a warning about being root */ @@ -99,6 +98,11 @@ get_interface_list(void) warn("May need to run as root to get access to all network interfaces."); #endif +#ifdef HAVE_NETMAP + if ((fd = open ("/dev/netmap", O_RDWR)) > 0) + netmap_version = get_netmap_version(fd); +#endif + if (pcap_findalldevs(&pcap_if, ebuf) < 0) errx(-1, "Error: %s", ebuf); @@ -128,47 +132,63 @@ get_interface_list(void) */ if (!(pcap_if_ptr->flags & PCAP_IF_LOOPBACK) && strcmp("any", pcap_if_ptr->name)) { +#endif #ifdef HAVE_NETMAP - struct nmreq nmr; - int fd; - bzero (&nmr, sizeof(nmr)); strncpy (nmr.nr_name, pcap_if_ptr->name, sizeof(nmr.nr_name)); - nmr.nr_version = NETMAP_API; - if ((fd = open ("/dev/netmap", O_RDWR)) > 0 + nmr.nr_version = netmap_version; + if (fd > 0 + && netmap_version != -1 && (ioctl(fd, NIOCGINFO, &nmr) == 0)) { int x; #endif /* HAVE_NETMAP */ +#if defined HAVE_LIBPCAP_NETMAP || defined HAVE_NETMAP list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); list_ptr = list_ptr->next; - snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s", pcap_if_ptr->name); + snprintf(list_ptr->name, sizeof(list_ptr->name), "vale:%s", pcap_if_ptr->name); sprintf(list_ptr->alias, "%%%d", i++); list_ptr->flags = pcap_if_ptr->flags; list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); list_ptr = list_ptr->next; - snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s*", pcap_if_ptr->name); + snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s", pcap_if_ptr->name); sprintf(list_ptr->alias, "%%%d", i++); list_ptr->flags = pcap_if_ptr->flags; - list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); - list_ptr = list_ptr->next; - snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s^", pcap_if_ptr->name); - sprintf(list_ptr->alias, "%%%d", i++); - list_ptr->flags = pcap_if_ptr->flags; + if (netmap_version >= 10) { + list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); + list_ptr = list_ptr->next; + snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s!", pcap_if_ptr->name); + sprintf(list_ptr->alias, "%%%d", i++); + list_ptr->flags = pcap_if_ptr->flags; -#ifdef HAVE_NETMAP - for (x = 0; x < nmr.nr_rx_rings; ++x) { list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); list_ptr = list_ptr->next; - snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s-%d", pcap_if_ptr->name, x); + snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s*", pcap_if_ptr->name); sprintf(list_ptr->alias, "%%%d", i++); list_ptr->flags = pcap_if_ptr->flags; + + list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); + list_ptr = list_ptr->next; + snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s^", pcap_if_ptr->name); + sprintf(list_ptr->alias, "%%%d", i++); + list_ptr->flags = pcap_if_ptr->flags; + } +#endif /* HAVE_LIBPCAP_NETMAP || HAVE_NETMAP */ +#ifdef HAVE_NETMAP + if (netmap_version >= 10) { + for (x = 0; x < nmr.nr_rx_rings; ++x) { + list_ptr->next = (interface_list_t *)safe_malloc(sizeof(interface_list_t)); + list_ptr = list_ptr->next; + snprintf(list_ptr->name, sizeof(list_ptr->name), "netmap:%s-%d", pcap_if_ptr->name, x); + sprintf(list_ptr->alias, "%%%d", i++); + list_ptr->flags = pcap_if_ptr->flags; + } } - close(fd); } #endif /* HAVE_NETMAP */ +#ifdef HAVE_LIBPCAP_NETMAP } #endif /* HAVE_LIBPCAP_NETMAP */ pcap_if_ptr = pcap_if_ptr->next; @@ -195,7 +215,12 @@ get_interface_list(void) } +#ifdef HAVE_NETMAP + if (fd > 0) + close(fd); +#endif + dbg(1, "xxx get_interface_list end"); return(list_head); } diff --git a/src/common/netmap.c b/src/common/netmap.c new file mode 100644 index 000000000..f691c25c7 --- /dev/null +++ b/src/common/netmap.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2013 Fred Klassen - AppNeta Inc. + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Tcpreplay Suite. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "defines.h" +#include "common.h" +#include "netmap.h" + +#ifdef DEBUG +extern int debug; +#endif + +#include +static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd); + +/** + * Method takes an open "/dev/netmap" file descriptor and returns + * the netmap version. + * + * Returns -1 on error + */ +int +get_netmap_version(int fd) +{ + u_int32_t netmap_version = -1; + nmreq_t nmr; + + assert(fd > 0); + + /* netmap version discovery */ + bzero (&nmr, sizeof(nmr)); + nmr.nr_version = NETMAP_API; + + /* attempt using the netmap API version that this was compiled under */ + if(ioctl(fd, NIOCGINFO, &nmr) == 0) { + netmap_version = nmr.nr_version; + dbgx(1, "netmap detected API version %d which matches compiled version\n", + netmap_version); + } else { + /* failed. + * + * Try other versions in an attempt to find the version + * that matches this system. + */ + int x; + for (x = 0; x < 50; ++x) { + bzero (&nmr, sizeof(nmr)); + nmr.nr_version = x; + if(ioctl(fd, NIOCGINFO, &nmr) == 0) { + netmap_version = nmr.nr_version; + dbgx(1, "netmap detected API version %d which doesn't match compiled version %d\n", + netmap_version, NETMAP_API); + break; + } + } + } + + return netmap_version; +} + +/** + * ioctl support for netmap + */ +static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd) { + struct ifreq ifr; + int error; + int fd; +#ifdef linux + struct ethtool_value eval; +#endif + + assert(sp); + + fd = socket (AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + dbg(1, "ioctl error: cannot get device control socket.\n"); + return -1; + } + + bzero (&ifr, sizeof(ifr)); + strncpy (ifr.ifr_name, sp->device, sizeof(ifr.ifr_name)); + + switch (what) { + case SIOCSIFFLAGS: + ifr.ifr_flags = sp->if_flags >> 16; + ifr.ifr_flags = sp->if_flags & 0xffff; + break; + +#ifdef linux + case SIOCETHTOOL: + eval.cmd = subcmd; + eval.data = sp->data; + ifr.ifr_data = (caddr_t)&eval; + dbgx(1, "ioctl SIOCETHTOOL subcmd=%d data=%u", subcmd, eval.data); + break; +#endif + } + + error = ioctl (fd, what, &ifr); + if (error) + goto done; + + switch (what) { + case SIOCGIFFLAGS: + sp->if_flags = (ifr.ifr_flags << 16) | (0xffff & ifr.ifr_flags); + dbgx(1, "SIOCGIFFLAGS flags are 0x%x", sp->if_flags); + break; + +#ifdef linux + case SIOCETHTOOL: + switch (subcmd) { + case ETHTOOL_GGSO: + sp->gso = eval.data; + dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GGSO=%u", eval.data); + break; + + case ETHTOOL_GTSO: + sp->tso = eval.data; + dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTSO=%u", eval.data); + break; + + case ETHTOOL_GRXCSUM: + sp->rxcsum = eval.data; + dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GRXCSUM=%u", eval.data); + break; + + case ETHTOOL_GTXCSUM: + sp->txcsum = eval.data; + dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTXCSUM=%u", eval.data); + break; + } + break; +#endif + + } + +done: + close (fd); + + if (error) + warnx("ioctl error %d %lu:%d", error, what, subcmd); + return error; +} + +/** + * Inner sendpacket_open() method for using netmap + */ +void * +sendpacket_open_netmap(const char *device, char *errbuf) { + sendpacket_t *sp = NULL; + nmreq_t nmr; + char ifname_buf[MAX_IFNAMELEN]; + const char *ifname; + const char *port = NULL; + size_t namelen; + u_int32_t nr_ringid = 0; + u_int32_t nr_flags = NR_REG_DEFAULT; + + assert(device); + assert(errbuf); + + dbg(1, "sendpacket_open_netmap: using netmap"); + + bzero(&nmr, sizeof(nmr)); + + /* prep & return our sp handle */ + sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t)); + + if (strlen(device) > MAX_IFNAMELEN - 8) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device); + goto IFACENAME_INVALID; + } + + /* + * Sort out interface names + * + * ifname (foo, netmap:foo or vale:foo) is the port name + * foo bind to a single NIC hardware queue + * netmap:foo bind to a single NIC hardware queue + * vale:foo bind to the Vale virtual interface + * + * for netmap version 10+ a suffix can indicate the following: + * netmap:foo! bind to all NIC hardware queues (may cause TX reordering) + * netmap:foo^ bind to the host (sw) ring pair + * netmap:foo* bind to the host (sw) and NIC ring pairs (transparent) + * netmap:foo-NN bind to the individual NIC ring pair (queue) where NN = the ring number + * netmap:foo{NN bind to the master side of pipe NN + * netmap:foo}NN bind to the slave side of pipe NN + */ + if (strncmp(device, "netmap:", 7) && strncmp(device, "vale", 4)) { + snprintf(ifname_buf, sizeof(ifname_buf), "netmap:%s", device); + ifname = ifname_buf; + } else { + ifname = device; + } + + if (!strncmp("vale", device, 4)) + sp->is_vale = 1; + + if (ifname[0] == 'n') + ifname += 7; + + /* scan for a separator */ + for (port = ifname; *port && !index("!-*^{}", *port); port++) + ; + + namelen = port - ifname; + if (namelen > sizeof(nmr.nr_name)) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device); + goto IFACENAME_INVALID; + } + /* + * Open the netmap device to fetch the number of queues of our + * interface. + * + * The first NIOCREGIF also detaches the card from the + * protocol stack and may cause a reset of the card, + * which in turn may take some time for the PHY to + * reconfigure. + */ + if ((sp->handle.fd = open ("/dev/netmap", O_RDWR)) < 0) { + dbg(1, "sendpacket_open_netmap: Unable to access netmap"); + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to access netmap.\n" + "See INSTALL to learn how to set up netmap-capable network drivers."); + goto OPEN_FAILED; + } + + /* + * The nmreq structure must have the NETMAP_API version for the running machine. + * However the binary may have been compiled on a different machine than the + * running machine. Discover the true netmap API version, and be careful to call + * fuctions that are available on all netmap versions. + */ + + sp->netmap_version = get_netmap_version(sp->handle.fd); + if (sp->netmap_version < 0) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to determine the running netmap version.\n" + "Try upgrading netmap and recompiling on the running machine."); + goto NETMAP_VERSION_FAILED; + } + + if (sp->netmap_version >= 10) { + switch (*port) { + case '-': /* one NIC */ + nr_flags = NR_REG_ONE_NIC; + nr_ringid = atoi(port + 1); + break; + + case '*': /* NIC and SW, ignore port */ + nr_flags = NR_REG_NIC_SW; + if (port[1]) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid netmap port for nic+sw"); + goto NETMAP_IF_PARSE_FAIL; + } + break; + + case '^': /* only sw ring */ + nr_flags = NR_REG_SW; + if (port[1]) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid port for sw ring"); + goto NETMAP_IF_PARSE_FAIL; + } + break; + + case '{': + nr_flags = NR_REG_PIPE_MASTER; + nr_ringid = atoi(port + 1); + break; + + case '}': + nr_flags = NR_REG_PIPE_SLAVE; + nr_ringid = atoi(port + 1); + break; + + case '!': + nr_flags = NR_REG_ALL_NIC; + break; + + default: /* '\0', no suffix */ + nr_flags = NR_REG_DEFAULT; + break; + } + + if (nr_ringid >= NETMAP_RING_MASK) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid ringid"); + goto NETMAP_IF_PARSE_FAIL; + } + + nmr.nr_ringid = nr_ringid; + nmr.nr_flags = nr_flags; + } + + nmr.nr_version = sp->netmap_version; + memcpy(nmr.nr_name, ifname, namelen); + nmr.nr_name[namelen] = '\0'; + strlcpy (sp->device, nmr.nr_name, sizeof(sp->device)); + + /* + * Register the interface on the netmap device: from now on, + * we can operate on the network interface without any + * interference from the legacy network stack. + * + * Cards take a long time to reset the PHY. + */ + fprintf(stderr, "Switching network driver for %s to netmap bypass mode... ", + sp->device); + fflush(NULL); + sleep(1); /* ensure message prints when user is connected via ssh */ + + + if (ioctl (sp->handle.fd, NIOCREGIF, &nmr)) { + snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Failure accessing netmap.\n" + "\tRequest for netmap version %u failed.\n\tCompiled netmap driver is version %u.\n\tError=%s\n", + sp->netmap_version, NETMAP_API, strerror(errno)); + goto NETMAP_UP_FAILED; + } + + sp->mmap_size = nmr.nr_memsize; + sp->mmap_addr = (struct netmap_d *)mmap (0, sp->mmap_size, + PROT_WRITE | PROT_READ, MAP_SHARED, sp->handle.fd, 0); + + if (!sp->mmap_addr || sp->mmap_addr == MAP_FAILED) { + snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "mmap: %s", strerror (errno)); + goto MMAP_FAILED; + } + + dbgx(1, "sendpacket_open_netmap: mapping %d Kbytes queues=%d", + sp->mmap_size >> 10, nmr.nr_tx_rings); + + sp->nm_if = NETMAP_IF(sp->mmap_addr, nmr.nr_offset); + sp->nmr = nmr; + sp->handle_type = SP_TYPE_NETMAP; + + /* set up ring IDs */ + sp->cur_tx_ring = 0; + switch(nr_flags) { + case NR_REG_DEFAULT: /* only use one queue to prevent TX reordering */ + sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0; + break; + + case NR_REG_ALL_NIC: + sp->first_tx_ring = sp->cur_tx_ring = 0; + sp->last_tx_ring = nmr.nr_tx_rings - 1; + break; + + case NR_REG_SW: + sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nmr.nr_tx_rings; + break; + + case NR_REG_NIC_SW: + sp->first_tx_ring = sp->cur_tx_ring = 0; + sp->last_tx_ring = nmr.nr_tx_rings; + break; + + case NR_REG_ONE_NIC: + sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nr_ringid; + break; + + default: + sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0; + } + { + /* debugging code */ + int i; + + dbgx(1, "%s tx first=%d last=%d num=%d", ifname, + sp->first_tx_ring, sp->last_tx_ring, sp->nmr.nr_tx_rings); + for (i = 0; i <= sp->nmr.nr_tx_rings; i++) { +#ifdef HAVE_NETMAP_RING_HEAD_TAIL + dbgx(1, "TX%d 0x%p head=%d cur=%d tail=%d", i, NETMAP_TXRING(sp->nm_if, i), + (NETMAP_TXRING(sp->nm_if, i))->head, + (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->tail); +#else + dbgx(1, "TX%d 0x%p cur=%d avail=%d", i, NETMAP_TXRING(sp->nm_if, i), + (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->avail); +#endif + } + } + + dbg(2, "Waiting 4 seconds for phy reset..."); + sleep (4); + dbg(2, "Ready!"); + + if (!sp->is_vale) { + if (nm_do_ioctl(sp, SIOCGIFFLAGS, 0) < 0) + goto NM_DO_IOCTL_FAILED; + } + + if ((sp->if_flags & IFF_UP) == 0) { + dbgx(1, "%s is down, bringing up...", sp->device); + sp->if_flags |= IFF_UP; + } + + + if (!sp->is_vale) { + if ((sp->if_flags & IFF_RUNNING) == 0) { + dbgx(1, "sendpacket_open_netmap: %s is not running", sp->device); + snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "interface %s is not running - check cables\n", sp->device); + goto NETMAP_IF_NOT_RUNNING; + } + + /* set promiscuous mode */ + sp->if_flags |= IFF_PROMISC; + if (nm_do_ioctl(sp, SIOCSIFFLAGS, 0) < 0) + goto NM_DO_IOCTL_FAILED; + +#ifdef linux + /* disable: + * - generic-segmentation-offload + * - tcp-segmentation-offload + * - rx-checksumming + * - tx-checksumming + */ + if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GGSO) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTSO) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GRXCSUM) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTXCSUM) < 0) + goto NM_DO_IOCTL_FAILED; + + sp->data = 0; + if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM) < 0 || + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM)) + goto NM_DO_IOCTL_FAILED; +#endif + } + + if(sp->abort) + goto NETMAP_ABORT; + + notice("done!"); + + return sp; + +NM_DO_IOCTL_FAILED: + snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "nm_do_ioctl: %s", strerror (errno)); +NETMAP_IF_NOT_RUNNING: + notice("failed!"); +NETMAP_ABORT: + fprintf(stderr, " Switching network driver for %s to normal mode... ", + sp->device); + fflush(NULL); + munmap(sp->mmap_addr, sp->mmap_size); +MMAP_FAILED: +#if NETMAP_API < 10 + ioctl(sp->handle.fd, NIOCUNREGIF, NULL); +#endif +NETMAP_UP_FAILED: +NETMAP_IF_PARSE_FAIL: +NETMAP_VERSION_FAILED: + close (sp->handle.fd); +OPEN_FAILED: + safe_free(sp); +IFACENAME_INVALID: + + return NULL; +} + +void sendpacket_close_netmap(void *p) +{ + sendpacket_t *sp = p; + fprintf(stderr, "Switching network driver for %s to normal mode... ", + sp->device); + fflush(NULL); + /* flush any remaining packets */ + ioctl(sp->handle.fd, NIOCTXSYNC, NULL); + +#ifdef linux + if (!sp->is_vale) { + /* restore original settings: + * - generic-segmentation-offload + * - tcp-segmentation-offload + * - rx-checksumming + * - tx-checksumming + */ + sp->data = sp->gso; + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO); + sp->data = sp->tso; + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO); + sp->data = sp->rxcsum; + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM); + sp->data = sp->txcsum; + nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM); + } +#endif /* linux */ + + /* restore interface to normal mode */ +#if NETMAP_API < 10 + ioctl(sp->handle.fd, NIOCUNREGIF, NULL); +#endif + if (sp->mmap_addr) + munmap(sp->mmap_addr, sp->mmap_size); + close(sp->handle.fd); + notice("done!"); +} + +int sendpacket_send_netmap(void *p, const u_char *data, size_t len) +{ + int retcode = 0; + sendpacket_t *sp = p; + struct netmap_ring *txring; + struct netmap_slot *slot; + char *pkt; + uint32_t cur, avail; + + if (sp->abort) + return retcode; + + txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); + while ((avail = nm_ring_space(txring)) == 0) { + /* out of space on current TX queue - go to next */ + ++sp->cur_tx_ring; + if (sp->cur_tx_ring > sp->last_tx_ring) { + /* + * out of space on all queues + * + * we have looped through all configured TX queues + * so we have to reset to the first queue and + * wait for available space + */ + struct pollfd pfd; + + sp->cur_tx_ring = sp->first_tx_ring; + + /* send TX interrupt signal + * + * On Linux this makes one slot free on the + * ring, which increases speed by about 10Mbps. + * + * But it will never free up all the slots. For + * that we must poll and call again. + */ + ioctl(sp->handle.fd, NIOCTXSYNC, NULL); + + pfd.fd = sp->handle.fd; + pfd.events = POLLOUT; + pfd.revents = 0; + if (poll(&pfd, 1, 1000) <= 0) { + if (++sp->tx_timeouts == NETMAP_TX_TIMEOUT_SEC) { + return -1; + } + return -2; + } + + sp->tx_timeouts = 0; + + /* + * Do not remove this even though it looks redundant. + * Overall performance is increased with this restart + * of the TX queue. + * + * This call increases the number of available slots from + * 1 to all that are truly available. + */ + ioctl(sp->handle.fd, NIOCTXSYNC, NULL); + } + + txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring); + } + + /* + * send + */ + cur = txring->cur; + slot = &txring->slot[cur]; + slot->flags = 0; + pkt = NETMAP_BUF(txring, slot->buf_idx); + memcpy(pkt, data, min(len, txring->nr_buf_size)); + slot->len = len; + + if (avail <= 1) + slot->flags = NS_REPORT; + + dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n", + cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring), + nm_ring_space(txring), txring->nr_buf_size); + + /* let kernel know that packet is available */ + cur = NETMAP_RING_NEXT(txring, cur); +#ifdef HAVE_NETMAP_RING_HEAD_TAIL + txring->head = cur; +#else + txring->avail--; +#endif + txring->cur = cur; + retcode = len; + + return retcode; +} diff --git a/src/common/netmap.h b/src/common/netmap.h new file mode 100644 index 000000000..7cb71b3f9 --- /dev/null +++ b/src/common/netmap.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2013 Fred Klassen - AppNeta Inc. + * + * The Tcpreplay Suite of tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or with the authors permission any later version. + * + * The Tcpreplay Suite is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Tcpreplay Suite. If not, see . + */ +#ifndef NETMAP_H_ +#define NETMAP_H_ + +#include "config.h" +#include "defines.h" +#include +#ifdef __NetBSD__ +#include +#else +#include +#endif + +#include +#include +#include + +#ifdef linux +# include +# include +#endif /* linux */ + +#ifdef HAVE_NETMAP_RING_HEAD_TAIL +#define NETMAP_TX_RING_EMPTY(ring) (nm_ring_space(ring) >= (ring)->num_slots - 1) +#define NETMAP_RING_NEXT(r, i) nm_ring_next(r, i) +#else +#define nm_ring_space(ring) (ring->avail) +#endif /* NETMAP_API < 10 */ + +#ifndef NETMAP_API +#define NETMAP_API 0 +#endif + +#ifndef HAVE_NETMAP_NR_REG +#define NR_REG_MASK 0xf /* values for nr_flags */ +enum { NR_REG_DEFAULT = 0, /* backward compat, used in older versions. */ + NR_REG_ALL_NIC, + NR_REG_SW, + NR_REG_NIC_SW, + NR_REG_ONE_NIC, + NR_REG_PIPE_MASTER, + NR_REG_PIPE_SLAVE, +}; +#endif + +#ifndef NETMAP_HW_RING +#define NETMAP_HW_RING 0x4000 /* single NIC ring pair */ +#endif +#ifndef NETMAP_SW_RING +#define NETMAP_SW_RING 0x2000 /* only host ring pair */ +#endif +#ifndef NETMAP_RING_MASK +#define NETMAP_RING_MASK 0x0fff /* the ring number */ +#endif +#ifndef NETMAP_NO_TX_POLL +#define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */ +#endif +#ifndef NETMAP_DO_RX_POLL +#define NETMAP_DO_RX_POLL 0x8000 /* DO automatic rxsync on poll */ +#endif +#ifndef NETMAP_BDG_ATTACH +#define NETMAP_BDG_ATTACH 1 /* attach the NIC */ +#endif +#ifndef NETMAP_BDG_DETACH +#define NETMAP_BDG_DETACH 2 /* detach the NIC */ +#endif +#ifndef NETMAP_BDG_LOOKUP_REG +#define NETMAP_BDG_LOOKUP_REG 3 /* register lookup function */ +#endif +#ifndef NETMAP_BDG_LIST +#define NETMAP_BDG_LIST 4 /* get bridge's info */ +#endif +#ifndef NETMAP_BDG_VNET_HDR +#define NETMAP_BDG_VNET_HDR 5 /* set the port virtio-net-hdr length */ +#endif +#ifndef NETMAP_BDG_OFFSET +#define NETMAP_BDG_OFFSET NETMAP_BDG_VNET_HDR /* deprecated alias */ +#endif +#ifndef NETMAP_BDG_HOST +#define NETMAP_BDG_HOST 1 /* attach the host stack on ATTACH */ +#endif + +#ifdef HAVE_NETMAP_NR_FLAGS +typedef struct nmreq nmreq_t; +#else +struct tcpr_nmreq { + char nr_name[IFNAMSIZ]; + uint32_t nr_version; /* API version */ + uint32_t nr_offset; /* nifp offset in the shared region */ + uint32_t nr_memsize; /* size of the shared region */ + uint32_t nr_tx_slots; /* slots in tx rings */ + uint32_t nr_rx_slots; /* slots in rx rings */ + uint16_t nr_tx_rings; /* number of tx rings */ + uint16_t nr_rx_rings; /* number of rx rings */ + uint16_t nr_ringid; /* ring(s) we care about */ + uint16_t nr_cmd; + uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */ + uint16_t nr_arg2; + uint32_t nr_arg3; /* req. extra buffers in NIOCREGIF */ + uint32_t nr_flags; + /* various modes, extends nr_ringid */ + uint32_t spare2[1]; +}; +typedef struct tcpr_nmreq nmreq_t; + +#endif /* HAVE_NETMAP_NR_FLAGS */ + +#define NETMAP_TX_TIMEOUT_SEC 10 +int get_netmap_version(int fd); +void *sendpacket_open_netmap(const char *device, char *errbuf); +void sendpacket_close_netmap(void *p); +int sendpacket_send_netmap(void *p, const u_char *data, size_t len); + +#endif /* NETMAP_H_ */ diff --git a/src/common/sendpacket.c b/src/common/sendpacket.c index 712706a31..3d7218d80 100644 --- a/src/common/sendpacket.c +++ b/src/common/sendpacket.c @@ -128,22 +128,6 @@ #include #include -#ifdef HAVE_NETMAP -#include -#ifdef linux -# include -# include -#endif /* linux */ -static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd); -static sendpacket_t *sendpacket_open_netmap(const char *device, char *errbuf); -#if NETMAP_API >= 10 -#define NETMAP_TX_RING_EMPTY nm_ring_empty -#else -#define nm_ring_space(ring) \ - (ring->avail) -#endif /* NETMAP_API < 10 */ -#endif /* HAVE_NETMAP */ - #ifdef HAVE_PF_PACKET #undef INJECT_METHOD @@ -227,20 +211,6 @@ static void sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...); static sendpacket_t * sendpacket_open_khial(const char *, char *) _U_; static struct tcpr_ether_addr * sendpacket_get_hwaddr_khial(sendpacket_t *) _U_; -#ifdef HAVE_NETMAP -static inline uint32_t get_netmap_buf_avail(struct netmap_ring *ring) -{ - uint32_t avail; -#if NETMAP_API > 4 - avail = nm_ring_space(ring); -#else - avail = ring->avail; -#endif - - return avail; -} -#endif /* HAVE_NETMAP */ - /** * returns number of bytes sent on success or -1 on error * Note: it is theoretically possible to get a return code >0 and < len @@ -260,13 +230,6 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr * prevent page misses on stack */ static const size_t buffer_payload_size = sizeof(buffer) + sizeof(struct pcap_pkthdr); -#ifdef HAVE_NETMAP - struct netmap_ring *txring; - struct netmap_slot *slot; - char *p; - uint32_t cur, avail; - bool tx_queue_empty; -#endif assert(sp); assert(data); @@ -277,7 +240,6 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr TRY_SEND_AGAIN: sp->attempt ++; - switch (sp->handle_type) { case SP_TYPE_KHIAL: @@ -457,73 +419,15 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr case SP_TYPE_NETMAP: #ifdef HAVE_NETMAP - txring = NETMAP_TXRING(sp->nm_if, 0); - while ((avail = get_netmap_buf_avail(txring)) == 0) { - struct pollfd pfd; - - /* send TX interrupt signal just in case */ - ioctl(sp->handle.fd, NIOCTXSYNC, NULL); - - if (sp->abort) - return retcode; - - pfd.fd = sp->handle.fd; - pfd.events = POLLOUT; - pfd.revents = 0; - if (poll(&pfd, 1, 1000) <= 0) { - dbgx(2, "netmap timeout empty=%d avail=%u bufsize=%d\n", - NETMAP_TX_RING_EMPTY(txring), - avail, txring->nr_buf_size); - goto TRY_SEND_AGAIN; - } - - /* - * Do not remove this even though it looks redundant. - * Overall performance is increased with this restart - * of the TX queue. - */ - ioctl(sp->handle.fd, NIOCTXSYNC, NULL); - - dbgx(2, "netmap poll empty=%d avail=%u bufsize=%d\n", - NETMAP_TX_RING_EMPTY(txring), - avail, txring->nr_buf_size); + retcode = sendpacket_send_netmap(sp, data, len); + + if (retcode == -1) { + sendpacket_seterr(sp, "interface hung!!"); + } else if (retcode == -2) { + /* this indicates that a retry was requested - this is not a failure */ + retcode = 0; + goto TRY_SEND_AGAIN; } - - /* - * send - */ - cur = txring->cur; - slot = &txring->slot[cur]; - slot->flags = 0; - p = NETMAP_BUF(txring, slot->buf_idx); - memcpy(p, data, min(len, txring->nr_buf_size)); - slot->len = len; - - /* let kernel know that packet is available */ -#if NETMAP_API >= 10 - dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n", - cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring), - nm_ring_space(txring), txring->nr_buf_size); - cur = nm_ring_next(txring, cur); - tx_queue_empty = nm_ring_empty(txring); - txring->head = cur; -#else - dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n", - cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring), - txring->avail, txring->nr_buf_size); - cur = NETMAP_RING_NEXT(txring, cur); - tx_queue_empty = NETMAP_TX_RING_EMPTY(txring); - txring->avail--; -#endif - txring->cur = cur; - retcode = len; - - /* - * If the queue is empty, tell netmap that packets are ready to TX - */ - if (tx_queue_empty) - ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* generate TX interrupt */ - #endif /* HAVE_NETMAP */ break; @@ -598,7 +502,7 @@ sendpacket_open(const char *device, char *errbuf, tcpr_dir_t direction, } else { #ifdef HAVE_NETMAP if (sendpacket_type == SP_TYPE_NETMAP) - sp = sendpacket_open_netmap(device, errbuf); + sp = (sendpacket_t*)sendpacket_open_netmap(device, errbuf); else #endif #if defined HAVE_PF_PACKET @@ -703,38 +607,7 @@ sendpacket_close(sendpacket_t *sp) case SP_TYPE_NETMAP: #ifdef HAVE_NETMAP - fprintf(stderr, "Switching network driver for %s to normal mode... ", - sp->device); - fflush(NULL); - /* flush any remaining packets */ - ioctl(sp->handle.fd, NIOCTXSYNC, NULL); - -#ifdef linux - if (sp->is_vale == 0) { - /* restore original settings: - * - generic-segmentation-offload - * - tcp-segmentation-offload - * - rx-checksumming - * - tx-checksumming - */ - sp->data = sp->gso; - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO); - sp->data = sp->tso; - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO); - sp->data = sp->rxcsum; - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM); - sp->data = sp->txcsum; - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM); - } -#endif /* linux */ - - /* restore interface to normal mode */ -#if NETMAP_API < 10 - ioctl(sp->handle.fd, NIOCUNREGIF, NULL); -#endif - munmap(sp->mmap_addr, sp->mmap_size); - close(sp->handle.fd); - notice("done!"); + sendpacket_close_netmap(sp); #endif /* HAVE_NETMAP */ break; @@ -906,245 +779,6 @@ sendpacket_get_hwaddr_libdnet(sendpacket_t *sp) #endif /* HAVE_LIBDNET */ #ifdef HAVE_NETMAP -/** - * ioctl support for netmap - */ -static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd) { - struct ifreq ifr; - int error; - int fd; -#ifdef linux - struct ethtool_value eval; -#endif - - assert(sp); - - fd = socket (AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - dbg(1, "ioctl error: cannot get device control socket.\n"); - return -1; - } - - bzero (&ifr, sizeof(ifr)); - strncpy (ifr.ifr_name, sp->device, sizeof(ifr.ifr_name)); - - switch (what) { - case SIOCSIFFLAGS: - ifr.ifr_flags = sp->if_flags >> 16; - ifr.ifr_flags = sp->if_flags & 0xffff; - break; - -#ifdef linux - case SIOCETHTOOL: - eval.cmd = subcmd; - eval.data = sp->data; - ifr.ifr_data = (caddr_t)&eval; - dbgx(1, "ioctl SIOCETHTOOL subcmd=%d data=%u", subcmd, eval.data); - break; -#endif - } - - error = ioctl (fd, what, &ifr); - if (error) - goto done; - - switch (what) { - case SIOCGIFFLAGS: - sp->if_flags = (ifr.ifr_flags << 16) | (0xffff & ifr.ifr_flags); - dbgx(1, "SIOCGIFFLAGS flags are 0x%x", sp->if_flags); - break; - -#ifdef linux - case SIOCETHTOOL: - switch (subcmd) { - case ETHTOOL_GGSO: - sp->gso = eval.data; - dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GGSO=%u", eval.data); - break; - - case ETHTOOL_GTSO: - sp->tso = eval.data; - dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTSO=%u", eval.data); - break; - - case ETHTOOL_GRXCSUM: - sp->rxcsum = eval.data; - dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GRXCSUM=%u", eval.data); - break; - - case ETHTOOL_GTXCSUM: - sp->txcsum = eval.data; - dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTXCSUM=%u", eval.data); - break; - } - break; -#endif - - } - -done: - close (fd); - - if (error) - warnx("ioctl error %d %lu:%d", error, what, subcmd); - return error; -} - -/** - * Inner sendpacket_open() method for using Linux version of netmap - */ -static sendpacket_t * -sendpacket_open_netmap(const char *device, char *errbuf) -{ - sendpacket_t *sp = NULL; - struct nmreq nmr; - - assert(device); - assert(errbuf); - - dbg(1, "sendpacket_open_netmap: using netmap"); - - /* prep & return our sp handle */ - sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t)); - - /* - * Open the netmap device to fetch the number of queues of our - * interface. - * - * The first NIOCREGIF also detaches the card from the - * protocol stack and may cause a reset of the card, - * which in turn may take some time for the PHY to - * reconfigure. - */ - if ((sp->handle.fd = open ("/dev/netmap", O_RDWR)) < 0) { - dbg(1, "sendpacket_open_netmap: Unable to access netmap"); - snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to access netmap.\n" - "See INSTALL to learn how to set up netmap-capable network drivers."); - goto OPEN_FAILED; - } - - /* - * Register the interface on the netmap device: from now on, - * we can operate on the network interface without any - * interference from the legacy network stack. - * - * Cards take a long time to reset the PHY. - */ - fprintf(stderr, "Switching network driver for %s to netmap bypass mode... ", - device); - fflush(NULL); - - bzero (&nmr, sizeof(nmr)); - strncpy (nmr.nr_name, device, sizeof(nmr.nr_name)); - nmr.nr_version = NETMAP_API; - - if (ioctl (sp->handle.fd, NIOCREGIF, &nmr) == -1) { - snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Failure accessing netmap.\n" - "\tRequest for netmap version %u failed.\n\tMake sure netmap driver is version %u.\n\tError=%s\n", - NETMAP_API, NETMAP_API, strerror(errno)); - goto NETMAP_UP_FAILED; - } - - sp->mmap_size = nmr.nr_memsize; - - dbgx(1, "sendpacket_open_netmap: mapping %d Kbytes queues=%d", - sp->mmap_size >> 10, nmr.nr_tx_rings); - sp->mmap_addr = (struct netmap_d *)mmap (0, sp->mmap_size, - PROT_WRITE | PROT_READ, MAP_SHARED, sp->handle.fd, 0); - - if (sp->mmap_addr == MAP_FAILED ) { - snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "mmap: %s", strerror (errno)); - goto MMAP_FAILED; - } - - bzero (&nmr, sizeof(nmr)); - strncpy (nmr.nr_name, device, sizeof(nmr.nr_name)); - nmr.nr_version = NETMAP_API; - strlcpy (sp->device, device, sizeof(sp->device)); - sp->nm_if = NETMAP_IF(sp->mmap_addr, nmr.nr_offset); - sp->nmr = nmr; - sp->handle_type = SP_TYPE_NETMAP; - - dbg(2, "Waiting 4 seconds for phy reset..."); - sleep (4); - dbg(2, "Ready!"); - - if (strncmp("vale", device, 4) == 0) - sp->is_vale = 1; - - if (sp->is_vale == 0) { - if (nm_do_ioctl(sp, SIOCGIFFLAGS, 0) < 0) - goto NM_DO_IOCTL_FAILED; - } - - if ((sp->if_flags & IFF_UP) == 0) { - dbgx(1, "%s is down, bringing up...", device); - sp->if_flags |= IFF_UP; - } - - if ((sp->if_flags & IFF_RUNNING) == 0) { - dbgx(1, "sendpacket_open_netmap: %s is not running", device); - snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "interface %s is not running - check cables\n", device); - goto NETMAP_IF_NOT_RUNNING; - } - - if (sp->is_vale == 0) { - - /* set promiscuous mode */ - sp->if_flags |= IFF_PROMISC; - if (nm_do_ioctl(sp, SIOCSIFFLAGS, 0) < 0) - goto NM_DO_IOCTL_FAILED; - -#ifdef linux - /* disable: - * - generic-segmentation-offload - * - tcp-segmentation-offload - * - rx-checksumming - * - tx-checksumming - */ - if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GGSO) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTSO) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GRXCSUM) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTXCSUM) < 0) - goto NM_DO_IOCTL_FAILED; - - sp->data = 0; - if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM) < 0 || - nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM)) - goto NM_DO_IOCTL_FAILED; -#endif - } - - if(sp->abort) - goto NETMAP_ABORT; - - notice("done!"); - - return sp; - -NM_DO_IOCTL_FAILED: - snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "nm_do_ioctl: %s", strerror (errno)); -NETMAP_IF_NOT_RUNNING: - notice("failed!"); -NETMAP_ABORT: - fprintf(stderr, " Switching network driver for %s to normal mode... ", - sp->device); - fflush(NULL); - munmap(sp->mmap_addr, sp->mmap_size); -MMAP_FAILED: -#if NETMAP_API < 10 - ioctl(sp->handle.fd, NIOCUNREGIF, NULL); -#endif -NETMAP_UP_FAILED: - close (sp->handle.fd); -OPEN_FAILED: - safe_free(sp); - - notice("done!"); - return NULL; -} #endif /* HAVE_NETMAP */ #if defined HAVE_PF_PACKET diff --git a/src/common/sendpacket.h b/src/common/sendpacket.h index 759f6b3c2..9681daa17 100644 --- a/src/common/sendpacket.h +++ b/src/common/sendpacket.h @@ -30,12 +30,8 @@ #endif #if defined HAVE_NETMAP -#include +#include "common/netmap.h" #include -#include -#ifndef NETMAP_API -#define NETMAP_API 0 -#endif #endif #ifdef HAVE_PF_PACKET @@ -95,11 +91,12 @@ union sendpacket_handle { }; #define SENDPACKET_ERRBUF_SIZE 1024 +#define MAX_IFNAMELEN 64 struct sendpacket_s { tcpr_dir_t cache_dir; int open; - char device[50]; + char device[MAX_IFNAMELEN]; char errbuf[SENDPACKET_ERRBUF_SIZE]; COUNTER retry_enobufs; COUNTER retry_eagain; @@ -119,11 +116,14 @@ struct sendpacket_s { struct tcpr_ether_addr ether; #ifdef HAVE_NETMAP struct netmap_if *nm_if; - struct nmreq nmr; + nmreq_t nmr; void *mmap_addr; int mmap_size; uint32_t if_flags; uint32_t is_vale; + int netmap_version; + int tx_timeouts; + uint16_t first_tx_ring, last_tx_ring, cur_tx_ring; #ifdef linux uint32_t data; uint32_t gso; diff --git a/src/config.h.in b/src/config.h.in index 5b7240ff8..70f34408f 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -215,6 +215,15 @@ /* Does netmap have nm_open function? */ #undef HAVE_NETMAP_NM_OPEN +/* Does netmap struct nmreq have nr_flags defined? */ +#undef HAVE_NETMAP_NR_FLAGS + +/* Does netmap have NR_REG_MASK defined? */ +#undef HAVE_NETMAP_NR_REG + +/* Does structure netmap_ring have head/tail defined? */ +#undef HAVE_NETMAP_RING_HEAD_TAIL + /* Define to 1 if you have the header file. */ #undef HAVE_NET_NETMAP_USER_H diff --git a/src/tcpreplay.c b/src/tcpreplay.c index 5d8e7aa7c..c09a0fd36 100644 --- a/src/tcpreplay.c +++ b/src/tcpreplay.c @@ -61,6 +61,8 @@ main(int argc, char *argv[]) int rcode; char buf[1024]; + fflush(NULL); + ctx = tcpreplay_init(); #ifdef TCPREPLAY optct = optionProcess(&tcpreplayOptions, argc, argv); @@ -70,6 +72,7 @@ main(int argc, char *argv[]) argc -= optct; argv += optct; + fflush(NULL); rcode = tcpreplay_post_args(ctx, argc); if (rcode <= -2) { warnx("%s", tcpreplay_getwarn(ctx)); @@ -77,6 +80,7 @@ main(int argc, char *argv[]) errx(-1, "Unable to parse args: %s", tcpreplay_geterr(ctx)); } + fflush(NULL); #ifdef TCPREPLAY_EDIT /* init tcpedit context */ if (tcpedit_init(&tcpedit, sendpacket_get_dlt(ctx->intf1)) < 0) { diff --git a/src/tcpreplay_api.c b/src/tcpreplay_api.c index c24afc8fb..7b2f6d8ab 100644 --- a/src/tcpreplay_api.c +++ b/src/tcpreplay_api.c @@ -303,6 +303,13 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) goto out; } +#ifdef HAVE_NETMAP + if (!strncmp(intname, "netmap:", 7) || !strncmp(intname, "vale:", 5)) { + options->netmap = 1; + ctx->sp_type = SP_TYPE_NETMAP; + } +#endif + options->intf1_name = safe_strdup(intname); /* open interfaces for writing */ @@ -325,6 +332,13 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc) ret = -1; goto out; } +#ifdef HAVE_NETMAP + if (!strncmp(intname, "netmap:", 7) || !strncmp(intname, "vale:", 5)) { + tcpreplay_seterr(ctx, "netmap/vale interface aliases not allowed for interface 2: %s", OPT_ARG(INTF2)); + ret = -1; + goto out; + } +#endif options->intf2_name = safe_strdup(intname); @@ -559,7 +573,6 @@ tcpreplay_set_netmap(tcpreplay_t *ctx, bool value) warn("netmap not compiled in"); return -1; #endif - return 0; } /**