From e1539bdbcb636f3fc3d3982bc3ee1987d6c00643 Mon Sep 17 00:00:00 2001 From: Christian Bell Date: Tue, 26 Jan 2010 11:58:37 -0800 Subject: [PATCH] Add Myricom SNF API support as a new pcap device. This patch adds support for our NICs when run in a specialized capture mode. It is diffed against the current master. The Myricom Sniffer10G software uses Myri-10G programmable Network Interface Cards (NICs), a firmware extension, a specialized driver and a user-level library (libsnf) to enable sustained capture of 10-Gigabit Ethernet traffic. Small-packet coalescing and an efficient zero-copy path to host memory allow Sniffer10G to capture streams at line rate for all Ethernet packet sizes. Optionally, libpcap can be used concurrently by multiple processes on a single NIC port to partition the incoming traffic across processes. While the Linux kernel enables this through multiple receive queues, the difference is that the myri_snf driver cooperates with libsnf to set up multiple queues that are each independently accessible through user-space. More information here: http://www.myri.com/scs/SNF/doc Signed-off-by: Guy Harris --- config.h.in | 3 + configure | 209 +++++++++++++++++++++++++++++++++++ configure.in | 113 +++++++++++++++++++ inet.c | 3 + pcap-bpf.c | 12 ++ pcap-int.h | 11 ++ pcap-linux.c | 16 +++ pcap-snf.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++ pcap-snf.h | 2 + 9 files changed, 675 insertions(+) create mode 100644 pcap-snf.c create mode 100644 pcap-snf.h diff --git a/config.h.in b/config.h.in index 990091d..55e13da 100644 --- a/config.h.in +++ b/config.h.in @@ -91,6 +91,9 @@ /* define if you have a Septel API */ #undef HAVE_SEPTEL_API +/* define if you have Myricom SNF API */ +#undef HAVE_SNF_API + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF diff --git a/configure b/configure index 961024d..dd86732 100755 --- a/configure +++ b/configure @@ -1313,6 +1313,11 @@ Optional Packages: Endace DAG library directory --with-septel[=DIR] include Septel support (located in directory DIR, if supplied). [default=yes, on Linux, if present] + --with-snf[=DIR] include Myricom SNF support ["yes", "no" or DIR; + default="yes" on BSD and Linux if present] + --with-snf-includes=DIR Myricom SNF include directory + --with-snf-libraries=DIR + Myricom SNF library directory --without-flex don't use flex --without-bison don't use bison @@ -7800,6 +7805,10 @@ septel) V_DEFS="$V_DEFS -DSEPTEL_ONLY" ;; +snf) + V_DEFS="$V_DEFS -DSNF_ONLY" + ;; + null) { echo "$as_me:$LINENO: WARNING: cannot determine packet capture interface" >&5 echo "$as_me: WARNING: cannot determine packet capture interface" >&2;} @@ -9095,6 +9104,206 @@ echo "$as_me: error: Specifying the capture type as 'septel' requires the Septel { (exit 1); exit 1; }; } fi +# Check for Myricom SNF support. + +# Check whether --with-snf was given. +if test "${with_snf+set}" = set; then + withval=$with_snf; + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specific a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi + +else + + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent + +fi + + + +# Check whether --with-snf-includes was given. +if test "${with_snf_includes+set}" = set; then + withval=$with_snf_includes; + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval + +fi + + + +# Check whether --with-snf-libraries was given. +if test "${with_snf_libraries+set}" = set; then + withval=$with_snf_libraries; + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval + +fi + + +case "$V_PCAP" in +bpf|linux|snf) + # + # We support the Sniffer API if we're on BSD, Linux, or if we're + # building a Sniffer-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Sniffer, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_snf = yes; then + { { echo "$as_me:$LINENO: error: Myricom SNF support only available with 'bpf' 'linux' and 'snf' packet capture types" >&5 +echo "$as_me: error: Myricom SNF support only available with 'bpf' 'linux' and 'snf' packet capture types" >&2;} + { (exit 1); exit 1; }; } + elif test $want_snf = yes; then + want_snf=no + fi + ;; +esac + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + { echo "$as_me:$LINENO: checking whether we have Myricom Sniffer API" >&5 +echo $ECHO_N "checking whether we have Myricom Sniffer API... $ECHO_C" >&6; } + + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + fi + + if test -f "$snf_include_dir/snf.h"; then + ac_cv_lbl_snf_api=yes + fi + { echo "$as_me:$LINENO: result: $ac_cv_lbl_snf_api ($snf_root)" >&5 +echo "${ECHO_T}$ac_cv_lbl_snf_api ($snf_root)" >&6; } + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + { { echo "$as_me:$LINENO: error: SNF API headers not found under $snf_include_dir; use --without-snf" >&5 +echo "$as_me: error: SNF API headers not found under $snf_include_dir; use --without-snf" >&2;} + { (exit 1); exit 1; }; } + fi + else + saved_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + { echo "$as_me:$LINENO: checking for snf_init in -lsnf" >&5 +echo $ECHO_N "checking for snf_init in -lsnf... $ECHO_C" >&6; } +if test "${ac_cv_lib_snf_snf_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnf $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char snf_init (); +int +main () +{ +return snf_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_snf_snf_init=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_snf_snf_init=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_snf_snf_init" >&5 +echo "${ECHO_T}$ac_cv_lib_snf_snf_init" >&6; } +if test $ac_cv_lib_snf_snf_init = yes; then + ac_cv_lbl_snf_api="yes" +else + ac_cv_lbl_snf_api="no" +fi + + LDFLAGS="$saved_ldflags" + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + { { echo "$as_me:$LINENO: error: SNF API cannot correctly be linked check config.log; use --without-snf" >&5 +echo "$as_me: error: SNF API cannot correctly be linked check config.log; use --without-snf" >&2;} + { (exit 1); exit 1; }; } + fi + else + V_INCLS="$V_INCLS -I$snf_include_dir" + LIBS="$LIBS -L$snf_lib_dir -lsnf" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SNF_API 1 +_ACEOF + + fi + fi +fi + +if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then + { { echo "$as_me:$LINENO: error: Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR" >&5 +echo "$as_me: error: Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR" >&2;} + { (exit 1); exit 1; }; } +fi # Check whether --with-flex was given. diff --git a/configure.in b/configure.in index a0e5973..4e515cf 100644 --- a/configure.in +++ b/configure.in @@ -500,6 +500,10 @@ septel) V_DEFS="$V_DEFS -DSEPTEL_ONLY" ;; +snf) + V_DEFS="$V_DEFS -DSNF_ONLY" + ;; + null) AC_MSG_WARN(cannot determine packet capture interface) AC_MSG_WARN((see the INSTALL doc for more info)) @@ -978,6 +982,115 @@ if test "$V_PCAP" = septel -a "$ac_cv_lbl_septel_api" = no; then AC_MSG_ERROR(Specifying the capture type as 'septel' requires the Septel API to be present; use --with-septel=DIR) fi +# Check for Myricom SNF support. +AC_ARG_WITH([snf], +AC_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support @<:@"yes", "no" or DIR; default="yes" on BSD and Linux if present@:>@]), +[ + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specific a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi +],[ + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent +]) + +AC_ARG_WITH([snf-includes], +AC_HELP_STRING([--with-snf-includes=DIR],[Myricom SNF include directory]), +[ + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval +],[]) + +AC_ARG_WITH([snf-libraries], +AC_HELP_STRING([--with-snf-libraries=DIR],[Myricom SNF library directory]), +[ + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval +],[]) + +case "$V_PCAP" in +bpf|linux|snf) + # + # We support the Sniffer API if we're on BSD, Linux, or if we're + # building a Sniffer-only libpcap. + # + ;; +*) + # + # If the user explicitly requested Sniffer, tell them it's not + # supported. + # + # If they expressed no preference, don't include it. + # + if test $want_snf = yes; then + AC_MSG_ERROR(Myricom SNF support only available with 'bpf' 'linux' and 'snf' packet capture types) + elif test $want_snf = yes; then + want_snf=no + fi + ;; +esac + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + AC_MSG_CHECKING(whether we have Myricom Sniffer API) + + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + fi + + if test -f "$snf_include_dir/snf.h"; then + ac_cv_lbl_snf_api=yes + fi + AC_MSG_RESULT([$ac_cv_lbl_snf_api ($snf_root)]) + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + AC_MSG_ERROR(SNF API headers not found under $snf_include_dir; use --without-snf) + fi + else + saved_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"], [ac_cv_lbl_snf_api="no"]) + LDFLAGS="$saved_ldflags" + + if test $ac_cv_lbl_snf_api = no; then + if test "$want_snf" = yes; then + AC_MSG_ERROR(SNF API cannot correctly be linked check config.log; use --without-snf) + fi + else + V_INCLS="$V_INCLS -I$snf_include_dir" + LIBS="$LIBS -L$snf_lib_dir -lsnf" + AC_DEFINE(HAVE_SNF_API, 1, [define if you have Myricom SNF API]) + fi + fi +fi + +if test "$V_PCAP" = snf -a "$ac_cv_lbl_snf_api" = no; then + AC_MSG_ERROR(Specifying the capture type as 'snf' requires the Myricom Sniffer API to be present; use --with-snf=DIR) +fi AC_LBL_LEX_AND_YACC(V_LEX, V_YACC, pcap_) if test "$V_LEX" = lex ; then diff --git a/inet.c b/inet.c index b21487b..e411cbe 100644 --- a/inet.c +++ b/inet.c @@ -670,6 +670,9 @@ pcap_lookupnet(device, netp, maskp, errbuf) #endif #ifdef PCAP_SUPPORT_USB || strstr(device, "usbmon") != NULL +#endif +#ifdef HAVE_SNF_API + || strstr(device, "snf") != NULL #endif ) { *netp = *maskp = 0; diff --git a/pcap-bpf.c b/pcap-bpf.c index 02aeec4..310256d 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -126,6 +126,10 @@ static int bpf_load(char *errbuf); #include "pcap-dag.h" #endif /* HAVE_DAG_API */ +#ifdef HAVE_SNF_API +#include "pcap-snf.h" +#endif /* HAVE_SNF_API */ + #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -417,6 +421,10 @@ pcap_create(const char *device, char *ebuf) if (strstr(device, "dag")) return (dag_create(device, ebuf)); #endif /* HAVE_DAG_API */ +#ifdef HAVE_SNF_API + if (strstr(device, "snf")) + return (snf_create(device, ebuf)); +#endif /* HAVE_SNF_API */ p = pcap_create_common(device, ebuf); if (p == NULL) @@ -2170,6 +2178,10 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) if (dag_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif /* HAVE_DAG_API */ +#ifdef HAVE_SNF_API + if (snf_platform_finddevs(alldevsp, errbuf) < 0) + return (-1); +#endif /* HAVE_SNF_API */ return (0); } diff --git a/pcap-int.h b/pcap-int.h index 075e71a..c3afbad 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -56,6 +56,10 @@ extern CRITICAL_SECTION g_PcapCompileCriticalSection; #include #endif +#ifdef HAVE_SNF_API +#include +#endif + #if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/ /* @@ -162,6 +166,13 @@ struct pcap_md { * Same as in linux above, introduce * generally? */ #endif /* HAVE_DAG_API */ +#ifdef HAVE_SNF_API + snf_handle_t snf_handle; /* opaque device handle */ + snf_ring_t snf_ring; /* opaque device ring handle */ + int snf_timeout; + int snf_boardnum; +#endif /*HAVE_SNF_API*/ + #ifdef HAVE_ZEROCOPY_BPF /* * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will diff --git a/pcap-linux.c b/pcap-linux.c index 6df107d..af12543 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -170,6 +170,10 @@ static const char rcsid[] _U_ = #include "pcap-septel.h" #endif /* HAVE_SEPTEL_API */ +#ifdef HAVE_SNF_API +#include "pcap-snf.h" +#endif /* HAVE_SNF_API */ + #ifdef PCAP_SUPPORT_USB #include "pcap-usb-linux.h" #endif @@ -376,6 +380,13 @@ pcap_create(const char *device, char *ebuf) } #endif /* HAVE_SEPTEL_API */ +#ifdef HAVE_SNF_API + handle = snf_create(device, ebuf); + if (strstr(device, "snf") || handle != NULL) + return handle; + +#endif /* HAVE_SNF_API */ + #ifdef PCAP_SUPPORT_BT if (strstr(device, "bluetooth")) { return bt_create(device, ebuf); @@ -2100,6 +2111,11 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) return (-1); #endif /* HAVE_SEPTEL_API */ +#ifdef HAVE_SNF_API + if (snf_platform_finddevs(alldevsp, errbuf) < 0) + return (-1); +#endif /* HAVE_SNF_API */ + #ifdef PCAP_SUPPORT_BT /* * Add Bluetooth devices. diff --git a/pcap-snf.c b/pcap-snf.c new file mode 100644 index 0000000..96781bd --- /dev/null +++ b/pcap-snf.c @@ -0,0 +1,306 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "snf.h" +#include "pcap-int.h" + +#ifdef SNF_ONLY +#define snf_create pcap_create +#define snf_platform_finddevs pcap_platform_finddevs +#endif + +static int +snf_set_datalink(pcap_t *p, int dlt) +{ + p->linktype = dlt; + return (0); +} + +static int +snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct snf_ring_stats stats; + int rc; + + if ((rc = snf_ring_getstats(p->md.snf_ring, &stats))) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", + pcap_strerror(rc)); + return -1; + } + ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; + ps->ps_drop = stats.ring_pkt_overflow; + ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; + return 0; +} + +static void +snf_platform_cleanup(pcap_t *p) +{ + if (p == NULL) + return; + + snf_ring_close(p->md.snf_ring); + snf_close(p->md.snf_handle); + pcap_cleanup_live_common(p); +} + +static int +snf_getnonblock(pcap_t *p, char *errbuf) +{ + return (p->md.snf_timeout == 0); +} + +static int +snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + if (nonblock) + p->md.snf_timeout = 0; + else { + if (p->md.timeout <= 0) + p->md.snf_timeout = -1; /* forever */ + else + p->md.snf_timeout = p->md.timeout; + } + return (0); +} + +#define _NSEC_PER_SEC 1000000000 + +static inline +struct timeval +snf_timestamp_to_timeval(const int64_t ts_nanosec) +{ + struct timeval tv; + int32_t rem; + if (ts_nanosec == 0) + return (struct timeval) { 0, 0 }; + tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; + tv.tv_usec = (ts_nanosec % _NSEC_PER_SEC) / 1000; + return tv; +} + +static int +snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_pkthdr hdr; + int i, flags, err, caplen, n; + struct snf_recv_req req; + + if (!p || cnt == 0) + return -1; + + n = 0; + while (n < cnt || cnt < 0) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + return (n); + } + } + + err = snf_ring_recv(p->md.snf_ring, p->md.snf_timeout, &req); + + if (err) { + if (err == EBUSY || err == EAGAIN) + return (0); + if (err == EINTR) + continue; + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", + pcap_strerror(err)); + return -1; + } + } + + caplen = req.length; + if (caplen > p->snapshot) + caplen = p->snapshot; + + if ((p->fcode.bf_insns == NULL) || + bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { + hdr.ts = snf_timestamp_to_timeval(req.timestamp); + hdr.caplen = caplen; + hdr.len = req.length; + callback(user, &hdr, req.pkt_addr); + } + n++; + } + return (n); +} + +static int +snf_setfilter(pcap_t *p, struct bpf_program *fp) +{ + if (!p) + return -1; + if (!fp) { + strncpy(p->errbuf, "setfilter: No filter specified", + sizeof(p->errbuf)); + return -1; + } + + /* Make our private copy of the filter */ + + if (install_bpf_program(p, fp) < 0) + return -1; + + p->md.use_bpf = 0; + + return (0); +} + +static int +snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) +{ + strlcpy(p->errbuf, "Sending packets isn't supported with snf", + PCAP_ERRBUF_SIZE); + return (-1); +} + +static int +snf_activate(pcap_t* p) +{ + char *device = p->opt.source; + const char *nr = NULL; + int err; + int flags = 0; + + if (device == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "device is NULL: %s", pcap_strerror(errno)); + return -1; + } + + /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. + * Since libpcap isn't thread-safe */ + if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) + flags |= SNF_F_PSHARED; + else + nr = NULL; + + err = snf_open(p->md.snf_boardnum, + 0, /* let SNF API parse SNF_NUM_RINGS, if set */ + NULL, /* default RSS, or use SNF_RSS_FLAGS env */ + 0, /* default to SNF_DATARING_SIZE from env */ + flags, /* may want pshared */ + &p->md.snf_handle); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_open failed: %s", pcap_strerror(err)); + return -1; + } + + err = snf_ring_open(p->md.snf_handle, &p->md.snf_ring); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_ring_open failed: %s", pcap_strerror(err)); + return -1; + } + + if (p->md.timeout <= 0) + p->md.snf_timeout = -1; + else + p->md.snf_timeout = p->md.timeout; + + err = snf_start(p->md.snf_handle); + if (err != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_start failed: %s", pcap_strerror(err)); + return -1; + } + + /* + * "select()" and "poll()" don't work on snf descriptors. + */ + p->selectable_fd = -1; + p->linktype = DLT_EN10MB; + p->read_op = snf_read; + p->inject_op = snf_inject; + p->setfilter_op = snf_setfilter; + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = snf_set_datalink; + p->getnonblock_op = snf_getnonblock; + p->setnonblock_op = snf_setnonblock; + p->stats_op = snf_pcap_stats; + p->cleanup_op = snf_platform_cleanup; + p->md.stat.ps_recv = 0; + p->md.stat.ps_drop = 0; + p->md.stat.ps_ifdrop = 0; + return 0; +} + +int +snf_platform_finddevs(pcap_if_t **devlistp, char *errbuf) +{ + /* + * There are no platform-specific devices since each device + * exists as a regular Ethernet device. + */ + return 0; +} + +pcap_t * +snf_create(const char *device, char *ebuf) +{ + pcap_t *p; + int boardnum = -1; + struct snf_ifaddrs *ifaddrs, *ifa; + size_t devlen; + + if (snf_init(SNF_VERSION_API)) + return NULL; + + /* + * Match a given interface name to our list of interface names, from + * which we can obtain the intended board number + */ + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) + return NULL; + devlen = strlen(device) + 1; + ifa = ifaddrs; + while (ifa) { + if (!strncmp(device, ifa->snf_ifa_name, devlen)) { + boardnum = ifa->snf_ifa_boardnum; + break; + } + ifa = ifa->snf_ifa_next; + } + snf_freeifaddrs(ifaddrs); + + if (ifa == NULL) { + /* + * If we can't find the device by name, support the name "snfX" + * and "snf10gX" where X is the board number. + */ + if (sscanf(device, "snf10g%d", &boardnum) != 1 && + sscanf(device, "snf%d", &boardnum) != 1) + return NULL; + } + + p = pcap_create_common(device, ebuf); + if (p == NULL) + return NULL; + + p->activate_op = snf_activate; + p->md.snf_boardnum = boardnum; + return p; +} diff --git a/pcap-snf.h b/pcap-snf.h new file mode 100644 index 0000000..8c19755 --- /dev/null +++ b/pcap-snf.h @@ -0,0 +1,2 @@ +pcap_t *snf_create(const char *, char *); +int snf_platform_finddevs(pcap_if_t **devlistp, char *errbuf);