]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
Napatech 3GD Support 177/head
authorMatt Keeler <mk@npulsetech.com>
Thu, 4 Oct 2012 16:34:00 +0000 (12:34 -0400)
committerMatt Keeler <mk@npulsetech.com>
Tue, 6 Nov 2012 13:37:22 +0000 (08:37 -0500)
For use with Network Cards from Napatech utilizing the 3GD driver/api.

    - Implemented new run modes in runmode-napatech-3gd.*
    - Implemented capture/decode threads in source-napatech-3gd.*
    - Integrated the new run modes and source into the build infrastructure.

    New configure switches
    --enabled-napatech-3gd : Turns on the NT 3GD support
    --with-napatech-3gd-includes : The directory containing the NT 3GD header files
    --with-napatech-3gd-libraries : The directory containing the NT 3GD libraries to link against.

    New CLI switch
    --napatech-3gd : Uses the Napatech 3GD run mode

    Runmodes Supported:
    - auto
    - autofp
    - workers

    Notes:
    - tested with 1 Gbps sustained traffic (no drops)

Signed-off-by: Matt Keeler <mk@npulsetech.com>
13 files changed:
configure.ac
src/Makefile.am
src/runmode-napatech-3gd.c [new file with mode: 0644]
src/runmode-napatech-3gd.h [new file with mode: 0644]
src/runmodes.c
src/runmodes.h
src/source-napatech-3gd.c [new file with mode: 0644]
src/source-napatech-3gd.h [new file with mode: 0644]
src/suricata.c
src/tm-modules.c
src/tm-threads-common.h
src/util-error.c
src/util-error.h

index 2a9d655213cae2d15ab01b5197da5621ca16f440..aa6f8bf75b35001eea1acb722fd54306c34eb801 100644 (file)
@@ -1223,6 +1223,39 @@ AC_INIT(configure.ac)
         fi
     fi
 
