From: Matt Keeler Date: Thu, 4 Oct 2012 16:34:00 +0000 (-0400) Subject: Napatech 3GD Support X-Git-Tag: suricata-1.4beta3~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F177%2Fhead;p=thirdparty%2Fsuricata.git Napatech 3GD Support 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 --- diff --git a/configure.ac b/configure.ac index 2a9d655213..aa6f8bf75b 100644 --- a/configure.ac +++ b/configure.ac @@ -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} diff --git a/src/Makefile.am b/src/Makefile.am index 7b1d31ebf4..a55438ef85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000000..c3ea162692 --- /dev/null +++ b/src/runmode-napatech-3gd.c @@ -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 + */ + +#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 index 0000000000..99d085ae98 --- /dev/null +++ b/src/runmode-napatech-3gd.h @@ -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 + */ + +#ifndef __RUNMODE_NAPATECH_3GD_H__ +#define __RUNMODE_NAPATECH_3GD_H__ + +#ifdef HAVE_NAPATECH_3GD +#include +#endif + +int RunModeNapatech3GDAuto(DetectEngineCtx *); +int RunModeNapatech3GDAutoFp(DetectEngineCtx *); +int RunModeNapatech3GDWorkers(DetectEngineCtx *); +void RunModeNapatech3GDRegister(void); +const char *RunModeNapatech3GDGetDefaultMode(void); + +#endif /* __RUNMODE_NAPATECH_3GD_H__ */ diff --git a/src/runmodes.c b/src/runmodes.c index f766ccac1c..7c20252590 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -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; diff --git a/src/runmodes.h b/src/runmodes.h index 532a193aef..03cfa67572 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -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 index 0000000000..c0cec5a0bc --- /dev/null +++ b/src/source-napatech-3gd.c @@ -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 + * + * 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 + +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 index 0000000000..f61c3cd778 --- /dev/null +++ b/src/source-napatech-3gd.h @@ -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 + */ + +#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 + +#endif + +#endif /* __SOURCE_NAPATECH_3GD_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 02608585a9..ec50796887 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -117,6 +117,7 @@ #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 : run Napatech feeds using \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(); diff --git a/src/tm-modules.c b/src/tm-modules.c index aa6f895b68..4e7b39152c 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -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); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 20033d842a..ca74454604 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -78,6 +78,8 @@ typedef enum { TMM_RECEIVEAFP, TMM_DECODEAFP, TMM_ALERTPCAPINFO, + TMM_RECEIVENAPATECH3GD, + TMM_DECODENAPATECH3GD, TMM_SIZE, } TmmId; diff --git a/src/util-error.c b/src/util-error.c index bdada841f2..2df4eff25d 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -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); diff --git a/src/util-error.h b/src/util-error.h index 9ec4ecca6a..dc10f438c7 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -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);