From patchwork Fri Apr 18 12:27:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Uvarov X-Patchwork-Id: 28633 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id CDCA02013D for ; Fri, 18 Apr 2014 12:27:28 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id lx4sf8830720iec.3 for ; Fri, 18 Apr 2014 05:27:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:subject :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=h/KyFlxakiKdYvm8ucO82rxgRiPHtE5+Q3YefMgUsrE=; b=QmPwZU3djbKQBwZ3nVsRvUyyXVP4xe2Vr6aVgYWamm4vWzYMDz0tkpCnHX99DzfuWp JoMYlQv7eoV9U4t04CJ1YHLVpnYlt7WeqkIWC79jpFrrHFIB1JtPAY1hAbQhQgp1qH8h 4IPTniJre2iNu9iO9U7wWqXJ9hu5NA/thjXCf0xu8K9DSaX3KiFuktUxFPuaOmxFwi8Z CO7GyHbxHJ5QArcSoPN57ZdHM6BhSyZ05wUeZk0EQGLCl4S2pP+1CJFp5R4NF6ZB4JS2 dDUM+m/i1ll3lctD/IcL0Vx4B+Cicu6eu6hqIph1uHoS9wEiDoJdFtwQ8C953hLGCD0Q xTCQ== X-Gm-Message-State: ALoCoQkCrqsEHCKaO0wzOKLEdE9a8nyV4E33dz4wQS1QJd696lZp6snh8rcH8v0lV6JcnwFTOFTR X-Received: by 10.43.45.1 with SMTP id ui1mr7599065icb.1.1397824048008; Fri, 18 Apr 2014 05:27:28 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.97.8 with SMTP id l8ls1513503qge.27.gmail; Fri, 18 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.52.144.42 with SMTP id sj10mr10764451vdb.19.1397824047847; Fri, 18 Apr 2014 05:27:27 -0700 (PDT) Received: from mail-ve0-f173.google.com (mail-ve0-f173.google.com [209.85.128.173]) by mx.google.com with ESMTPS id ph6si4942634veb.161.2014.04.18.05.27.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 18 Apr 2014 05:27:27 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.173 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.173; Received: by mail-ve0-f173.google.com with SMTP id oy12so2750146veb.18 for ; Fri, 18 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.52.175.166 with SMTP id cb6mr11798714vdc.1.1397824047713; Fri, 18 Apr 2014 05:27:27 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp108764vcb; Fri, 18 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.229.179.65 with SMTP id bp1mr18194435qcb.11.1397824046896; Fri, 18 Apr 2014 05:27:26 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id e61si11923198qgf.26.2014.04.18.05.27.25 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 18 Apr 2014 05:27:26 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of lng-odp-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1Wb7su-0004im-2k; Fri, 18 Apr 2014 12:27:12 +0000 Received: from mail-lb0-f172.google.com ([209.85.217.172]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1Wb7sn-0004ih-Pc for lng-odp@lists.linaro.org; Fri, 18 Apr 2014 12:27:06 +0000 Received: by mail-lb0-f172.google.com with SMTP id c11so1339547lbj.3 for ; Fri, 18 Apr 2014 05:27:13 -0700 (PDT) X-Received: by 10.152.42.164 with SMTP id p4mr13870957lal.5.1397824032889; Fri, 18 Apr 2014 05:27:12 -0700 (PDT) Received: from maxim-lap.localhost.onion ([92.39.133.154]) by mx.google.com with ESMTPSA id q4sm27257707lbl.14.2014.04.18.05.27.11 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 18 Apr 2014 05:27:12 -0700 (PDT) From: Maxim Uvarov To: lng-odp@lists.linaro.org Date: Fri, 18 Apr 2014 16:27:08 +0400 Message-Id: <1397824028-22186-1-git-send-email-maxim.uvarov@linaro.org> X-Mailer: git-send-email 1.8.5.1.163.gd7aced9 Subject: [lng-odp] [PATCH 1/2] patch libpcap for odp X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: maxim.uvarov@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.173 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 From: Vincent Hsu Signed-off-by: Vincent Hsu --- ODP Libpcap example was moved to new git repo: https://git.linaro.org/lng/odp-apps.git I think it's reasonable to have this patch revied in mailing list also, so sending it now. Best regards, Maxim. Makefile.in | 15 ++- config.h.in | 3 + configure | 90 ++++++++++++++ configure.in | 63 ++++++++++ inet.c | 10 ++ pcap-int.h | 22 ++++ pcap-linux.c | 374 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- pcap.c | 83 ++++++++++++- 8 files changed, 652 insertions(+), 8 deletions(-) diff --git a/Makefile.in b/Makefile.in index 47f5a06..ec2acd8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -48,8 +48,11 @@ AR = @AR@ LN_S = @LN_S@ MKDEP = @MKDEP@ CCOPT = @V_CCOPT@ -INCLS = -I. @V_INCLS@ +INCLS = -I. @V_INCLS@ @ODP_INCLS@ DEFS = @DEFS@ @V_DEFS@ +ifeq ($(ODP_HAVE_NETMAP),yes) +DEFS += -DODP_HAVE_NETMAP +endif ADDLOBJS = @ADDLOBJS@ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ LIBS = @LIBS@ @@ -359,8 +362,11 @@ all: libpcap.a shared pcap-config libpcap.a: $(OBJ) @rm -f $@ - $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) - $(RANLIB) $@ + if [ -n "@ODP_LIB@" ] ; then $(AR) x @ODP_LIB@ ; fi + ODP_OBJS=`$(AR) t @ODP_LIB@`; \ + $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) $$ODP_OBJS; \ + $(RANLIB) $@; \ + if [ -n "@ODP_LIB@" ] ; then rm $$ODP_OBJS ; fi shared: libpcap.$(DYEXT) @@ -369,7 +375,7 @@ libpcap.so: $(OBJ) VER=`cat $(srcdir)/VERSION`; \ MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ @V_SHLIB_CMD@ @V_SHLIB_OPT@ @V_SONAME_OPT@$@.$$MAJOR_VER $(LDFLAGS) \ - -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) + -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) @ODP_LIB@ # # The following rule succeeds, but the result is untested. @@ -624,6 +630,7 @@ install-shared-so: libpcap.so $(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so + ln -sf libpcap.so $(DESTDIR)$(libdir)/libpcap.so.0.8 install-shared-dylib: libpcap.dylib [ -d $(DESTDIR)$(libdir) ] || \ (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) diff --git a/config.h.in b/config.h.in index c6bc68e..be3175d 100644 --- a/config.h.in +++ b/config.h.in @@ -253,6 +253,9 @@ /* /dev/dlpi directory */ #undef PCAP_DEV_PREFIX +/* target host supports odp */ +#undef PCAP_SUPPORT_ODP + /* target host supports Bluetooth sniffing */ #undef PCAP_SUPPORT_BT diff --git a/configure b/configure index 07c2d33..34c2d84 100755 --- a/configure +++ b/configure @@ -658,6 +658,9 @@ AR RANLIB V_YACC V_LEX +PCAP_SUPPORT_ODP +ODP_LIB +ODP_INCLS HAVE_LINUX_TPACKET_AUXDATA LIBOBJS EGREP @@ -733,6 +736,9 @@ with_libnl enable_ipv6 enable_optimizer_dbg enable_yydebug +with_odp +with_odp_includes +with_odp_libraries with_dag with_dag_includes with_dag_libraries @@ -1396,6 +1402,11 @@ Optional Packages: --with-pcap=TYPE use packet capture TYPE --without-libnl disable libnl support [default=yes, on Linux, if present] + --with-odp[=DIR] include ODP support ["yes", "no" or DIR; + default="yes" on Linux if present] + --with-odp-includes=DIR ODP include directory + --with-odp-libraries=DIR + ODP library directory --with-dag[=DIR] include Endace DAG support ["yes", "no" or DIR; default="yes" on BSD and Linux if present] --with-dag-includes=DIR Endace DAG include directory @@ -6079,6 +6090,85 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${enable_yydebug-no}" >&5 $as_echo "${enable_yydebug-no}" >&6; } +# Check for ODP support. + +# Check whether --with-odp was given. +if test "${with_odp+set}" = set; then : + withval=$with_odp; + if test "$withval" = no + then + # User doesn't want ODP support. + want_odp=no + elif test "$withval" = yes + then + # User wants ODP support but hasn't specified a directory. + want_odp=yes + ODP_ROOT=../../.. + else + # User wants ODP support and has specified a directory, so use the provided value. + want_odp=yes + ODP_ROOT=$withval + fi + +else + + # + # Use ODP API if present, otherwise don't + # + want_odp=ifpresent + +fi + + + +# Check whether --with-odp-includes was given. +if test "${with_odp_includes+set}" = set; then : + withval=$with_odp_includes; + # User wants odp support and has specified a header directory, so use the provided value. + want_odp=yes + ODP_INCLS=$withval + +fi + + + +# Check whether --with-odp-libraries was given. +if test "${with_odp_libraries+set}" = set; then : + withval=$with_odp_libraries; + # User wants odp support and has specified a library directory, so use the provided value. + want_odp=yes + ODP_LIB=$withval + +fi + + +if test "$want_odp" = yes; then + +$as_echo "#define PCAP_SUPPORT_ODP 1" >>confdefs.h + + + # If necessary, set default paths for ODP API headers and libraries. + if test -z "$ODP_ROOT"; then + ODP_ROOT="../../.." + fi + + if test -z "$ODP_INCLS"; then + ODP_INCLS="-I$ODP_ROOT/build/include" + fi + + if test -z "$ODP_LIB"; then + ODP_LIB="$ODP_ROOT/build/lib/libodp.a" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: ODP is supported" >&5 +$as_echo "$as_me: ODP is supported" >&6;} + + + + + +fi + # Check for Endace DAG card support. # Check whether --with-dag was given. diff --git a/configure.in b/configure.in index 42cbe9b..96e8331 100644 --- a/configure.in +++ b/configure.in @@ -697,6 +697,69 @@ if test "$enable_yydebug" = "yes"; then fi AC_MSG_RESULT(${enable_yydebug-no}) +# Check for ODP support. +AC_ARG_WITH([odp], +AC_HELP_STRING([--with-odp@<:@=DIR@:>@],[include ODP support @<:@"yes", "no" or DIR; default="yes" on Linux if present@:>@]), +[ + if test "$withval" = no + then + # User doesn't want ODP support. + want_odp=no + elif test "$withval" = yes + then + # User wants ODP support but hasn't specified a directory. + want_odp=yes + ODP_ROOT=../../.. + else + # User wants ODP support and has specified a directory, so use the provided value. + want_odp=yes + ODP_ROOT=$withval + fi +],[ + # + # Use ODP API if present, otherwise don't + # + want_odp=ifpresent +]) + +AC_ARG_WITH([odp-includes], +AC_HELP_STRING([--with-odp-includes=DIR],[ODP include directory]), +[ + # User wants odp support and has specified a header directory, so use the provided value. + want_odp=yes + ODP_INCLS=$withval +],[]) + +AC_ARG_WITH([odp-libraries], +AC_HELP_STRING([--with-odp-libraries=DIR],[ODP library directory]), +[ + # User wants odp support and has specified a library directory, so use the provided value. + want_odp=yes + ODP_LIB=$withval +],[]) + +if test "$want_odp" = yes; then + AC_DEFINE(PCAP_SUPPORT_ODP, 1, [target host supports odp]) + + # If necessary, set default paths for ODP API headers and libraries. + if test -z "$ODP_ROOT"; then + ODP_ROOT="../../.." + fi + + if test -z "$ODP_INCLS"; then + ODP_INCLS="-I$ODP_ROOT/build/include" + fi + + if test -z "$ODP_LIB"; then + ODP_LIB="$ODP_ROOT/build/lib/libodp.a" + fi + + AC_MSG_NOTICE(ODP is supported) + AC_SUBST(ODP_INCLS) + AC_SUBST(ODP_LIB) + AC_SUBST(PCAP_SUPPORT_ODP) +fi + # Check for Endace DAG card support. AC_ARG_WITH([dag], AC_HELP_STRING([--with-dag@<:@=DIR@:>@],[include Endace DAG support @<:@"yes", "no" or DIR; default="yes" on BSD and Linux if present@:>@]), diff --git a/inet.c b/inet.c index c699658..beacc4e 100644 --- a/inet.c +++ b/inet.c @@ -865,12 +865,22 @@ pcap_lookupnet(device, netp, maskp, errbuf) register struct sockaddr_in *sin4; struct ifreq ifr; +#ifdef PCAP_SUPPORT_ODP + if (!strncmp(device, "odp:", 4)) + device += 4; + else if (!strncmp(device, "netmap:", 7)) + device += 7; +#endif /* PCAP_SUPPORT_ODP */ + /* * The pseudo-device "any" listens on all interfaces and therefore * has the network address and -mask "0.0.0.0" therefore catching * all traffic. Using NULL for the interface is the same as "any". */ if (!device || strcmp(device, "any") == 0 +#ifdef PCAP_SUPPORT_ODP + || !strncmp(device, "vale", 4) +#endif /* PCAP_SUPPORT_ODP */ #ifdef HAVE_DAG_API || strstr(device, "dag") != NULL #endif diff --git a/pcap-int.h b/pcap-int.h index 6d6febe..ca86c8d 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -40,6 +40,13 @@ extern "C" { #endif +#ifdef PCAP_SUPPORT_ODP +#include +#include +#include +#include +#endif /* PCAP_SUPPORT_ODP */ + #ifdef WIN32 #include extern CRITICAL_SECTION g_PcapCompileCriticalSection; @@ -83,6 +90,9 @@ extern CRITICAL_SECTION g_PcapCompileCriticalSection; #endif /* _MSC_VER */ struct pcap_opt { +#ifdef PCAP_SUPPORT_ODP + char *destination; +#endif char *source; int timeout; /* timeout for buffering */ int buffer_size; @@ -223,6 +233,13 @@ struct pcap { getadapter_op_t getadapter_op; #endif cleanup_op_t cleanup_op; + +#ifdef PCAP_SUPPORT_ODP + odp_pktio_t pktio; + odp_pktio_t pktio_second; + bool is_bridge; + bool is_netmap; +#endif /* PCAP_SUPPORT_ODP */ }; /* @@ -423,6 +440,11 @@ int install_bpf_program(pcap_t *, struct bpf_program *); int pcap_strcasecmp(const char *, const char *); +#ifdef PCAP_SUPPORT_ODP +pcap_t* odp_create(const char *, char *, int *); +pcap_t *pcap_create_bridge(const char *, char *, size_t); +#endif + #ifdef __cplusplus } #endif diff --git a/pcap-linux.c b/pcap-linux.c index a15a8b1..be0ef20 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -138,6 +138,17 @@ #include #include +#ifdef PCAP_SUPPORT_ODP +#include +#define SHM_PKT_POOL_SIZE (512*2048) +#define SHM_PKT_POOL_BUF_SIZE 1856 +#endif /* PCAP_SUPPORT_ODP */ + +#ifdef ODP_HAVE_NETMAP +#include +#include +#endif + #include "pcap-int.h" #include "pcap/sll.h" #include "pcap/vlan.h" @@ -333,6 +344,12 @@ static int pcap_setfilter_linux(pcap_t *, struct bpf_program *); static int pcap_setdirection_linux(pcap_t *, pcap_direction_t); static int pcap_set_datalink_linux(pcap_t *, int); static void pcap_cleanup_linux(pcap_t *); +#ifdef PCAP_SUPPORT_ODP +static void pcap_odp_init(pcap_t *); +static int pcap_activate_odp(pcap_t *); +static int pcap_read_odp(pcap_t *, int, pcap_handler, u_char *); +static void pcap_cleanup_odp(pcap_t *); +#endif union thdr { struct tpacket_hdr *h1; @@ -1050,7 +1067,6 @@ linux_if_drops(const char * if_name) return dropped_pkts; } - /* * With older kernels promiscuous mode is kind of interesting because we * have to reset the interface before exiting. The problem can't really @@ -1375,7 +1391,7 @@ pcap_activate_linux(pcap_t *handle) * "handle->fd" is a socket, so "select()" and "poll()" * should work on it. */ - handle->selectable_fd = handle->fd; + handle->selectable_fd = -1; return status; @@ -2399,6 +2415,11 @@ pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter, } } +#ifdef PCAP_SUPPORT_ODP + /* ODP not yet support filtering_in_kernel */ + can_filter_in_kernel = 0; +#endif + /* * NOTE: at this point, we've set both the "len" and "filter" * fields of "fcode". As of the 2.6.32.4 kernel, at least, @@ -6056,3 +6077,352 @@ reset_kernel_filter(pcap_t *handle) &dummy, sizeof(dummy)); } #endif + +#ifdef PCAP_SUPPORT_ODP +pcap_t * +odp_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *handle; + + *is_ours = (!strncmp(device, "odp:", 4) + || !strncmp(device, "b:", 2) + || !strncmp(device, "netmapb:", 8) + || !strncmp(device, "netmap:", 7) + || !strncmp(device, "vale", 4)); + if (! *is_ours) + return NULL; + if (!strncmp(device, "odp:", 4)) { + handle = pcap_create_common((device + 4), ebuf, sizeof(struct pcap_linux)); + handle->is_bridge = false; + handle->is_netmap = false; + } else if (!strncmp(device, "b:", 2)) { + handle = pcap_create_common((device + 2), ebuf, sizeof(struct pcap_linux)); + handle->is_bridge = true; + handle->is_netmap = false; + printf("bridge src: %s, dest: %s\n", + handle->opt.source, handle->opt.destination); +#ifdef ODP_HAVE_NETMAP + } else if (!strncmp(device, "netmap:", 7)) { + handle = pcap_create_common((device + 7), ebuf, sizeof(struct pcap_linux)); + handle->is_bridge = false; + handle->is_netmap = true; + } else if (!strncmp(device, "netmapb:", 8)) { + handle = pcap_create_common((device + 8), ebuf, sizeof(struct pcap_linux)); + handle->is_bridge = true; + handle->is_netmap = true; + printf("bridge src: %s, dest: %s\n", + handle->opt.source, handle->opt.destination); +#endif + } else { + handle = pcap_create_common(device, ebuf, sizeof(struct pcap_linux)); + handle->is_bridge = false; + handle->is_netmap = false; + } + if (handle == NULL) + return NULL; + + handle->activate_op = pcap_activate_odp; + return (handle); +} + +static void +pcap_odp_init(pcap_t *handle) +{ + int thr_id; + odp_buffer_pool_t pool; + odp_pktio_t pktio; + void *pool_base; + char inq_name[ODP_QUEUE_NAME_LEN]; + odp_queue_t inq_def; + odp_queue_param_t qparam; + int fd; + int ret; + + /* Init ODP before calling anything else */ + if (odp_init_global()) { + fprintf(stderr, "Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Create thread structure for ODP */ + thr_id = odp_thread_create(0); + odp_init_local(thr_id); + + /* Is pool have been created in another theard ? */ + pool = odp_buffer_pool_lookup("packet_pool"); + if (pool == ODP_BUFFER_POOL_INVALID) { + /* Create packet pool */ + pool_base = odp_shm_reserve("shm_packet_pool", + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); + if (pool_base == NULL) { + fprintf(stderr, + "Error: packet pool mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + + pool = odp_buffer_pool_create("packet_pool", pool_base, + SHM_PKT_POOL_SIZE, + SHM_PKT_POOL_BUF_SIZE, + ODP_CACHE_LINE_SIZE, + ODP_BUFFER_TYPE_PACKET); + if (pool == ODP_BUFFER_POOL_INVALID) { + fprintf(stderr, "Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + odp_buffer_pool_print(pool); + } else { + fprintf(stdout, "packet pool have been created.\n"); + } + + /* Open a packet IO instance for this thread */ + /* if any device, need ODP support */ + + /* for netmap */ + odp_pktio_params_t pparams; +#ifdef ODP_HAVE_NETMAP + if (handle->is_netmap) { + memset(&pparams.nm_params, 0, sizeof(pparams.nm_params)); + pparams.nm_params.type = ODP_PKTIO_TYPE_NETMAP; + pparams.nm_params.netmap_mode = ODP_NETMAP_MODE_HW; + pparams.nm_params.ringid = 0; + printf(" pktio type: netmap\n"); + } else { +#endif + memset(&pparams.sock_params, 0, sizeof(pparams.sock_params)); + pparams.sock_params.type = ODP_PKTIO_TYPE_SOCKET; + printf(" pktio type: socket\n"); +#ifdef ODP_HAVE_NETMAP + } +#endif + handle->pktio = odp_pktio_open(handle->opt.source, pool, &pparams); + + if (handle->pktio == ODP_QUEUE_INVALID) { + fprintf(stderr, " Error: pktio create failed %s\n", handle->opt.source); + return; + } + + /* + * Create and set the default INPUT queue associated with the 'pktio' + * resource + */ + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; + qparam.sched.sync = ODP_SCHED_SYNC_NONE; + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", + (int)handle->pktio); + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; + + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); + if (inq_def == ODP_QUEUE_INVALID) { + fprintf(stderr, " Error: pktio queue creation failed\n"); + return; + } + + ret = odp_pktio_inq_setdef(handle->pktio, inq_def); + if (ret != 0) { + fprintf(stderr, " Error: default input-Q setup\n"); + return; + } + + printf(" created pktio:%02i, queue mode\n" + " default pktio%02i-INPUT queue:%u\n", + handle->pktio, handle->pktio, inq_def); + + /* for bridge */ + if (handle->is_bridge) { + handle->pktio_second = odp_pktio_open(handle->opt.destination, pool, &pparams); + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)handle->pktio_second); + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; + + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); + if (inq_def == ODP_QUEUE_INVALID) { + fprintf(stderr, " Error: pktio queue creation failed\n"); + return; + } + + ret = odp_pktio_inq_setdef(handle->pktio_second, inq_def); + if (ret != 0) { + fprintf(stderr, " Error: default input-Q setup\n"); + return; + } + + printf(" created pktio:%02i, queue mode\n" + " default pktio%02i-INPUT queue:%u\n", + handle->pktio_second, handle->pktio_second, inq_def); + } +} + +static int +pcap_activate_odp(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + const char *device; + int status = 0; + int arptype; + struct ifreq ifr; + + /* initial ODP stuff */ + pcap_odp_init(handle); + + device = handle->opt.source; + + handle->inject_op = pcap_inject_linux; + handle->setdirection_op = pcap_setdirection_linux; + handle->set_datalink_op = pcap_set_datalink_linux; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->cleanup_op = pcap_cleanup_odp; + handle->read_op = pcap_read_odp; + handle->setfilter_op = pcap_setfilter_linux; + handle->stats_op = pcap_stats_linux; + + /* + * The "any" device is a special device which causes us not + * to bind to a particular device and thus to look at all + * devices. + */ + if (strcmp(device, "any") == 0) { + if (handle->opt.promisc) { + handle->opt.promisc = 0; + /* Just a warning. */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Promiscuous mode not supported on the \"any\" device"); + status = PCAP_WARNING_PROMISC_NOTSUP; + } + } + + handlep->device = strdup(device); + if (handlep->device == NULL) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", + pcap_strerror(errno)); + return PCAP_ERROR; + } + + /* copy timeout value */ + handlep->timeout = handle->opt.timeout; + + /* + * If we're in promiscuous mode, then we probably want + * to see when the interface drops packets too, so get an + * initial count from /proc/net/dev + */ + if (handle->opt.promisc) + handlep->proc_dropped = linux_if_drops(handlep->device); + + /* + activate_new */ + /* Will create a sock_fd just for setting */ + status = activate_new(handle); + if (status < 0) + goto fail; + + /* Allocate the buffer */ + status = 0; + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, + &handle->opt.buffer_size, + sizeof(handle->opt.buffer_size)) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "SO_RCVBUF: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto fail; + } + } + + handle->buffer = malloc(handle->bufsize + handle->offset); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + status = PCAP_ERROR; + goto fail; + } + + handle->selectable_fd = handle->fd; + /* - activate_new */ + + return status; + +fail: + pcap_cleanup_linux(handle); + return status; +} + +static int +pcap_read_odp(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *userdata) +{ + odp_packet_t pkt; + odp_buffer_t buf; + u_char *bp; + struct pcap_linux *handlep = handle->priv; + struct pcap_pkthdr pcap_header; + struct timeval ts; + long n = 1; + + for (n = 1; (n <= max_packets) || (max_packets < 0); n++) { + /* Use schedule to get buf from any input queue */ + buf = odp_schedule(NULL); + /* fill out pcap_header */ + gettimeofday(&ts, NULL); + pcap_header.ts = ts; + + pkt = odp_packet_from_buffer(buf); + bp = odp_packet_l2(pkt); + pcap_header.len = odp_packet_get_len(pkt); + pcap_header.caplen = pcap_header.len; + + /* ODP not yet support filtering_in_kernel */ + if (handlep->filter_in_userland && handle->fcode.bf_insns) { + if (bpf_filter(handle->fcode.bf_insns, bp, + pcap_header.len, + pcap_header.caplen) == 0) { + /* rejected by filter */ + n--; + goto clean_buf; + } + } + + callback(userdata, &pcap_header, bp); + + /* for bridge */ + if (handle->is_bridge) { + odp_pktio_t pktio_tmp; + odp_queue_t outq; + pktio_tmp = odp_pktio_get_input(pkt); + printf("ODP: from pktio %d\n", pktio_tmp); + if (pktio_tmp == handle->pktio) { + printf("ODP: to pktio %d\n", handle->pktio_second); + outq = odp_pktio_outq_getdef(handle->pktio_second); + } else if (pktio_tmp == handle->pktio_second) { + printf("ODP: to pktio %d\n", handle->pktio); + outq = odp_pktio_outq_getdef(handle->pktio); + } else { + printf("ODP: Unknown pktio\n"); + goto clean_buf; + } + odp_queue_enq(outq, buf); + } +clean_buf: + handlep->packets_read++; + odp_buffer_free(buf); + + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + + return max_packets; +} + +static void +pcap_cleanup_odp(pcap_t *handle) +{ + odp_pktio_close(handle->pktio); + if (handle->is_bridge) + odp_pktio_close(handle->pktio_second); + pcap_cleanup_linux(handle); +} +#endif /* PCAP_SUPPORT_ODP */ diff --git a/pcap.c b/pcap.c index b2b5da6..242cb6a 100644 --- a/pcap.c +++ b/pcap.c @@ -307,6 +307,9 @@ struct capture_source_type { int (*findalldevs_op)(pcap_if_t **, char *); pcap_t *(*create_op)(const char *, char *, int *); } capture_source_types[] = { +#ifdef PCAP_SUPPORT_ODP + { NULL, odp_create }, +#endif #ifdef HAVE_DAG_API { dag_findalldevs, dag_create }, #endif @@ -527,9 +530,84 @@ pcap_create_common(const char *source, char *ebuf, size_t size) if (p == NULL) return (NULL); - p->opt.source = strdup(source); +#ifdef PCAP_SUPPORT_ODP + if (strstr(source, ",")) { + char *delim = ","; + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + + p->opt.source = strdup(strtok((char *) source, delim)); + if (p->opt.source == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + p->opt.destination = strdup(strtok(NULL, delim)); + if (p->opt.destination == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + } else { +#endif + p->opt.source = strdup(source); + if (p->opt.source == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } +#ifdef PCAP_SUPPORT_ODP + } +#endif + + /* + * Default to "can't set rfmon mode"; if it's supported by + * a platform, the create routine that called us can set + * the op to its routine to check whether a particular + * device supports it. + */ + p->can_set_rfmon_op = pcap_cant_set_rfmon; + + initialize_ops(p); + + /* put in some defaults*/ + pcap_set_snaplen(p, 65535); /* max packet size */ + p->opt.timeout = 0; /* no timeout specified */ + p->opt.buffer_size = 0; /* use the platform's default */ + p->opt.promisc = 0; + p->opt.rfmon = 0; + p->opt.immediate = 0; + p->opt.tstamp_type = -1; /* default to not setting time stamp type */ + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + return (p); +} + +#ifdef PCAP_SUPPORT_ODP +pcap_t * +pcap_create_bridge(const char *device, char *ebuf, size_t size) +{ + pcap_t *p; + char *delim = ","; + + p = pcap_alloc_pcap_t(ebuf, size); + if (p == NULL) + return (NULL); + + p->opt.source = strdup(strtok((char *) device, delim)); if (p->opt.source == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + free(p); + return (NULL); + } + + p->opt.destination = strdup(strtok(NULL, delim)); + if (p->opt.destination == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(p); return (NULL); @@ -541,7 +619,7 @@ pcap_create_common(const char *source, char *ebuf, size_t size) * the op to its routine to check whether a particular * device supports it. */ - p->can_set_rfmon_op = pcap_cant_set_rfmon; + p->can_set_rfmon_op = 0; initialize_ops(p); @@ -556,6 +634,7 @@ pcap_create_common(const char *source, char *ebuf, size_t size) p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; return (p); } +#endif /* PCAP_SUPPORT_ODP */ int pcap_check_activated(pcap_t *p)