+  # napatech-3gd
+    AC_ARG_ENABLE(napatech-3gd,
+                [  --enable-napatech-3gd   Enabled Napatech 3GD Devices],
+                [ enable_napatech_3gd=yes ],
+                [ enable_napatech_3gd=no])
+    AC_ARG_WITH(napatech_3gd_includes,
+                [  --with-napatech-3gd-includes=DIR   napatech 3gd include directory],
+                [with_napatech_3gd_includes="$withval"],[with_napatech_3gd_includes="/opt/napatech3/include"])
+    AC_ARG_WITH(napatech_3gd_libraries,
+                [  --with-napatech-3gd-libraries=DIR  napatech 3gd library directory],
+                [with_napatech_3gd_libraries="$withval"],[with_napatech_3gd_libraries="/opt/napatech3/lib"])
+
+    if test "$enable_napatech_3gd" = "yes"; then
+        CPPFLAGS="${CPPFLAGS} -I${with_napatech_3gd_includes}"
+        LDFLAGS="${LDFLAGS} -L${with_napatech_3gd_libraries} -lntapi"
+        AC_CHECK_HEADER(nt.h,NAPATECH_3GD="yes",NAPATECH_3GD="no")
+        if test "$NAPATECH_3GD" != "no"; then
+            NAPATECH_3GD=""
+            AC_CHECK_LIB(ntapi, NT_Init,NAPATECH_3GD="yes",NAPATECH_3GD="no")
+        fi
+
+        if test "$NAPATECH_3GD" != "no"; then
+            CFLAGS="${CFLAGS} -DHAVE_NAPATECH_3GD"
+        fi
+
+        if test "$NAPATECH_3GD" = "no"; then
+            echo
+            echo "  ERROR! libntapi library not found"
+            echo
+            exit 1
+        fi
+    fi
+
   # libluajit
     AC_ARG_ENABLE(luajit,
                [  --enable-luajit  Enable Luajit support],
@@ -1339,6 +1372,7 @@ Suricata Configuration:
   IPFW support:                            ${enable_ipfw}
   DAG enabled:                             ${enable_dag}
   Napatech enabled:                        ${enable_napatech}
+  Napatech 3GD enabled:                    ${enable_napatech_3gd}
 
   libnss support:                          ${enable_nss}
   libnspr support:                         ${enable_nspr}
index 7b1d31ebf4d7e1ffe2bd6e11ea2163e1766275c3..a55438ef8597709f7d8cd473b922ed543f483d1f 100644 (file)
@@ -16,6 +16,7 @@ runmode-ipfw.c runmode-ipfw.h \
 runmode-erf-file.c runmode-erf-file.h \
 runmode-erf-dag.c runmode-erf-dag.h \
 runmode-napatech.c runmode-napatech.h \
+runmode-napatech-3gd.c runmode-napatech-3gd.h \
 runmode-af-packet.c runmode-af-packet.h \
 packet-queue.c packet-queue.h \
 data-queue.c data-queue.h \
@@ -28,6 +29,7 @@ source-ipfw.c source-ipfw.h \
 source-erf-file.c source-erf-file.h \
 source-erf-dag.c source-erf-dag.h \
 source-napatech.c source-napatech.h \
+source-napatech-3gd.c source-napatech-3gd.h \
 source-af-packet.c source-af-packet.h \
 decode.c decode.h \
 decode-ethernet.c decode-ethernet.h \
diff --git a/src/runmode-napatech-3gd.c b/src/runmode-napatech-3gd.c
new file mode 100644 (file)
index 0000000..c3ea162
--- /dev/null
@@ -0,0 +1,207 @@
+/* Copyright (C) 2012 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ *  \author nPulse Technologies, LLC.
+ *  \author Matt Keeler <mk@npulsetech.com>
+ */
+
+#include "suricata-common.h"
+#include "tm-threads.h"
+#include "conf.h"
+#include "runmodes.h"
+#include "runmode-napatech.h"
+#include "log-httplog.h"
+#include "output.h"
+
+#include "alert-fastlog.h"
+#include "alert-prelude.h"
+#include "alert-unified2-alert.h"
+#include "alert-debuglog.h"
+
+#include "util-debug.h"
+#include "util-time.h"
+#include "util-cpu.h"
+#include "util-affinity.h"
+#include "util-runmodes.h"
+#include "util-device.h"
+
+#include "runmode-napatech-3gd.h"
+
+// need Napatech3GDStreamDevConf structure
+#include "source-napatech-3gd.h"
+
+#define NT3GD_RUNMODE_AUTO    1
+#define NT3GD_RUNMODE_AUTOFP  2
+#define NT3GD_RUNMODE_WORKERS 4
+
+static const char *default_mode = NULL;
+static int num_configured_streams = 0;
+
+const char *RunModeNapatech3GDGetDefaultMode(void)
+{
+    return default_mode;
+}
+
+void RunModeNapatech3GDRegister(void)
+{
+    SCLogInfo("RunModeNapatech3GDRegister called\n");
+#ifdef HAVE_NAPATECH_3GD
+    default_mode = "autofp";
+    RunModeRegisterNewRunMode(RUNMODE_NAPATECH_3GD, "auto",
+            "Multi threaded Napatech 3GD mode",
+            RunModeNapatech3GDAuto);
+    RunModeRegisterNewRunMode(RUNMODE_NAPATECH_3GD, "autofp",
+            "Multi threaded Napatech 3GD mode.  Packets from "
+            "each flow are assigned to a single detect "
+            "thread instead of any detect thread",
+            RunModeNapatech3GDAutoFp);
+    RunModeRegisterNewRunMode(RUNMODE_NAPATECH_3GD, "workers",
+            "Workers Napatech 3GD mode, each thread does all"
+            " tasks from acquisition to logging",
+            RunModeNapatech3GDWorkers);
+    return;
+#endif
+}
+
+#ifdef HAVE_NAPATECH_3GD
+int Napatech3GDRegisterDeviceStreams()
+{
+    NtInfoStream_t info_stream;
+    NtInfo_t info;
+    char error_buf[100];
+    int status;
+    int i;
+    char live_dev_buf[9];
+
+    if ((status = NT_InfoOpen(&info_stream, "Test")) != NT_SUCCESS)
+    {
+        NT_ExplainError(status, error_buf, sizeof(error_buf) -1);
+        SCLogError(SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED, "NT_InfoOpen failed: %s", error_buf);
+        return -1;
+    }
+
+
+    info.cmd = NT_INFO_CMD_READ_STREAM;
+    if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS)
+    {
+        NT_ExplainError(status, error_buf, sizeof(error_buf) -1);
+        SCLogError(SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED, "NT_InfoRead failed: %s", error_buf);
+        return -1;
+    }
+
+    num_configured_streams = info.u.stream.data.count;
+    for (i = 0; i < num_configured_streams; i++)
+    {
+        // The Stream IDs do not have to be sequential
+        snprintf(live_dev_buf, sizeof(live_dev_buf), "nt3gd%d", info.u.stream.data.streamIDList[i]);
+        LiveRegisterDevice(live_dev_buf);
+    }
+
+    if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS)
+    {
+        NT_ExplainError(status, error_buf, sizeof(error_buf) -1);
+        SCLogError(SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED, "NT_InfoClose failed: %s", error_buf);
+        return -1;
+    }
+    return 0;
+}
+
+void *Napatech3GDConfigParser(const char *device) {
+    // Expect device to be of the form nt3gd%d where %d is the stream id to use
+    int dev_len = strlen(device);
+    struct Napatech3GDStreamDevConf *conf = SCMalloc(sizeof(struct Napatech3GDStreamDevConf));
+    if (dev_len < 6 || dev_len > 8)
+    {
+        SCLogError(SC_ERR_NAPATECH_3GD_PARSE_CONFIG, "Could not parse config for device: %s - invalid length", device);
+        return NULL;
+    }
+
+    // device+5 is a pointer to the beginning of the stream id after the constant nt3gd portion
+    conf->stream_id = atoi(device+5);
+    return (void *) conf;
+}
+
+int Napatech3GDGetThreadsCount(void *conf __attribute__((unused))) {
+    // No matter which live device it is there is no reason to ever use more than 1 thread
+    //   2 or more thread would cause packet duplication
+    return 1;
+}
+
+int Napatech3GDInit(DetectEngineCtx *de_ctx, int runmode) {
+    int ret;
+    char errbuf[100];
+
+    RunModeInitialize();
+    TimeModeSetLive();
+
+    /* Initialize the 3GD API and check version compatibility */
+    if ((ret = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
+        NT_ExplainError(ret, errbuf, sizeof(errbuf));
+        SCLogError(SC_ERR_NAPATECH_3GD_INIT_FAILED ,"NT_Init failed. Code 0x%X = %s", ret, errbuf);
+        exit(EXIT_FAILURE);
+    }
+
+    ret = Napatech3GDRegisterDeviceStreams();
+    if (ret < 0 || num_configured_streams <= 0) {
+        SCLogError(SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED, "Unable to setup up Napatech 3GD Streams");
+        exit(EXIT_FAILURE);
+    }
+
+    switch(runmode) {
+        case NT3GD_RUNMODE_AUTO:
+            ret = RunModeSetLiveCaptureAuto(de_ctx, Napatech3GDConfigParser, Napatech3GDGetThreadsCount,
+                                            "Napatech3GDStream", "Napatech3GDDecode",
+                                            "RxNT3GD", NULL);
+            break;
+        case NT3GD_RUNMODE_AUTOFP:
+            ret = RunModeSetLiveCaptureAutoFp(de_ctx, Napatech3GDConfigParser, Napatech3GDGetThreadsCount,
+                                              "Napatech3GDStream", "Napatech3GDDecode",
+                                              "RxNT3GD", NULL);
+            break;
+        case NT3GD_RUNMODE_WORKERS:
+            ret = RunModeSetLiveCaptureWorkers(de_ctx, Napatech3GDConfigParser, Napatech3GDGetThreadsCount,
+                                               "Napatech3GDStream", "Napatech3GDDecode",
+                                               "RxNT3GD", NULL);
+            break;
+        default:
+            ret = -1;
+    }
+
+    if (ret != 0) {
+        SCLogError(SC_ERR_RUNMODE, "Runmode start failed");
+        exit(EXIT_FAILURE);
+    }
+    return 0;
+}
+
+int RunModeNapatech3GDAuto(DetectEngineCtx *de_ctx) {
+    return Napatech3GDInit(de_ctx, NT3GD_RUNMODE_AUTO);
+}
+
+int RunModeNapatech3GDAutoFp(DetectEngineCtx *de_ctx) {
+    return Napatech3GDInit(de_ctx, NT3GD_RUNMODE_AUTOFP);
+}
+
+int RunModeNapatech3GDWorkers(DetectEngineCtx *de_ctx) {
+    return Napatech3GDInit(de_ctx, NT3GD_RUNMODE_WORKERS);
+}
+
+#endif
+
diff --git a/src/runmode-napatech-3gd.h b/src/runmode-napatech-3gd.h
new file mode 100644 (file)
index 0000000..99d085a
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2012 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ *  \file
+ *
+ *  \autor nPulse Technologies, LLC.
+ *  \author Matt Keeler <mk@npulsetech.com>
+ */
+
+#ifndef __RUNMODE_NAPATECH_3GD_H__
+#define __RUNMODE_NAPATECH_3GD_H__
+
+#ifdef HAVE_NAPATECH_3GD
+#include <nt.h>
+#endif
+
+int RunModeNapatech3GDAuto(DetectEngineCtx *);
+int RunModeNapatech3GDAutoFp(DetectEngineCtx *);
+int RunModeNapatech3GDWorkers(DetectEngineCtx *);
+void RunModeNapatech3GDRegister(void);
+const char *RunModeNapatech3GDGetDefaultMode(void);
+
+#endif /* __RUNMODE_NAPATECH_3GD_H__ */
index f766ccac1c07aead236335ad83d1ea2693a753c5..7c20252590350bda410ae092d280047c26376a22 100644 (file)
@@ -116,6 +116,8 @@ static const char *RunModeTranslateModeToName(int runmode)
             return "ERF_DAG";
         case RUNMODE_NAPATECH:
             return "NAPATECH";
+        case RUNMODE_NAPATECH_3GD:
+            return "NAPATECH_3GD";
         case RUNMODE_UNITTEST:
             return "UNITTEST";
         case RUNMODE_AFP_DEV:
@@ -175,6 +177,7 @@ void RunModeRegisterRunModes(void)
     RunModeErfFileRegister();
     RunModeErfDagRegister();
     RunModeNapatechRegister();
+    RunModeNapatech3GDRegister();
     RunModeIdsAFPRegister();
 #ifdef UNITTESTS
     UtRunModeRegister();
@@ -263,6 +266,9 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c
             case RUNMODE_NAPATECH:
                 custom_mode = RunModeNapatechGetDefaultMode();
                 break;
+            case RUNMODE_NAPATECH_3GD:
+                custom_mode = RunModeNapatech3GDGetDefaultMode();
+                break;
             case RUNMODE_AFP_DEV:
                 custom_mode = RunModeAFPGetDefaultMode();
                 break;
index 532a193aef3b12857176b25b3d86c73bf4747423..03cfa67572bf14745c52ab12a6d8bc7d676296be 100644 (file)
@@ -36,6 +36,7 @@ enum {
     RUNMODE_NAPATECH,
     RUNMODE_AFP_DEV,
     RUNMODE_UNITTEST,
+    RUNMODE_NAPATECH_3GD,
     RUNMODE_MAX,
 };
 
@@ -59,6 +60,7 @@ void RunModeShutDown(void);
 #include "runmode-erf-file.h"
 #include "runmode-erf-dag.h"
 #include "runmode-napatech.h"
+#include "runmode-napatech-3gd.h"
 #include "runmode-af-packet.h"
 
 int threading_set_cpu_affinity;
diff --git a/src/source-napatech-3gd.c b/src/source-napatech-3gd.c
new file mode 100644 (file)
index 0000000..c0cec5a
--- /dev/null
@@ -0,0 +1,395 @@
+/* Copyright (C) 2012 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author nPulse Technologies, LLC.
+ * \author Matt Keeler <mk@npulsetech.com>
+ *
+ * Support for NAPATECH adapter with the 3GD Driver/API.
+ * Requires libntapi from Napatech A/S.
+ *
+ */
+
+#include "suricata-common.h"
+#include "suricata.h"
+#include "threadvars.h"
+#include "util-optimize.h"
+#include "tm-queuehandlers.h"
+#include "tm-threads.h"
+#include "tm-modules.h"
+
+#include "util-privs.h"
+#include "tmqh-packetpool.h"
+
+#ifndef HAVE_NAPATECH_3GD
+
+TmEcode NoNapatech3GDSupportExit(ThreadVars *, void *, void **);
+
+
+void TmModuleNapatech3GDStreamRegister (void) {
+    tmm_modules[TMM_RECEIVENAPATECH3GD].name = "Napatech3GDStream";
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadInit = NoNapatech3GDSupportExit;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].Func = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadExitPrintStats = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadDeinit = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].RegisterTests = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].cap_flags = SC_CAP_NET_ADMIN;
+}
+
+void TmModuleNapatech3GDDecodeRegister (void) {
+    tmm_modules[TMM_DECODENAPATECH3GD].name = "Napatech3GDDecode";
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadInit = NoNapatech3GDSupportExit;
+    tmm_modules[TMM_DECODENAPATECH3GD].Func = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadExitPrintStats = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadDeinit = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].RegisterTests = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].cap_flags = 0;
+    tmm_modules[TMM_DECODENAPATECH3GD].flags = TM_FLAG_DECODE_TM;
+}
+
+TmEcode NoNapatech3GDSupportExit(ThreadVars *tv, void *initdata, void **data)
+{
+    SCLogError(SC_ERR_NAPATECH_3GD_NOSUPPORT,
+            "Error creating thread %s: you do not have support for Napatech 3GD adapter "
+            "enabled please recompile with --enable-napatech-3gd", tv->name);
+    exit(EXIT_FAILURE);
+}
+
+#else /* Implied we do have NAPATECH 3GD support */
+
+#include "source-napatech-3gd.h"
+#include <nt.h>
+
+extern int max_pending_packets;
+extern uint8_t suricata_ctl_flags;
+
+typedef struct Napatech3GDThreadVars_ {
+    ThreadVars *tv;
+    NtNetStreamRx_t rx_stream;
+    uint64_t stream_id;
+    uint64_t pkts;
+    uint64_t drops;
+    uint64_t bytes;
+
+    TmSlot *slot;
+} Napatech3GDThreadVars;
+
+
+TmEcode Napatech3GDStreamThreadInit(ThreadVars *, void *, void **);
+void Napatech3GDStreamThreadExitStats(ThreadVars *, void *);
+TmEcode Napatech3GDStreamLoop(ThreadVars *tv, void *data, void *slot);
+
+TmEcode Napatech3GDDecodeThreadInit(ThreadVars *, void *, void **);
+TmEcode Napatech3GDDecode(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
+
+/**
+ * \brief Register the Napatech 3GD receiver (reader) module.
+ */
+void TmModuleNapatech3GDStreamRegister(void)
+{
+    tmm_modules[TMM_RECEIVENAPATECH3GD].name = "Napatech3GDStream";
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadInit = Napatech3GDStreamThreadInit;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].Func = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].PktAcqLoop = Napatech3GDStreamLoop;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadExitPrintStats = Napatech3GDStreamThreadExitStats;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].ThreadDeinit = Napatech3GDStreamThreadDeinit;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].RegisterTests = NULL;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].cap_flags = SC_CAP_NET_RAW;
+    tmm_modules[TMM_RECEIVENAPATECH3GD].flags = TM_FLAG_RECEIVE_TM;
+}
+
+/**
+ * \brief Register the Napatech 3GD decoder module.
+ */
+void TmModuleNapatech3GDDecodeRegister(void)
+{
+    tmm_modules[TMM_DECODENAPATECH3GD].name = "Napatech3GDDecode";
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadInit = Napatech3GDDecodeThreadInit;
+    tmm_modules[TMM_DECODENAPATECH3GD].Func = Napatech3GDDecode;
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadExitPrintStats = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].ThreadDeinit = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].RegisterTests = NULL;
+    tmm_modules[TMM_DECODENAPATECH3GD].cap_flags = 0;
+    tmm_modules[TMM_DECODENAPATECH3GD].flags = TM_FLAG_DECODE_TM;
+}
+
+/**
+ * \brief   Initialize the Napatech 3GD receiver thread, generate a single
+ *          NapatechThreadVar structure for each thread, this will
+ *          contain a NtNetStreamRx_t stream handle which is used when the
+ *          thread executes to acquire the packets.
+ *
+ * \param tv        Thread variable to ThreadVars
+ * \param initdata  Initial data to the adapter passed from the user,
+ *                  this is processed by the user.
+ *
+ *                  For now, we assume that we have only a single name for the NAPATECH 3GD
+ *                  adapter.
+ *
+ * \param data      data pointer gets populated with
+ *
+ */
+TmEcode Napatech3GDStreamThreadInit(ThreadVars *tv, void *initdata, void **data)
+{
+    SCEnter();
+    struct Napatech3GDStreamDevConf *conf = (struct Napatech3GDStreamDevConf *)initdata;
+    uintmax_t stream_id = conf->stream_id;
+    *data = NULL;
+
+    SCLogInfo("Napatech 3GD Thread Stream ID:%lu", stream_id);
+
+    Napatech3GDThreadVars *ntv3 = SCMalloc(sizeof(Napatech3GDThreadVars));
+    if (ntv3 == NULL) {
+        SCLogError(SC_ERR_MEM_ALLOC,
+                "Failed to allocate memory for NAPATECH 3GD thread vars.");
+        exit(EXIT_FAILURE);
+    }
+
+    memset(ntv3, 0, sizeof (Napatech3GDThreadVars));
+    ntv3->stream_id = stream_id;
+    ntv3->tv = tv;
+
+    SCLogInfo("Started processing packets from NAPATECH 3GD Stream: %lu", ntv3->stream_id);
+
+    *data = (void *)ntv3;
+
+    SCReturnInt(TM_ECODE_OK);
+}
+
+/**
+ *  \brief Main Napatech 3GD reading Loop function
+ */
+TmEcode Napatech3GDStreamLoop(ThreadVars *tv, void *data, void *slot)
+{
+    SCEnter();
+
+    int32_t status;
+    char errbuf[100];
+    uint16_t packet_q_len = 0;
+    uint64_t pkt_ts;
+    NtNetBuf_t packet_buffer;
+    Napatech3GDThreadVars *ntv3 = (Napatech3GDThreadVars *)data;
+    NtNetRx_t stat_cmd;
+
+    SCLogInfo("Opening NAPATECH 3GD Stream: %lu for processing", ntv3->stream_id);
+
+    if ((status = NT_NetRxOpen(&(ntv3->rx_stream), "SuricataStream", NT_NET_INTERFACE_PACKET, ntv3->stream_id, -1)) != NT_SUCCESS) {
+        NT_ExplainError(status, errbuf, sizeof(errbuf));
+        SCLogError(SC_ERR_NAPATECH_3GD_OPEN_FAILED, "Failed to open NAPATECH 3GD Stream: %lu - %s", ntv3->stream_id, errbuf);
+        SCFree(ntv3);
+        SCReturnInt(TM_ECODE_FAILED);
+    }
+
+    stat_cmd.cmd = NT_NETRX_READ_CMD_STREAM_DROP;
+
+    SCLogInfo("Napatech 3GD Packet Stream Loop Started for Stream ID: %lu", ntv3->stream_id);
+
+    TmSlot *s = (TmSlot *)slot;
+    ntv3->slot = s->slot_next;
+
+    while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) {
+        /* make sure we have at least one packet in the packet pool, to prevent
+         * us from alloc'ing packets at line rate */
+        do {
+            packet_q_len = PacketPoolSize();
+            if (unlikely(packet_q_len == 0)) {
+                PacketPoolWait();
+            }
+        } while (packet_q_len == 0);
+
+        /*
+         * Napatech 3GD returns packets 1 at a time
+         */
+        status = NT_NetRxGet(ntv3->rx_stream, &packet_buffer, 1000);
+        if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
+            /*
+             * no frames currently available
+             */
+            continue;
+        } else if (unlikely(status != NT_SUCCESS)) {
+            SCLogError(SC_ERR_NAPATECH_3GD_STREAM_NEXT_FAILED,
+                       "Failed to read from Napatech 3GD Stream: %lu",
+                       ntv3->stream_id);
+            SCReturnInt(TM_ECODE_FAILED);
+        }
+
+        Packet *p = PacketGetFromQueueOrAlloc();
+        if (unlikely(p == NULL)) {
+            NT_NetRxRelease(ntv3->rx_stream, packet_buffer);
+            SCReturnInt(TM_ECODE_FAILED);
+        }
+
+        pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer);
+
+        /*
+         * Handle the different timestamp forms that the napatech cards could use
+         *   - NT_TIMESTAMP_TYPE_NATIVE is not supported due to having an base of 0 as opposed to NATIVE_UNIX which has a base of 1/1/1970
+         */
+        switch(NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) {
+            case NT_TIMESTAMP_TYPE_NATIVE_UNIX:
+                p->ts.tv_sec = pkt_ts / 100000000;
+                p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0;
+                break;
+            case NT_TIMESTAMP_TYPE_PCAP:
+                p->ts.tv_sec = pkt_ts >> 32;
+                p->ts.tv_usec = pkt_ts & 0xFFFFFFFF;
+                break;
+            case NT_TIMESTAMP_TYPE_PCAP_NANOTIME:
+                p->ts.tv_sec = pkt_ts >> 32;
+                p->ts.tv_usec = ((pkt_ts & 0xFFFFFFFF) / 1000) + (pkt_ts % 1000) > 500 ? 1 : 0;
+                break;
+            case NT_TIMESTAMP_TYPE_NATIVE_NDIS:
+                /* number of seconds between 1/1/1601 and 1/1/1970 */
+                p->ts.tv_sec = (pkt_ts / 100000000) - 11644473600;
+                p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0;
+                break;
+            default:
+                SCLogError(SC_ERR_NAPATECH_3GD_TIMESTAMP_TYPE_NOT_SUPPORTED,
+                           "Packet from Napatech 3GD Stream: %lu does not have a supported timestamp format",
+                           ntv3->stream_id);
+                NT_NetRxRelease(ntv3->rx_stream, packet_buffer);
+                SCReturnInt(TM_ECODE_FAILED);
+        }
+
+        SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec);
+        p->datalink = LINKTYPE_ETHERNET;
+
+        ntv3->pkts++;
+        ntv3->bytes += NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer);
+
+        // Update drop counter
+        if (unlikely((status = NT_NetRxRead(ntv3->rx_stream, &stat_cmd)) != NT_SUCCESS))
+        {
+            NT_ExplainError(status, errbuf, sizeof(errbuf));
+            SCLogWarning(SC_ERR_NAPATECH_3GD_STAT_DROPS_FAILED, "Couldn't retrieve drop statistics from the RX stream: %lu - %s", ntv3->stream_id, errbuf);
+        }
+        else
+        {
+            ntv3->drops += stat_cmd.u.streamDrop.pktsDropped;
+        }
+
+        if (unlikely(PacketCopyData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
+            TmqhOutputPacketpool(ntv3->tv, p);
+            NT_NetRxRelease(ntv3->rx_stream, packet_buffer);
+            SCReturnInt(TM_ECODE_FAILED);
+        }
+
+        if (unlikely(TmThreadsSlotProcessPkt(ntv3->tv, ntv3->slot, p) != TM_ECODE_OK)) {
+            TmqhOutputPacketpool(ntv3->tv, p);
+            NT_NetRxRelease(ntv3->rx_stream, packet_buffer);
+            SCReturnInt(TM_ECODE_FAILED);
+        }
+
+        NT_NetRxRelease(ntv3->rx_stream, packet_buffer);
+        SCPerfSyncCountersIfSignalled(tv, 0);
+    }
+
+    SCReturnInt(TM_ECODE_OK);
+}
+
+/**
+ * \brief Print some stats to the log at program exit.
+ *
+ * \param tv Pointer to ThreadVars.
+ * \param data Pointer to data, ErfFileThreadVars.
+ */
+void Napatech3GDStreamThreadExitStats(ThreadVars *tv, void *data)
+{
+    Napatech3GDThreadVars *ntv3 = (Napatech3GDThreadVars *)data;
+    double percent = 0;
+    if (ntv3->drops > 0)
+        percent = (((double) ntv3->drops) / (ntv3->pkts+ntv3->drops)) * 100;
+
+    SCLogInfo("Stream: %lu; Packets: %"PRIu64"; Drops: %"PRIu64" (%5.2f%%); Bytes: %"PRIu64, ntv3->stream_id, ntv3->pkts, ntv3->drops, percent, ntv3->bytes);
+}
+
+/**
+ * \brief   Deinitializes the NAPATECH 3GD card.
+ * \param   tv pointer to ThreadVars
+ * \param   data pointer that gets cast into PcapThreadVars for ptv
+ */
+TmEcode Napatech3GDStreamThreadDeinit(ThreadVars *tv, void *data)
+{
+    SCEnter();
+    Napatech3GDThreadVars *ntv3 = (Napatech3GDThreadVars *)data;
+    SCLogDebug("Closing Napatech 3GD Stream: %d", ntv3->stream_id);
+    NT_NetRxClose(ntv3->rx_stream);
+    SCReturnInt(TM_ECODE_OK);
+}
+
+
+/** Decode Napatech 3GD */
+
+/**
+ * \brief   This function passes off to link type decoders.
+ *
+ * Napatech3GDDecode reads packets from the PacketQueue and passes
+ * them off to the proper link type decoder.
+ *
+ * \param t pointer to ThreadVars
+ * \param p pointer to the current packet
+ * \param data pointer that gets cast into PcapThreadVars for ptv
+ * \param pq pointer to the current PacketQueue
+ */
+TmEcode Napatech3GDDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq,
+        PacketQueue *postpq)
+{
+    SCEnter();
+
+    DecodeThreadVars *dtv = (DecodeThreadVars *)data;
+
+    /* update counters */
+    SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca);
+    SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca);
+    SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p));
+    SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
+    SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
+
+    switch (p->datalink) {
+        case LINKTYPE_ETHERNET:
+            DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
+            break;
+        default:
+            SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED,
+                    "Error: datalink type %" PRId32 " not yet supported in module Napatech3GDDecode",
+                    p->datalink);
+            break;
+    }
+    SCReturnInt(TM_ECODE_OK);
+}
+
+TmEcode Napatech3GDDecodeThreadInit(ThreadVars *tv, void *initdata, void **data)
+{
+    SCEnter();
+    DecodeThreadVars *dtv = NULL;
+
+    dtv = DecodeThreadVarsAlloc();
+
+    if(dtv == NULL)
+        SCReturnInt(TM_ECODE_FAILED);
+
+    DecodeRegisterPerfCounters(dtv, tv);
+
+    *data = (void *)dtv;
+
+    SCReturnInt(TM_ECODE_OK);
+}
+
+#endif /* HAVE_NAPATECH_3GD */
+
diff --git a/src/source-napatech-3gd.h b/src/source-napatech-3gd.h
new file mode 100644 (file)
index 0000000..f61c3cd
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2012 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author nPulse Technologies, LLC
+ * \author Matt Keeler <mk@npulsetech.com>
+ */
+
+#ifndef __SOURCE_NAPATECH_3GD_H__
+#define __SOURCE_NAPATECH_3GD_H__
+
+void TmModuleNapatech3GDStreamRegister (void);
+TmEcode Napatech3GDStreamThreadDeinit(ThreadVars *tv, void *data);
+void TmModuleNapatech3GDDecodeRegister (void);
+
+struct Napatech3GDStreamDevConf
+{
+    int stream_id;
+};
+
+#ifdef HAVE_NAPATECH_3GD
+
+#include <nt.h>
+
+#endif
+
+#endif /* __SOURCE_NAPATECH_3GD_H__ */
index 02608585a990a222ad1fdd18eae2b5b37724c2fe..ec50796887974092eda9ca6b29731257c3365f8b 100644 (file)
 #include "source-erf-file.h"
 #include "source-erf-dag.h"
 #include "source-napatech.h"
