Re: [PATCH] DPDK DAQ Module

"Ed Borgoyn (eborgoyn)" <[email protected]>
Newsgroups gmane.comp.security.ids.snort.devel
Message-ID <D387FB08.45BB3%[email protected]>
Thank you for your effort and contribution to the Snort DAQ code-base.

On 6/16/16, 2:37 AM, "Tiwei Bie" <[email protected]> wrote:

>Hello everyone,
>
>We have implemented the DPDK DAQ Module for daq, below is the patch
>which is generated against daq-2.0.6:
>
> configure.ac                        |  30 ++
> os-daq-modules/Makefile.am          |  12 +
> os-daq-modules/daq_dpdk.c           | 833
>++++++++++++++++++++++++++++++++++++
> os-daq-modules/daq_static_modules.c |   3 +
> os-daq-modules/daq_static_modules.h |   3 +
> 5 files changed, 881 insertions(+)
> create mode 100644 os-daq-modules/daq_dpdk.c
>
>diff --git a/configure.ac b/configure.ac
>index 4246ad4..cd0309d 100644
>--- a/configure.ac
>+++ b/configure.ac
>@@ -102,6 +102,22 @@ if test "x$with_netmap_includes" != "xno"; then
>     CPPFLAGS="${CPPFLAGS} -I${with_netmap_includes}"
> fi
> 
>+AC_ARG_WITH(dpdk_includes,
>+            [  --with-dpdk-includes=DIR    dpdk include directory],
>+            [with_dpdk_includes="$withval"], [with_dpdk_includes="no"])
>+
>+if test "x$with_dpdk_includes" != "xno"; then
>+    CPPFLAGS="${CPPFLAGS} -I${with_dpdk_includes}"
>+fi
>+
>+AC_ARG_WITH(dpdk_libraries,
>+            [  --with-dpdk-libraries=DIR    dpdk library directory],
>+            [with_dpdk_libraries="$withval"], [with_dpdk_libraries="no"])
>+
>+if test "x$with_dpdk_libraries" != "xno"; then
>+    DPDK_LDFLAGS="-L${with_dpdk_libraries}"
>+fi
>+
> DEFAULT_ENABLE=yes
> 
> # Modules configuration
>@@ -128,6 +144,19 @@ if test "$enable_afpacket_module" = yes; then
> fi
> AM_CONDITIONAL([BUILD_AFPACKET_MODULE], [test "$enable_afpacket_module"
>= yes])
> 
>+# DPDK Module
>+AC_ARG_ENABLE(dpdk-module,
>+              AC_HELP_STRING([--disable-dpdk-module],[don't build the
>bundled dpdk module]),
>+              [enable_dpdk_module="$enableval"],
>[enable_dpdk_module="$DEFAULT_ENABLE"])
>+if test "$enable_dpdk_module" = yes; then
>+    AC_CHECK_HEADER([rte_config.h], [], [enable_dpdk_module=no])
>+    if test "$enable_dpdk_module" = yes; then
>+        STATIC_LIBS="${STATIC_LIBS} -lsfbpf ${DPDK_LDFLAGS} -ldpdk
>-lpthread"
>+        CFLAGS="${CFLAGS} -std=gnu99 -Wno-pedantic"
>+    fi
>+fi
>+AM_CONDITIONAL([BUILD_DPDK_MODULE], [test "$enable_dpdk_module" = yes])
>+
> # Dump Module
> AC_ARG_ENABLE(dump-module,
>               AC_HELP_STRING([--disable-dump-module],[don't build the
>bundled Dump module]),
>@@ -301,6 +330,7 @@ AC_OUTPUT
> 
> echo
> echo "Build AFPacket DAQ module.. : $enable_afpacket_module"
>+echo "Build DPDK DAQ module...... : $enable_dpdk_module"
> echo "Build Dump DAQ module...... : $enable_dump_module"
> echo "Build IPFW DAQ module...... : $enable_ipfw_module"
> echo "Build IPQ DAQ module....... : $enable_ipq_module"
>diff --git a/os-daq-modules/Makefile.am b/os-daq-modules/Makefile.am
>index 625ba4c..23ca3b8 100644
>--- a/os-daq-modules/Makefile.am
>+++ b/os-daq-modules/Makefile.am
>@@ -38,6 +38,18 @@ endif
>     libdaq_static_modules_la_CFLAGS += -DBUILD_PCAP_MODULE
> endif
> 
>+if BUILD_DPDK_MODULE
>+if BUILD_SHARED_MODULES
>+    pkglib_LTLIBRARIES += daq_dpdk.la
>+    daq_dpdk_la_SOURCES = daq_dpdk.c
>+    daq_dpdk_la_CFLAGS = -DBUILDING_SO -msse4
>+    daq_dpdk_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
>@XCCFLAGS@
>+    daq_dpdk_la_LIBADD = $(top_builddir)/sfbpf/libsfbpf.la
>+endif
>+    libdaq_static_modules_la_SOURCES += daq_dpdk.c
>+    libdaq_static_modules_la_CFLAGS += -DBUILD_DPDK_MODULE -msse4
>+endif
>+
> if BUILD_DUMP_MODULE
> if BUILD_SHARED_MODULES
>     pkglib_LTLIBRARIES += daq_dump.la
>diff --git a/os-daq-modules/daq_dpdk.c b/os-daq-modules/daq_dpdk.c
>new file mode 100644
>index 0000000..c080256
>--- /dev/null
>+++ b/os-daq-modules/daq_dpdk.c
>@@ -0,0 +1,833 @@
>+/*
>+** Copyright (C) 2016
>+**     University of Science and Technology of China.  All rights
>reserved.
>+** Author: Tiwei Bie <[email protected]>
>+**         Jiaxin Liu <[email protected]>
>+**
>+** This program is free software; you can redistribute it and/or modify
>+** it under the terms of the GNU General Public License Version 2 as
>+** published by the Free Software Foundation.  You may not use, modify or
>+** distribute this program under any other version of the GNU General
>+** Public License.
>+**
>+** This program 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 this program; if not, write to the Free Software
>+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
>USA.
>+*/
>+
>+#ifdef HAVE_CONFIG_H
>+#include "config.h"
>+#endif
>+
>+#include <errno.h>
>+#include <getopt.h>
>+#include <net/if.h>
>+#include <stdio.h>
>+#include <stdlib.h>
>+#include <string.h>
>+
>+#include <daq_api.h>
>+#include <sfbpf.h>
>+#include <sfbpf_dlt.h>
>+
>+#include <rte_config.h>
>+#include <rte_eal.h>
>+#include <rte_ethdev.h>
>+
>+#define DAQ_DPDK_VERSION 2
>+
>+#define NUM_MBUFS 8191
>+#define MBUF_CACHE_SIZE 250
>+#define BURST_SIZE 32
>+
>+#define MAX_ARGS 64
>+
>+#define RX_RING_NUM 1
>+#define TX_RING_NUM 1
>+
>+#define RX_RING_SIZE 128
>+#define TX_RING_SIZE 512
>+
>+static const struct rte_eth_conf port_conf_default = {
>+    .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
>+};
>+
>+typedef struct _dpdk_instance
>+{
>+    struct _dpdk_instance *next;
>+    struct _dpdk_instance *peer;
>+#define DPDKINST_STARTED	0x1
>+    uint32_t flags;
>+    int rx_rings;
>+    int tx_rings;
>+    int port;
>+    int index;
>+    int tx_start;
>+    int tx_end;
>+    struct rte_mempool *mbuf_pool;
>+    struct rte_mbuf *tx_burst[BURST_SIZE * RX_RING_NUM];
>+} DpdkInstance;
>+
>+typedef struct _dpdk_context
>+{
>+    char *device;
>+    char *filter;
>+    int snaplen;
>+    int timeout;
>+    int debug;
>+    DpdkInstance *instances;
>+    int intf_count;
>+    struct sfbpf_program fcode;
>+    volatile int break_loop;
>+    int promisc_flag;
>+    DAQ_Stats_t stats;
>+    DAQ_State state;
>+    char errbuf[256];
>+} Dpdk_Context_t;
>+
>+static void dpdk_daq_reset_stats(void *handle);
>+
>+static int start_instance(Dpdk_Context_t *dpdkc, DpdkInstance *instance)
>+{
>+    int rx_rings = RX_RING_NUM, tx_rings = TX_RING_NUM;
>+    struct rte_eth_conf port_conf = port_conf_default;
>+    int port, queue, ret;
>+
>+    port = instance->port;
>+
>+    ret = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
>+    if (ret != 0)
>+    {
>+        DPE(dpdkc->errbuf, "%s: Couldn't configure port %d\n",
>__FUNCTION__, port);
>+        return DAQ_ERROR;
>+    }
>+
>+    instance->rx_rings = rx_rings;
>+    instance->tx_rings = tx_rings;
>+
>+    for (queue = 0; queue < rx_rings; queue++)
>+    {
>+        ret = rte_eth_rx_queue_setup(port, queue, RX_RING_SIZE,
>+                rte_eth_dev_socket_id(port),
>+                NULL, instance->mbuf_pool);
>+        if (ret != 0)
>+        {
>+            DPE(dpdkc->errbuf, "%s: Couldn't setup rx queue %d for port
>%d\n", __FUNCTION__, queue, port);
>+            return DAQ_ERROR;
>+        }
>+    }
>+
>+    for (queue = 0; queue < tx_rings; queue++)
>+    {
>+        ret = rte_eth_tx_queue_setup(port, queue, TX_RING_SIZE,
>+                rte_eth_dev_socket_id(port),
>+                NULL);
>+        if (ret != 0)
>+        {
>+            DPE(dpdkc->errbuf, "%s: Couldn't setup tx queue %d for port
>%d\n", __FUNCTION__, queue, port);
>+            return DAQ_ERROR;
>+        }
>+    }
>+
>+    ret = rte_eth_dev_start(instance->port);
>+    if (ret != 0)
>+    {
>+        DPE(dpdkc->errbuf, "%s: Couldn't start device for port %d\n",
>__FUNCTION__, port);
>+        return DAQ_ERROR;
>+    }
>+
>+    instance->flags |= DPDKINST_STARTED;
>+
>+    if (dpdkc->promisc_flag)
>+        rte_eth_promiscuous_enable(instance->port);
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static void destroy_instance(DpdkInstance *instance)
>+{
>+    int i;
>+
>+    if (instance)
>+    {
>+        if (instance->flags & DPDKINST_STARTED)
>+        {
>+            for (i = instance->tx_start; i < instance->tx_end; i++)
>+                rte_pktmbuf_free(instance->tx_burst[i]);
>+
>+            rte_eth_dev_stop(instance->port);
>+            instance->flags &= ~DPDKINST_STARTED;
>+        }
>+
>+        free(instance);
>+    }
>+}
>+
>+static DpdkInstance *create_instance(const char *device, DpdkInstance
>*parent, char *errbuf, size_t errlen)
>+{
>+    DpdkInstance *instance;
>+    int port;
>+    char poolname[64];
>+    static int index = 0;
>+
>+    instance = calloc(1, sizeof(DpdkInstance));
>+    if (!instance)
>+    {
>+        snprintf(errbuf, errlen, "%s: Couldn't allocate a new instance
>structure.", __FUNCTION__);
>+        goto err;
>+    }
>+
>+    instance->index = index;
>+    index++;
>+
>+    if (strncmp(device, "dpdk", 4) != 0 || sscanf(&device[4], "%d",
>&port) != 1)
>+    {
>+        snprintf(errbuf, errlen, "%s: Invalid interface specification:
>'%s'!", __FUNCTION__, device);
>+        goto err;
>+    }
>+
>+    instance->port = port;
>+
>+    snprintf(poolname, sizeof(poolname), "MBUF_POOL%d", port);
>+    instance->mbuf_pool = rte_pktmbuf_pool_create(poolname, NUM_MBUFS,
>+                MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
>rte_socket_id());
>+    if (instance->mbuf_pool == NULL)
>+    {
>+        snprintf(errbuf, errlen, "%s: Couldn't create mbuf pool!\n",
>__FUNCTION__);
>+        goto err;
>+    }
>+
>+    return instance;
>+
>+err:
>+    destroy_instance(instance);
>+    return NULL;
>+}
>+
>+static int create_bridge(Dpdk_Context_t *dpdkc, const int port1, const
>int port2)
>+{
>+    DpdkInstance *instance, *peer1, *peer2;
>+
>+    peer1 = peer2 = NULL;
>+    for (instance = dpdkc->instances; instance; instance =
>instance->next)
>+    {
>+        if (instance->port == port1)
>+            peer1 = instance;
>+        else if (instance->port == port2)
>+            peer2 = instance;
>+    }
>+
>+    if (!peer1 || !peer2)
>+        return DAQ_ERROR_NODEV;
>+
>+    peer1->peer = peer2;
>+    peer2->peer = peer1;
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static int dpdk_close(Dpdk_Context_t *dpdkc)
>+{
>+    DpdkInstance *instance;
>+
>+    if (!dpdkc)
>+        return -1;
>+
>+    /* Free all of the device instances. */
>+    while ((instance = dpdkc->instances) != NULL)
>+    {
>+        dpdkc->instances = instance->next;
>+        destroy_instance(instance);
>+    }
>+
>+    sfbpf_freecode(&dpdkc->fcode);
>+
>+    dpdkc->state = DAQ_STATE_STOPPED;
>+
>+    return 0;
>+}
>+
>+static int parse_args(char *inputstring, char **argv)
>+{
>+    char **ap;
>+
>+    for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;)
>+    {
>+        if (**ap != '\0')
>+            if (++ap >= &argv[MAX_ARGS])
>+                break;
>+    }
>+    return ap - argv;
>+}
>+
>+static int dpdk_daq_initialize(const DAQ_Config_t *config, void
>**ctxt_ptr, char *errbuf, size_t errlen)
>+{
>+    Dpdk_Context_t *dpdkc;
>+    DpdkInstance *instance;
>+    DAQ_Dict *entry;
>+    char intf[IFNAMSIZ];
>+    int num_intfs = 0;
>+    int port1, port2, ports;
>+    size_t len;
>+    char *dev;
>+    int ret, rval = DAQ_ERROR;
>+    char *dpdk_args = NULL;
>+    char argv0[] = "fake";
>+    char *argv[MAX_ARGS + 1];
>+    int argc;
>+
>+    dpdkc = calloc(1, sizeof(Dpdk_Context_t));
>+    if (!dpdkc)
>+    {
>+        snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the
>new DPDK context!", __FUNCTION__);
>+        rval = DAQ_ERROR_NOMEM;
>+        goto err;
>+    }
>+
>+    dpdkc->device = strdup(config->name);
>+    if (!dpdkc->device)
>+    {
>+        snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the
>device string!", __FUNCTION__);
>+        rval = DAQ_ERROR_NOMEM;
>+        goto err;
>+    }
>+
>+    dpdkc->snaplen = config->snaplen;
>+    dpdkc->timeout = (config->timeout > 0) ? (int) config->timeout : -1;
>+    dpdkc->promisc_flag = (config->flags & DAQ_CFG_PROMISC);
>+
>+    /* Import the DPDK arguments */
>+    for (entry = config->values; entry; entry = entry->next)
>+    {
>+        if (!strcmp(entry->key, "dpdk_args"))
>+            dpdk_args = entry->value;
>+    }
>+
>+    if (!dpdk_args)
>+    {
>+        snprintf(errbuf, errlen, "%s: Missing EAL arguments!",
>__FUNCTION__);
>+        rval = DAQ_ERROR_INVAL;
>+        goto err;
>+    }
>+
>+    argv[0] = argv0;
>+    argc = parse_args(dpdk_args, &argv[1]) + 1;
>+    optind = 1;
>+
>+    ret = rte_eal_init(argc, argv);
>+    if (ret < 0)
>+    {
>+        snprintf(errbuf, errlen, "%s: Invalid EAL arguments!\n",
>__FUNCTION__);
>+        rval = DAQ_ERROR_INVAL;
>+        goto err;
>+    }
>+
>+    ports = rte_eth_dev_count();
>+    if (ports == 0)
>+    {
>+        snprintf(errbuf, errlen, "%s: No Ethernet ports!\n",
>__FUNCTION__);
>+        rval = DAQ_ERROR_NODEV;
>+        goto err;
>+    }
>+
>+    dev = dpdkc->device;
>+    if (*dev == ':' || ((len = strlen(dev)) > 0 && *(dev + len - 1) ==
>':') ||
>+            (config->mode == DAQ_MODE_PASSIVE && strstr(dev, "::")))
>+    {
>+        snprintf(errbuf, errlen, "%s: Invalid interface specification:
>'%s'!", __FUNCTION__, dpdkc->device);
>+        goto err;
>+    }
>+
>+    while (*dev != '\0')
>+    {
>+        len = strcspn(dev, ":");
>+        if (len >= sizeof(intf))
>+        {
>+            snprintf(errbuf, errlen, "%s: Interface name too long!
>(%zu)", __FUNCTION__, len);
>+            goto err;
>+        }
>+        if (len != 0)
>+        {
>+            dpdkc->intf_count++;
>+            if (dpdkc->intf_count > ports)
>+            {
>+                snprintf(errbuf, errlen, "%s: Using more than %d
>interfaces is not valid!",
>+                         __FUNCTION__, ports);
>+                goto err;
>+            }
>+            snprintf(intf, len + 1, "%s", dev);
>+            instance = create_instance(intf, dpdkc->instances, errbuf,
>errlen);
>+            if (!instance)
>+                goto err;
>+
>+            instance->next = dpdkc->instances;
>+            dpdkc->instances = instance;
>+            num_intfs++;
>+            if (config->mode != DAQ_MODE_PASSIVE)
>+            {
>+                if (num_intfs == 2)
>+                {
>+                    port1 = dpdkc->instances->next->port;
>+                    port2 = dpdkc->instances->port;
>+
>+                    if (create_bridge(dpdkc, port1, port2) !=
>DAQ_SUCCESS)
>+                    {
>+                        snprintf(errbuf, errlen, "%s: Couldn't create
>the bridge between dpdk%d and dpdk%d!",
>+                                 __FUNCTION__, port1, port2);
>+                        goto err;
>+                    }
>+                    num_intfs = 0;
>+                }
>+                else if (num_intfs > 2)
>+                    break;
>+            }
>+        }
>+        else
>+            len = 1;
>+        dev += len;
>+    }
>+
>+    /* If there are any leftover unbridged interfaces and we're not in
>Passive mode, error out. */
>+    if (!dpdkc->instances || (config->mode != DAQ_MODE_PASSIVE &&
>num_intfs != 0))
>+    {
>+        snprintf(errbuf, errlen, "%s: Invalid interface specification:
>'%s'!",
>+                __FUNCTION__, dpdkc->device);
>+        goto err;
>+    }
>+
>+    /* Initialize other default configuration values. */
>+    dpdkc->debug = 0;
>+
>+    /* Import the configuration dictionary requests. */
>+    for (entry = config->values; entry; entry = entry->next)
>+    {
>+        if (!strcmp(entry->key, "debug"))
>+            dpdkc->debug = 1;
>+    }
>+
>+    dpdkc->state = DAQ_STATE_INITIALIZED;
>+
>+    *ctxt_ptr = dpdkc;
>+    return DAQ_SUCCESS;
>+
>+err:
>+    if (dpdkc)
>+    {
>+        dpdk_close(dpdkc);
>+        if (dpdkc->device)
>+            free(dpdkc->device);
>+        free(dpdkc);
>+    }
>+    return rval;
>+}
>+
>+static int dpdk_daq_set_filter(void *handle, const char *filter)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+    struct sfbpf_program fcode;
>+
>+    if (dpdkc->filter)
>+        free(dpdkc->filter);
>+
>+    dpdkc->filter = strdup(filter);
>+    if (!dpdkc->filter)
>+    {
>+        DPE(dpdkc->errbuf, "%s: Couldn't allocate memory for the filter
>string!", __FUNCTION__);
>+        return DAQ_ERROR;
>+    }
>+
>+    if (sfbpf_compile(dpdkc->snaplen, DLT_EN10MB, &fcode, dpdkc->filter,
>1, 0) < 0)
>+    {
>+        DPE(dpdkc->errbuf, "%s: BPF state machine compilation failed!",
>__FUNCTION__);
>+        return DAQ_ERROR;
>+    }
>+
>+    sfbpf_freecode(&dpdkc->fcode);
>+    dpdkc->fcode.bf_len = fcode.bf_len;
>+    dpdkc->fcode.bf_insns = fcode.bf_insns;
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static int dpdk_daq_start(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+    DpdkInstance *instance;
>+
>+    for (instance = dpdkc->instances; instance; instance =
>instance->next)
>+    {
>+        if (start_instance(dpdkc, instance) != DAQ_SUCCESS)
>+            return DAQ_ERROR;
>+    }
>+
>+    dpdk_daq_reset_stats(handle);
>+
>+    dpdkc->state = DAQ_STATE_STARTED;
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = {
>+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_PASS */
>+    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLOCK */
>+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_REPLACE */
>+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_WHITELIST */
>+    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLACKLIST */
>+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_IGNORE */
>+    DAQ_VERDICT_BLOCK       /* DAQ_VERDICT_RETRY */
>+};
>+
>+static int dpdk_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t
>callback, DAQ_Meta_Func_t metaback, void *user)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+    DpdkInstance *instance, *peer;
>+    DAQ_PktHdr_t daqhdr;
>+    DAQ_Verdict verdict;
>+    const uint8_t *data;
>+    uint16_t len;
>+    int c = 0, burst_size;
>+    int i, got_one, ignored_one, sent_one;
>+    int queue;
>+    struct timeval ts;
>+
>+    while (c < cnt || cnt <= 0)
>+    {
>+        struct rte_mbuf *bufs[BURST_SIZE];
>+
>+        got_one = 0;
>+        ignored_one = 0;
>+        sent_one = 0;
>+
>+        for (instance = dpdkc->instances; instance; instance =
>instance->next)
>+        {
>+
>+            /* Has breakloop() been called? */
>+            if (dpdkc->break_loop)
>+            {
>+                dpdkc->break_loop = 0;
>+                return 0;
>+            }
>+
>+            peer = instance->peer;
>+            if (peer)
>+            {
>+                burst_size = peer->tx_end - peer->tx_start;
>+                if (burst_size > 0)
>+                    goto do_send_packet;
>+            }
>+
>+            for (queue = 0; queue < instance->rx_rings; queue++)
>+            {
>+                gettimeofday(&ts, NULL);
>+
>+                if (cnt <= 0 || cnt - c >= BURST_SIZE)
>+                    burst_size = BURST_SIZE;
>+                else
>+                    burst_size = cnt - c;
>+
>+                const uint16_t nb_rx =
>+                    rte_eth_rx_burst(instance->port, queue,
>+                            bufs, burst_size);
>+
>+                if (unlikely(nb_rx == 0))
>+                    continue;
>+
>+                for (i = 0; i < nb_rx; i++)
>+                {
>+                    verdict = DAQ_VERDICT_PASS;
>+
>+                    data = rte_pktmbuf_mtod(bufs[i], void *);
>+                    len = rte_pktmbuf_data_len(bufs[i]);
>+
>+                    dpdkc->stats.hw_packets_received++;
>+
>+                    if (dpdkc->fcode.bf_insns &&
>sfbpf_filter(dpdkc->fcode.bf_insns, data, len, len) == 0)
>+                    {
>+                        ignored_one = 1;
>+                        dpdkc->stats.packets_filtered++;
>+                        goto send_packet;
>+                    }
>+                    got_one = 1;
>+
>+                    daqhdr.ts = ts;
>+                    daqhdr.caplen = len;
>+                    daqhdr.pktlen = len;
>+                    daqhdr.ingress_index = instance->index;
>+                    daqhdr.egress_index = peer ? peer->index :
>DAQ_PKTHDR_UNKNOWN;
>+                    daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN;
>+                    daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN;
>+                    daqhdr.flags = 0;
>+                    daqhdr.opaque = 0;
>+                    daqhdr.priv_ptr = NULL;
>+                    daqhdr.address_space_id = 0;
>+
>+                    if (callback)
>+                    {
>+                        verdict = callback(user, &daqhdr, data);
>+                        if (verdict >= MAX_DAQ_VERDICT)
>+                            verdict = DAQ_VERDICT_PASS;
>+                        dpdkc->stats.verdicts[verdict]++;
>+                        verdict = verdict_translation_table[verdict];
>+                    }
>+                    dpdkc->stats.packets_received++;
>+                    c++;
>+send_packet:
>+                    if (verdict == DAQ_VERDICT_PASS && peer)
>+                    {
>+                        peer->tx_burst[peer->tx_end] = bufs[i];
>+                        peer->tx_end++;
>+                    }
>+                    else
>+                    {
>+                        rte_pktmbuf_free(bufs[i]);
>+                    }
>+                }
>+            }
>+
>+            if (peer)
>+            {
>+                burst_size = peer->tx_end - peer->tx_start;
>+                if (unlikely(burst_size == 0))
>+                    continue;
>+do_send_packet:
>+                for (queue = 0; burst_size != 0 && queue <
>peer->tx_rings; queue++)
>+                {
>+                    const uint16_t nb_tx = rte_eth_tx_burst(peer->port,
>+                            queue,
>+                            &peer->tx_burst[peer->tx_start],
>+                            burst_size);
>+
>+                    if (unlikely(nb_tx == 0))
>+                        continue;
>+
>+                    sent_one = 1;
>+                    burst_size -= nb_tx;
>+                    peer->tx_start += nb_tx;
>+                }
>+
>+                if (burst_size == 0)
>+                {
>+                    peer->tx_start = 0;
>+                    peer->tx_end = 0;
>+                }
>+            }
>+        }
>+
>+        if ((!got_one && !ignored_one && !sent_one))
>+        {
>+            struct timeval now;
>+
>+            if (dpdkc->timeout == -1)
>+                continue;
>+
>+            /* If time out, return control to the caller. */
>+            gettimeofday(&now, NULL);
>+            if (now.tv_sec > ts.tv_sec ||
>+                    (now.tv_usec - ts.tv_usec) > dpdkc->timeout * 1000)
>+                return 0;
>+        }
>+        else
>+        {
>+            gettimeofday(&ts, NULL);
>+        }
>+    }
>+
>+    return 0;
>+}
>+
>+static int dpdk_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, const
>uint8_t *packet_data, uint32_t len, int reverse)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+    DpdkInstance *instance;
>+
>+    struct rte_mbuf *m;
>+
>+    /* Find the instance that the packet was received on. */
>+    for (instance = dpdkc->instances; instance; instance =
>instance->next)
>+    {
>+        if (instance->index == hdr->ingress_index)
>+            break;
>+    }
>+
>+    if (!instance)
>+    {
>+        DPE(dpdkc->errbuf, "%s: Unrecognized ingress interface
>specified: %u",
>+                __FUNCTION__, hdr->ingress_index);
>+        return DAQ_ERROR_NODEV;
>+    }
>+
>+    if (!reverse && !(instance = instance->peer))
>+    {
>+        DPE(dpdkc->errbuf, "%s: Specified ingress interface (%u) has no
>peer for forward injection.",
>+                __FUNCTION__, hdr->ingress_index);
>+        return DAQ_ERROR_NODEV;
>+    }
>+
>+    m = rte_pktmbuf_alloc(instance->mbuf_pool);
>+    if (!m)
>+    {
>+        DPE(dpdkc->errbuf, "%s: Couldn't allocate memory for packet.",
>+                __FUNCTION__);
>+        return DAQ_ERROR_NOMEM;
>+    }
>+
>+    rte_memcpy(rte_pktmbuf_mtod(m, void *), packet_data, len);
>+
>+    const uint16_t nb_tx = rte_eth_tx_burst(instance->port, 0, &m, 1);
>+
>+    if (unlikely(nb_tx == 0))
>+    {
>+        DPE(dpdkc->errbuf, "%s: Couldn't send packet. Try again.",
>__FUNCTION__);
>+        rte_pktmbuf_free(m);
>+        return DAQ_ERROR_AGAIN;
>+    }
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static int dpdk_daq_breakloop(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    dpdkc->break_loop = 1;
>+
>+    return DAQ_SUCCESS;
>+
>+}
>+
>+static int dpdk_daq_stop(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    dpdk_close(dpdkc);
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static void dpdk_daq_shutdown(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    dpdk_close(dpdkc);
>+    if (dpdkc->device)
>+        free(dpdkc->device);
>+    if (dpdkc->filter)
>+        free(dpdkc->filter);
>+    free(dpdkc);
>+}
>+
>+static DAQ_State dpdk_daq_check_status(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    return dpdkc->state;
>+}
>+
>+static int dpdk_daq_get_stats(void *handle, DAQ_Stats_t *stats)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    rte_memcpy(stats, &dpdkc->stats, sizeof(DAQ_Stats_t));
>+
>+    return DAQ_SUCCESS;
>+}
>+
>+static void dpdk_daq_reset_stats(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    memset(&dpdkc->stats, 0, sizeof(DAQ_Stats_t));
>+}
>+
>+static int dpdk_daq_get_snaplen(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    return dpdkc->snaplen;
>+}
>+
>+static uint32_t dpdk_daq_get_capabilities(void *handle)
>+{
>+    return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT |
>+        DAQ_CAPA_UNPRIV_START | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_BPF |
>+        DAQ_CAPA_DEVICE_INDEX;
>+}
>+
>+static int dpdk_daq_get_datalink_type(void *handle)
>+{
>+    return DLT_EN10MB;
>+}
>+
>+static const char *dpdk_daq_get_errbuf(void *handle)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    return dpdkc->errbuf;
>+}
>+
>+static void dpdk_daq_set_errbuf(void *handle, const char *string)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+
>+    if (!string)
>+        return;
>+
>+    DPE(dpdkc->errbuf, "%s", string);
>+}
>+
>+static int dpdk_daq_get_device_index(void *handle, const char *device)
>+{
>+    Dpdk_Context_t *dpdkc = (Dpdk_Context_t *) handle;
>+    DpdkInstance *instance;
>+    int port;
>+
>+    if (strncmp(device, "dpdk", 4) != 0 || sscanf(&device[4], "%d",
>&port) != 1)
>+        return DAQ_ERROR_NODEV;
>+
>+    for (instance = dpdkc->instances; instance; instance =
>instance->next)
>+    {
>+        if (instance->port == port)
>+            return instance->index;
>+    }
>+
>+    return DAQ_ERROR_NODEV;
>+}
>+
>+#ifdef BUILDING_SO
>+DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA =
>+#else
>+const DAQ_Module_t dpdk_daq_module_data =
>+#endif
>+{
>+    /* .api_version = */ DAQ_API_VERSION,
>+    /* .module_version = */ DAQ_DPDK_VERSION,
>+    /* .name = */ "dpdk",
>+    /* .type = */ DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_INTF_CAPABLE |
>DAQ_TYPE_MULTI_INSTANCE,
>+    /* .initialize = */ dpdk_daq_initialize,
>+    /* .set_filter = */ dpdk_daq_set_filter,
>+    /* .start = */ dpdk_daq_start,
>+    /* .acquire = */ dpdk_daq_acquire,
>+    /* .inject = */ dpdk_daq_inject,
>+    /* .breakloop = */ dpdk_daq_breakloop,
>+    /* .stop = */ dpdk_daq_stop,
>+    /* .shutdown = */ dpdk_daq_shutdown,
>+    /* .check_status = */ dpdk_daq_check_status,
>+    /* .get_stats = */ dpdk_daq_get_stats,
>+    /* .reset_stats = */ dpdk_daq_reset_stats,
>+    /* .get_snaplen = */ dpdk_daq_get_snaplen,
>+    /* .get_capabilities = */ dpdk_daq_get_capabilities,
>+    /* .get_datalink_type = */ dpdk_daq_get_datalink_type,
>+    /* .get_errbuf = */ dpdk_daq_get_errbuf,
>+    /* .set_errbuf = */ dpdk_daq_set_errbuf,
>+    /* .get_device_index = */ dpdk_daq_get_device_index,
>+    /* .modify_flow = */ NULL,
>+    /* .hup_prep = */ NULL,
>+    /* .hup_apply = */ NULL,
>+    /* .hup_post = */ NULL,
>+    /* .dp_add_dc = */ NULL
>+};
>diff --git a/os-daq-modules/daq_static_modules.c
>b/os-daq-modules/daq_static_modules.c
>index 96de3b8..c430bc0 100644
>--- a/os-daq-modules/daq_static_modules.c
>+++ b/os-daq-modules/daq_static_modules.c
>@@ -26,6 +26,9 @@ const DAQ_Module_t *static_modules[] =
> #ifdef BUILD_AFPACKET_MODULE
>     &afpacket_daq_module_data,
> #endif
>+#ifdef BUILD_DPDK_MODULE
>+    &dpdk_daq_module_data,
>+#endif
> #ifdef BUILD_DUMP_MODULE
>     &dump_daq_module_data,
> #endif
>diff --git a/os-daq-modules/daq_static_modules.h
>b/os-daq-modules/daq_static_modules.h
>index befcfca..a418351 100644
>--- a/os-daq-modules/daq_static_modules.h
>+++ b/os-daq-modules/daq_static_modules.h
>@@ -24,6 +24,9 @@
> #ifdef BUILD_AFPACKET_MODULE
> extern const DAQ_Module_t afpacket_daq_module_data;
> #endif
>+#ifdef BUILD_DPDK_MODULE
>+extern const DAQ_Module_t dpdk_daq_module_data;
>+#endif
> #ifdef BUILD_DUMP_MODULE
> extern const DAQ_Module_t dump_daq_module_data;
> #endif
>-- 
>2.7.4 (Apple Git-66)
>
>----------------------------------------------------------------
>
>## Usage
>
>### Setup DPDK
>
>$ cd dpdk-16.04
>$ export RTE_SDK=`pwd`
>$ export RTE_TARGET=build
>
>Patch dpdk with the following patch:
>
>diff --git a/mk/exec-env/linuxapp/rte.vars.mk
>b/mk/exec-env/linuxapp/rte.vars.mk
>index 5fd7d85..847a3d0 100644
>--- a/mk/exec-env/linuxapp/rte.vars.mk
>+++ b/mk/exec-env/linuxapp/rte.vars.mk
>@@ -41,6 +41,8 @@
> #
> ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> EXECENV_CFLAGS  = -pthread -fPIC
>+else ifeq ($(CONFIG_RTE_BUILD_FPIC),y)
>+EXECENV_CFLAGS  = -pthread -fPIC
> else
> EXECENV_CFLAGS  = -pthread
> endif
>
>$ make config T=x86_64-native-linuxapp-gcc
>$ echo 'CONFIG_RTE_BUILD_FPIC=y' >> build/.config
>$ echo 'CONFIG_RTE_BUILD_COMBINE_LIBS=y' >> build/.config
>$ make
><... setup dpdk ...>
>
>### Setup daq
>
>$ wget https://www.snort.org/downloads/snort/daq-2.0.6.tar.gz
>$ tar xvfz daq-2.0.6.tar.gz
>$ cd daq-2.0.6
>
><... patch daq-2.0.6 with the above patch ...>
>
>$ aclocal
>$ autoconf
>$ autoheader
>$ automake -a
>$ ./configure --with-dpdk-includes=$RTE_SDK/$RTE_TARGET/include
>--with-dpdk-libraries=$RTE_SDK/$RTE_TARGET/lib
>$ make && sudo make install
>
>### Setup snort
>
>$ wget https://www.snort.org/downloads/snort/snort-2.9.8.2.tar.gz
>$ tar xvfz snort-2.9.8.2.tar.gz
>$ cd snort-2.9.8.2
>$ ./configure
>
>Patch src/Makefile with following patch:
>
>diff --git a/src/Makefile b/src/Makefile
>index bc947ba..54985aa 100644
>--- a/src/Makefile
>+++ b/src/Makefile
>@@ -507,7 +507,7 @@ clean-binPROGRAMS:
> 
> snort$(EXEEXT): $(snort_OBJECTS) $(snort_DEPENDENCIES)
>$(EXTRA_snort_DEPENDENCIES)
> 	@rm -f snort$(EXEEXT)
>-	$(AM_V_CCLD)$(LINK) $(snort_OBJECTS) $(snort_LDADD) $(LIBS)
>+	$(AM_V_CCLD)$(LINK) $(snort_OBJECTS) $(snort_LDADD) $(LIBS)
>-Wl,--whole-archive,-ldpdk,--no-whole-archive
> 
> mostlyclean-compile:
> 	-rm -f *.$(OBJEXT)
>
>$ make
><... setup snort ...>
>
>### Run snort with DPDK DAQ module
>
># 1. dpdk interfaces are named as dpdk0, dpdk1, ...
># 2. dpdk eal arguments are passed to DPDK DAQ Module via dpdk_args, e.g.
>dpdk_args="-c 40"
>$ sudo ./src/snort --daq dpdk --daq-var dpdk_args="-c 40" -i dpdk0:dpdk1
>--daq-mode inline -c etc/snort.conf -Q -f 'not ip'
>
>----------------------------------------------------------------
>
>## Performance
>
>We have tested the performance in inline mode with three computers
>equipped with Intel 82599ES 10Gb NICs:
>
>[ computer1 ] -> [ computer2 ] -> [ computer3 ]
>
>### On computer1:
>
>We used pktgen[1] to generate 60 bytes random UDP packets at line rate:
>
>$ cat config
>core_id=3,port_id=0,queue_id=0  # CPU3 manages the queue 0 of NIC-0
>$ sudo ./build/pktgen -c 08 -- -c config -f tx -b 6
>
>### On computer2:
>
>We ran snort in inline mode:
>
>$ sudo ./src/snort --daq dpdk --daq-var dpdk_args="-c 40" \
>                   -i dpdk0:dpdk1 --daq-mode inline \
>                   -c etc/snort.conf -Q -f 'not ip'
>
>And -f 'not ip' was used in our performance testing to bypass the
>snort upper layers' processing, so the packets will be forwarded
>in daq directly.
>
>### On computer3:
>
>We used pktgen[1] to receive packets, and got the following performance
>numbers:
>
>$ sudo ./build/pktgen -c fffff -- -c config -f rx
>Lcore 18: 14.877 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8512 sec
>Lcore 18: 14.876 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8551 sec
>Lcore 18: 14.877 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8562 sec
>Lcore 18: 14.878 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8548 sec
>Lcore 18: 14.874 Mpps, 9.995 Gbps (4 packets per chunk) in 0.8535 sec
>Lcore 18: 14.880 Mpps, 10.000 Gbps (4 packets per chunk) in 0.8520 sec
>Lcore 18: 14.875 Mpps, 9.996 Gbps (4 packets per chunk) in 0.8565 sec
>Lcore 18: 14.876 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8552 sec
>Lcore 18: 14.878 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8554 sec
>Lcore 18: 14.878 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8528 sec
>Lcore 18: 14.878 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8556 sec
>Lcore 18: 14.876 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8560 sec
>Lcore 18: 14.879 Mpps, 9.999 Gbps (4 packets per chunk) in 0.8538 sec
>Lcore 18: 14.876 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8536 sec
>Lcore 18: 14.878 Mpps, 9.998 Gbps (4 packets per chunk) in 0.8552 sec
>Lcore 18: 14.876 Mpps, 9.997 Gbps (4 packets per chunk) in 0.8562 sec
>
>----------------------------------------------------------------
>
>## Ugly hacks
>
>There are some ugly hacks in this patch related to CFLAGS/LDFLAGS :-(
>
>1. Need to patch snort-2.9.8.2/src/Makefile manually:
>    -       $(AM_V_CCLD)$(LINK) $(snort_OBJECTS) $(snort_LDADD) $(LIBS)
>    +       $(AM_V_CCLD)$(LINK) $(snort_OBJECTS) $(snort_LDADD) $(LIBS) 
>-Wl,--whole-archive,-ldpdk,--no-whole-archive
>
>2. Override the global CFLAGS when DPDK DAQ Module is enabled:
>    CFLAGS="${CFLAGS} -std=gnu99 -Wno-pedantic"
>
>Any comments would be appreciated. Thanks a lot!
>
>[1] https://github.com/btw616/dpdk/tree/master/apps/pktgen
>
>Best wishes,
>Tiwei Bie
>
>
>--------------------------------------------------------------------------
>----
>What NetFlow Analyzer can do for you? Monitors network bandwidth and 
>traffic
>patterns at an interface-level. Reveals which users, apps, and protocols 
>are 
>consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
>J-Flow, sFlow and other flows. Make informed decisions using capacity 
>planning
>reports. 
>http://pubads.g.doubleclick.net/gampad/clk?id=1444514421&iu=/41014381
>_______________________________________________
>Snort-devel mailing list
>[email protected]
>https://lists.sourceforge.net/lists/listinfo/snort-devel
>Archive:
>http://sourceforge.net/mailarchive/forum.php?forum_name=snort-devel
>
>Please visit http://blog.snort.org for the latest news about Snort!


------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports. http://pubads.g.doubleclick.net/gampad/clk?id=1444514421&iu=/41014381
_______________________________________________
Snort-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/snort-devel
Archive:
http://sourceforge.net/mailarchive/forum.php?forum_name=snort-devel

Please visit http://blog.snort.org for the latest news about Snort!
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.