+#include "source-napatech-3gd.h"
 
 #include "source-af-packet.h"
 
@@ -523,6 +524,9 @@ void usage(const char *progname)
 #endif
 #ifdef HAVE_NAPATECH
     printf("\t--napatech <adapter>          : run Napatech feeds using <adapter>\n");
+#endif
+#ifdef HAVE_NAPATECH_3GD
+    printf("\t--napatech-3gd               : run Napatech Streams using the 3GD API\n");
 #endif
     printf("\n");
     printf("\nTo run the engine with default configuration on "
@@ -773,6 +777,7 @@ int main(int argc, char **argv)
         {"erf-in", required_argument, 0, 0},
         {"dag", required_argument, 0, 0},
         {"napatech", required_argument, 0, 0},
+        {"napatech-3gd", 0, 0, 0},
         {"build-info", 0, &build_info, 1},
         {NULL, 0, NULL, 0}
     };
@@ -1012,6 +1017,15 @@ int main(int argc, char **argv)
                 exit(EXIT_FAILURE);
 #endif /* HAVE_NAPATECH */
                        }
+                       else if (strcmp((long_opts[option_index]).name, "napatech-3gd") == 0) {
+#ifdef HAVE_NAPATECH_3GD
+                run_mode = RUNMODE_NAPATECH_3GD;
+#else
+                SCLogError(SC_ERR_NAPATECH_3GD_REQUIRED, "libntapi and a Napatech adapter are required"
+                                                    " to capture packets using --napatech-3gd.");
+                exit(EXIT_FAILURE);
+#endif /* HAVE_NAPATECH_3GD */
+                                   }
             else if(strcmp((long_opts[option_index]).name, "pcap-buffer-size") == 0) {
 #ifdef HAVE_PCAP_SET_BUFF
                 if (ConfSet("pcap.buffer-size", optarg, 0) != 1) {
@@ -1473,6 +1487,9 @@ int main(int argc, char **argv)
     /* napatech */
     TmModuleNapatechFeedRegister();
     TmModuleNapatechDecodeRegister();
+    /* napatech-3gd */
+    TmModuleNapatech3GDStreamRegister();
+    TmModuleNapatech3GDDecodeRegister();
 
     /* stream engine */
     TmModuleStreamTcpRegister();
index aa6f895b68bd77af26ab64d3167f9783061a862c..4e7b39152c4eeb2a331269dd19c1c6a3753c9723 100644 (file)
@@ -262,6 +262,8 @@ const char * TmModuleTmmIdToString(TmmId id)
         CASE_CODE (TMM_DECODEERFDAG);
         CASE_CODE (TMM_RECEIVENAPATECH);
         CASE_CODE (TMM_DECODENAPATECH);
+        CASE_CODE (TMM_RECEIVENAPATECH3GD);
+        CASE_CODE (TMM_DECODENAPATECH3GD);
         CASE_CODE (TMM_RECEIVEAFP);
         CASE_CODE (TMM_ALERTPCAPINFO);
         CASE_CODE (TMM_DECODEAFP);
index 20033d842aa2f6f423ba708a4ff23cf4974272ff..ca744546044eccc37e588fb3f034a72c162c2c44 100644 (file)
@@ -78,6 +78,8 @@ typedef enum {
     TMM_RECEIVEAFP,
     TMM_DECODEAFP,
     TMM_ALERTPCAPINFO,
+    TMM_RECEIVENAPATECH3GD,
+    TMM_DECODENAPATECH3GD,
     TMM_SIZE,
 } TmmId;
 
index bdada841f2688aaadc5964b16b2885bf5e0595ba..2df4eff25d6563011d9d1b122afb423dacf140e5 100644 (file)
@@ -196,6 +196,16 @@ const char * SCErrorToString(SCError err)
         CASE_CODE (SC_ERR_NAPATECH_FEED_NEXT_FAILED);
         CASE_CODE (SC_ERR_NAPATECH_REQUIRED);
         CASE_CODE (SC_ERR_NAPATECH_NOSUPPORT);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_OPEN_FAILED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_STREAM_NEXT_FAILED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_NOSUPPORT);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_REQUIRED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_TIMESTAMP_TYPE_NOT_SUPPORTED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_INIT_FAILED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_CONFIG_STREAM);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_STAT_DROPS_FAILED);
+        CASE_CODE (SC_ERR_NAPATECH_3GD_PARSE_CONFIG);
         CASE_CODE (SC_WARN_COMPATIBILITY);
         CASE_CODE (SC_ERR_DCERPC);
         CASE_CODE (SC_ERR_DETECT_PREPARE);
index 9ec4ecca6a2dd3b3576979d24a23445e7055c65b..dc10f438c7db88e054e8b583e62a478b5ba75aa4 100644 (file)
@@ -249,6 +249,16 @@ typedef enum {
     SC_ERR_NO_LUAJIT_SUPPORT,
     SC_ERR_LUAJIT_ERROR,
     SC_ERR_DEFRAG_INIT,
+    SC_ERR_NAPATECH_3GD_OPEN_FAILED,
+    SC_ERR_NAPATECH_3GD_STREAM_NEXT_FAILED,
+    SC_ERR_NAPATECH_3GD_NOSUPPORT,
+    SC_ERR_NAPATECH_3GD_REQUIRED,
+    SC_ERR_NAPATECH_3GD_TIMESTAMP_TYPE_NOT_SUPPORTED,
+    SC_ERR_NAPATECH_3GD_INIT_FAILED,
+    SC_ERR_NAPATECH_3GD_CONFIG_STREAM,
+    SC_ERR_NAPATECH_3GD_STREAMS_REGISTER_FAILED,
+    SC_ERR_NAPATECH_3GD_STAT_DROPS_FAILED,
+    SC_ERR_NAPATECH_3GD_PARSE_CONFIG,
 } SCError;
 
 const char *SCErrorToString(SCError);