diff --git a/configure.in b/configure.in index 866decfe65..8fc98bfff6 100644 --- a/configure.in +++ b/configure.in @@ -748,10 +748,21 @@ AC_CHECK_HEADER(pcap.h,,[AC_ERROR(pcap.h not found ...)]) AM_CONDITIONAL([BUILD_UNITTESTS], [test "x$enable_unittests" = "xyes"]) # AF_PACKET support - AC_CHECK_DECL([PACKET_FANOUT], - AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Packet fanout support is available]), - [], - [[#include ]]) + AC_ARG_ENABLE(af-packet, + AS_HELP_STRING([--enable-af-packet], [Enable AF_PACKET support]), + ,[enable_af_packet=no]) + AS_IF([test "x$enable_af_packet" = "xyes"], [ + AC_CHECK_DECL([AF_PACKET], + AC_DEFINE([HAVE_AF_PACKET],[1],[AF_PACKET support is available]), + [enable_af_packet=no], + [[#include ]]) + AC_CHECK_DECL([PACKET_FANOUT], + AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Packet fanout support is available]), + [], + [[#include ]]) + CFLAGS="${CFLAGS} -DUNITTESTS" + ]) + # enable native timeval for unified alert output AC_ARG_ENABLE(unified-native-timeval, @@ -1001,6 +1012,7 @@ Suricata Configuration: NFQueue support: ${enable_nfqueue} IPFW support: ${enable_ipfw} PF_RING support: ${enable_pfring} + AF_PACKET support: ${enable_af_packet} Prelude support: ${enable_prelude} Unit tests enabled: ${enable_unittests} Debug output enabled: ${enable_debug} diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 763d89d436..6faa07f659 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -15,7 +15,18 @@ * 02110-1301, USA. */ +/** + * \file + * + * \author Eric Leblond + * + * AF_PACKET socket runmode + * + */ + + #include "suricata-common.h" +#include "config.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" @@ -23,7 +34,6 @@ #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" -#include "source-pfring.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" @@ -39,26 +49,49 @@ #include "util-affinity.h" #include "util-device.h" -static const char *default_mode = NULL; +#include "source-af-packet.h" + +static const char *default_mode_auto = NULL; +static const char *default_mode_autofp = NULL; const char *RunModeAFPGetDefaultMode(void) { - return default_mode; +#ifdef HAVE_AF_PACKET +#ifdef HAVE_PACKET_FANOUT + if (AFPConfGetThreads() <= 1) { + return default_mode_auto; + } else { + return default_mode_autofp; + } +#else + return default_mode_auto; +#endif +#else + return NULL; +#endif } void RunModeIdsAFPRegister(void) { + default_mode_auto = "auto"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto", "Multi threaded af-packet mode", RunModeIdsAFPAuto); - default_mode = "auto"; - + RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single", + "Single threaded af-packet mode", + RunModeIdsAFPSingle); + default_mode_autofp = "autofp"; + RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp", + "Multi socket AF_PACKET mode. Packets from " + "each flow are assigned to a single detect " + "thread.", + RunModeIdsAFPAutoFp); return; } /** * \brief RunModeIdsAFPAuto set up the following thread packet handlers: - * - Receive thread (from iface pcap) + * - Receive thread (from live iface) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread @@ -77,6 +110,8 @@ void RunModeIdsAFPRegister(void) int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) { SCEnter(); + +#ifdef HAVE_AF_PACKET /* tname = Detect + cpuid, this is 11bytes length as max */ char tname[16]; uint16_t cpu = 0; @@ -88,28 +123,27 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - /* TODO must not use PCAP function */ - /** \todo fix parasiting of pcap mode */ - int npcap = LiveGetDeviceCount(); + int nlive = LiveGetDeviceCount(); - if (npcap == 1) { - char *pcap_dev = NULL; - if (ConfGet("pcap.single_pcap_dev", &pcap_dev) == 0) { + if (nlive == 1) { + char *live_dev = NULL; + char *live_devc = NULL; + if (ConfGet("af-packet.interface", &live_dev) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving " - "pcap.single_pcap_dev from Conf"); + "af-packet.interface from Conf"); exit(EXIT_FAILURE); } - SCLogDebug("pcap_dev %s", pcap_dev); + SCLogDebug("live_dev %s", live_dev); - char *pcap_devc = SCStrdup(pcap_dev); + live_devc = SCStrdup(live_dev); /* create the threads */ - ThreadVars *tv_receivepcap = + ThreadVars *tv_receiveafp = TmThreadCreatePacketHandler("ReceiveAFP", "packetpool", "packetpool", "pickup-queue", "simple", "1slot"); - if (tv_receivepcap == NULL) { + if (tv_receiveafp == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } @@ -118,28 +152,30 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n"); exit(EXIT_FAILURE); } - Tm1SlotSetFunc(tv_receivepcap, tm_module, (void *)pcap_devc); + TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)live_devc); - TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); + TmThreadSetCPU(tv_receiveafp, RECEIVE_CPU_SET); - if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { + if (TmThreadSpawn(tv_receiveafp) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } } else { - SCLogInfo("Using %d pcap device(s).", npcap); - - for (thread = 0; thread < npcap; thread++) { - char *pcap_dev = LiveGetDevice(thread); - if (pcap_dev == NULL) { - printf("Failed to lookup pcap dev %d\n", thread); + SCLogInfo("Using %d live device(s).", nlive); + + for (thread = 0; thread < nlive; thread++) { + char *live_dev = LiveGetDevice(thread); + char *tnamec = NULL; + char *live_devc = NULL; + if (live_dev == NULL) { + printf("Failed to lookup live dev %d\n", thread); exit(EXIT_FAILURE); } - SCLogDebug("pcap_dev %s", pcap_dev); + SCLogDebug("live_dev %s", live_dev); - snprintf(tname, sizeof(tname),"RecvPcap-%s", pcap_dev); - char *tnamec = SCStrdup(tname); - char *pcap_devc = SCStrdup(pcap_dev); + snprintf(tname, sizeof(tname),"RecvAFP-%s", live_dev); + tnamec = SCStrdup(tname); + live_devc = SCStrdup(live_dev); /* create the threads */ ThreadVars *tv_receiveafp = @@ -156,7 +192,7 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n"); exit(EXIT_FAILURE); } - Tm1SlotSetFunc(tv_receiveafp, tm_module, (void *)pcap_devc); + TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)live_devc); TmThreadSetCPU(tv_receiveafp, RECEIVE_CPU_SET); @@ -286,14 +322,14 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) printf("ERROR: TmModuleGetByName DecodeAFP failed\n"); exit(EXIT_FAILURE); } - TmVarSlotSetFuncAppend(tv_decode1, tm_module, NULL); + TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } - TmVarSlotSetFuncAppend(tv_decode1, tm_module, NULL); + TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); @@ -335,7 +371,7 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } - Tm1SlotSetFunc(tv_detect_ncpu, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); @@ -371,7 +407,7 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) printf("ERROR: TmModuleGetByName for RespondReject failed\n"); exit(EXIT_FAILURE); } - Tm1SlotSetFunc(tv_rreject, tm_module, NULL); + TmSlotSetFuncAppend(tv_rreject, tm_module, NULL); TmThreadSetCPU(tv_rreject, REJECT_CPU_SET); @@ -399,5 +435,224 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - return 0; +#endif + SCReturnInt(0); +} + +int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) +{ + SCEnter(); + +/* We include only if AF_PACKET is enabled */ +#ifdef HAVE_AF_PACKET + + char tname[12]; + char qname[12]; + char queues[2048] = ""; + int afp_threads; + char *live_dev = NULL; + char *live_devc = NULL; + + RunModeInitialize(); + + TimeModeSetLive(); + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + /* always create at least one thread */ + int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + if (thread_max == 0) + thread_max = ncpus * threading_detect_ratio; + if (thread_max < 1) + thread_max = 1; + + int thread; + for (thread = 0; thread < thread_max; thread++) { + if (strlen(queues) > 0) + strlcat(queues, ",", sizeof(queues)); + + snprintf(qname, sizeof(qname),"pickup%"PRIu16, thread+1); + strlcat(queues, qname, sizeof(queues)); + } + SCLogDebug("queues %s", queues); + + if (ConfGet("af-packet.interface", &live_dev) == 0) { + SCLogError(SC_ERR_RUNMODE, "Failed retrieving " + "af-packet.interface from Conf"); + exit(EXIT_FAILURE); + } + SCLogDebug("live_dev %s", live_dev); + + + afp_threads = AFPConfGetThreads(); + SCLogInfo("Going to use %" PRId32 " AF_PACKET receive thread(s)", + afp_threads); + /* create the threads */ + for (thread = 0; thread < afp_threads; thread++) { + snprintf(tname, sizeof(tname), "RxAFP%"PRIu16, thread+1); + char *thread_name = SCStrdup(tname); + + ThreadVars *tv_receive = + TmThreadCreatePacketHandler(thread_name, + "packetpool", "packetpool", + queues, "flow", "varslot"); + if (tv_receive == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceiveAFP"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n"); + exit(EXIT_FAILURE); + } + live_devc = SCStrdup(live_dev); + TmSlotSetFuncAppend(tv_receive, tm_module, live_devc); + + tm_module = TmModuleGetByName("DecodeAFP"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodeAFP failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv_receive, tm_module, NULL); + + TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); + + if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + for (thread = 0; thread < thread_max; thread++) { + snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); + snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + + SCLogDebug("tname %s, qname %s", tname, qname); + + char *thread_name = SCStrdup(tname); + + ThreadVars *tv_detect_ncpu = + TmThreadCreatePacketHandler(thread_name, + qname, "flow", + "packetpool", "packetpool", + "varslot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); + + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); + + TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + + char *thread_group_name = SCStrdup("Detect"); + if (thread_group_name == NULL) { + printf("Error allocating memory\n"); + exit(EXIT_FAILURE); + } + tv_detect_ncpu->thread_group_name = thread_group_name; + + /* add outputs as well */ + SetupOutputs(tv_detect_ncpu); + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + +#endif /* HAVE_AF_PACKET */ + + SCReturnInt(0); +} + +/** + * \brief Single thread version of the AF_PACKET processing. + */ +int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) +{ + int nafp = LiveGetDeviceCount(); + char *afp_dev = NULL; + char *afp_devc = NULL; + + SCEnter(); +#ifdef HAVE_AF_PACKET + + if (nafp > 1) { + SCLogError(SC_ERR_RUNMODE, + "Can't use single runmode with multiple device"); + exit(EXIT_FAILURE); + } + + RunModeInitialize(); + TimeModeSetLive(); + + if (ConfGet("af-packet.interface", &afp_dev) == 0) { + SCLogError(SC_ERR_RUNMODE, "Failed retrieving " + "af-packet.interface from Conf"); + exit(EXIT_FAILURE); + } + + SCLogDebug("afp_dev %s", afp_dev); + afp_devc = SCStrdup(afp_dev); + + /* create the threads */ + ThreadVars *tv = TmThreadCreatePacketHandler("AFPacket", + "packetpool", "packetpool", + "packetpool", "packetpool", + "pktacqloop"); + if (tv == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + + TmModule *tm_module = TmModuleGetByName("ReceiveAFP"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv, tm_module, afp_devc); + + tm_module = TmModuleGetByName("DecodeAFP"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodeAFP failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); + + SetupOutputs(tv); + + if (TmThreadSpawn(tv) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + +#endif /* HAVE_AF_PACKET */ + SCReturnInt(0); } diff --git a/src/runmode-af-packet.h b/src/runmode-af-packet.h index 02344ff017..c1afea3577 100644 --- a/src/runmode-af-packet.h +++ b/src/runmode-af-packet.h @@ -20,11 +20,13 @@ * \author Eric Leblond */ -#ifndef __RUNMODE_AFP_H__ -#define __RUNMODE_AFP_H__ +#ifndef __RUNMODE_AF_PACKET_H__ +#define __RUNMODE_AF_PACKET_H__ int RunModeIdsAFPAuto(DetectEngineCtx *); +int RunModeIdsAFPSingle(DetectEngineCtx *); +int RunModeIdsAFPAutoFp(DetectEngineCtx *); void RunModeIdsAFPRegister(void); const char *RunModeAFPGetDefaultMode(void); -#endif /* __RUNMODE_AFP_H__ */ +#endif /* __RUNMODE_AF_PACKET_H__ */ diff --git a/src/source-af-packet.c b/src/source-af-packet.c index b535f46b17..fbdc842cb2 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -25,12 +25,13 @@ * Fanouts socket from David Miller: * we need to support the split of flow in different socket * option: - - packet_fanout type - - fanout ID ?? seems it could be useful - - protocol is the IEEE 802.3 protocol number in network order (filtering is great) - - runmode -> family of threads in parallel (acccount) - - add a new ratio or threads number (overwritten by cpu_affinity) - - add af_max_read_packets for batched reading + * - packet_fanout type + * - fanout ID ?? seems it could be useful + * - protocol is the IEEE 802.3 protocol number in network order (filtering + * is great) + * - runmode -> family of threads in parallel (acccount) + * - add a new ratio or threads number (overwritten by cpu_affinity) + * - add af_max_read_packets for batched reading * * architecture * loop with read @@ -40,10 +41,12 @@ * bind * must switch to promiscous mode -> use PACKET_MR_PROMISC socket option * - * \todo watch other interface event to detect suppression of the monitored interface + * \todo watch other interface event to detect suppression of the monitored + * interface */ #include "suricata-common.h" +#include "config.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" @@ -57,17 +60,64 @@ #include "util-debug.h" #include "util-error.h" #include "util-privs.h" +#include "util-optimize.h" #include "tmqh-packetpool.h" #include "source-af-packet.h" #include +#ifdef HAVE_AF_PACKET #include #include #include +#endif extern uint8_t suricata_ctl_flags; extern int max_pending_packets; +#define AFP_WORKER_MODE 0 +#define AFP_LOOP_MODE 1 + +#ifndef HAVE_AF_PACKET + +TmEcode NoAFPSupportExit(ThreadVars *, void *, void **); + +void TmModuleReceiveAFPRegister (void) { + tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; + tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit; + tmm_modules[TMM_RECEIVEAFP].Func = NULL; + tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; + tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVEAFP].cap_flags = 0; +} + +/** + * \brief Registration Function for DecodeAFP. + * \todo Unit tests are needed for this module. + */ +void TmModuleDecodeAFPRegister (void) { + tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; + tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit; + tmm_modules[TMM_DECODEAFP].Func = NULL; + tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; + tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; + tmm_modules[TMM_DECODEAFP].cap_flags = 0; +} + +/** + * \brief this function prints an error message and exits. + */ +TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data) +{ + SCLogError(SC_ERR_NO_AF_PACKET,"Error creating thread %s: you do not have " + "support for AF_PACKET enabled, on Linux host please recompile " + "with --enable-af-packet", tv->name); + exit(EXIT_FAILURE); +} + +#else /* We have AF_PACKET support */ + /** control how many packets we may read in one go */ static int afp_max_read_packets = 0; /** max packets < 65536 */ @@ -81,8 +131,6 @@ static int afp_max_read_packets = 0; #define POLL_TIMEOUT 100 -#define AFP_BUFSIZE 4096 - /** * \brief Structure to hold thread specific variables. */ @@ -103,19 +151,21 @@ typedef struct AFPThreadVars_ uint64_t bytes; uint32_t errs; - /* AFP buffer size */ - int AFP_buffer_size; + /* socket buffer size */ + int buffer_size; + + int cluster_id; + int cluster_type; ThreadVars *tv; + TmSlot *slot; Packet *in_p; Packet *array[AFP_FILE_MAX_PKTS]; uint16_t array_idx; - int fanout; - - char *data; /** Per function and thread data */ + uint8_t *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ } AFPThreadVars; @@ -123,6 +173,7 @@ TmEcode ReceiveAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *) TmEcode ReceiveAFPThreadInit(ThreadVars *, void *, void **); void ReceiveAFPThreadExitStats(ThreadVars *, void *); TmEcode ReceiveAFPThreadDeinit(ThreadVars *, void *); +TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot); TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **); TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); @@ -135,6 +186,7 @@ void TmModuleReceiveAFPRegister (void) { tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; tmm_modules[TMM_RECEIVEAFP].Func = ReceiveAFP; + tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; @@ -155,7 +207,26 @@ void TmModuleDecodeAFPRegister (void) { tmm_modules[TMM_DECODEAFP].cap_flags = 0; } -static int createsocket(AFPThreadVars *ptv, char *devname, int verbose); +static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose); + +int AFPConfGetThreads() +{ + int afp_threads = 1; + char *threadsstr = NULL; + + if (ConfGet("af-packet.threads", &threadsstr) != 1) { + afp_threads = 1; + } else { + if (threadsstr != NULL) { + afp_threads = (uint8_t)atoi(threadsstr); + } + } + if (afp_threads == 0) { + afp_threads = 1; + } + return afp_threads; +} + /** * \brief AF packet read function. @@ -166,11 +237,10 @@ static int createsocket(AFPThreadVars *ptv, char *devname, int verbose); * \param user pointer to AFPThreadVars * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success */ -TmEcode AFPRead(AFPThreadVars *ptv) +TmEcode AFPRead(AFPThreadVars *ptv, int mode) { Packet *p = NULL; /* XXX should try to use read that get directly to packet */ - uint8_t buf[AFP_BUFSIZE]; int offset = 0; int caplen; struct sockaddr_ll from; @@ -198,8 +268,8 @@ TmEcode AFPRead(AFPThreadVars *ptv) offset = SLL_HEADER_LEN; else offset = 0; - iov.iov_len = AFP_BUFSIZE - offset; - iov.iov_base = buf + offset; + iov.iov_len = ptv->datalen - offset; + iov.iov_base = ptv->data + offset; caplen = recvmsg(ptv->socket, &msg, MSG_TRUNC); @@ -208,14 +278,21 @@ TmEcode AFPRead(AFPThreadVars *ptv) errno); SCReturnInt(TM_ECODE_FAILED); } - if (ptv->array_idx == 0) { - p = ptv->in_p; - } else { - p = PacketGetFromQueueOrAlloc(); + switch(mode) { + case AFP_WORKER_MODE: + if (ptv->array_idx == 0) { + p = ptv->in_p; + } else { + p = PacketGetFromQueueOrAlloc(); + } + break; + case AFP_LOOP_MODE: + p = PacketGetFromQueueOrAlloc(); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, "AFPRread does not support this mode"); } - if (p == NULL) { - TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } @@ -232,23 +309,33 @@ TmEcode AFPRead(AFPThreadVars *ptv) /* add forged header */ if (ptv->cooked) { - SllHdr * hdrp = (SllHdr *)buf; + SllHdr * hdrp = (SllHdr *)ptv->data; /* XXX this is minimalist, but this seems enough */ hdrp->sll_protocol = from.sll_protocol; } p->datalink = ptv->datalink; SET_PKT_LEN(p, caplen + offset); - if (PacketCopyData(p, buf, GET_PKT_LEN(p)) == -1) { + if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } - SCLogDebug("pktlen: %" PRIu32 " (pkt %02x, pkt data %02x)", - GET_PKT_LEN(p), *pkt, *GET_PKT_DATA(p)); - - /* store the packet in our array */ - ptv->array[ptv->array_idx] = p; - ptv->array_idx++; + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", + GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + + switch(mode) { + case AFP_WORKER_MODE: + /* store the packet in our array */ + ptv->array[ptv->array_idx] = p; + ptv->array_idx++; + break; + case AFP_LOOP_MODE: + TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, "AFPRread does not support this mode"); + TmqhOutputPacketpool(ptv->tv, p); + } SCReturnInt(TM_ECODE_OK); } @@ -258,7 +345,7 @@ static int AFPTryReopen(AFPThreadVars *ptv) ptv->afp_state = AFP_STATE_DOWN; - afp_activate_r = createsocket(ptv, ptv->iface, 0); + afp_activate_r = AFPCreateSocket(ptv, ptv->iface, 0); if (afp_activate_r != 0) { return afp_activate_r; } @@ -268,6 +355,101 @@ static int AFPTryReopen(AFPThreadVars *ptv) return 0; } +/** + * \brief Main AF_PACKET reading Loop function + */ +TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) +{ + uint16_t packet_q_len = 0; + AFPThreadVars *ptv = (AFPThreadVars *)data; + TmSlot *s = (TmSlot *)slot; + ptv->slot = s->slot_next; + struct pollfd fds; + int r; + + SCEnter(); + + fds.fd = ptv->socket; + fds.events = POLLIN; + + while (1) { + /* Start by checking the state of our interface */ + if (unlikely(ptv->afp_state == AFP_STATE_DOWN)) { + int dbreak = 0; + do { + usleep(AFP_RECONNECT_TIMEOUT); + if (suricata_ctl_flags != 0) { + dbreak = 1; + break; + } + r = AFPTryReopen(ptv); + } while (r < 0); + if (dbreak == 1) + break; + } + + /* 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); + + r = poll(&fds, 1, POLL_TIMEOUT); + + if (suricata_ctl_flags != 0) { + break; + } + + if (r > 0 && + (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + if (fds.revents & (POLLHUP | POLLRDHUP)) { + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + continue; + } + if (fds.revents & POLLERR) { + char c; + /* Do a recv to get errno */ + if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1) + continue; /* what, no error? */ + SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", + errno, strerror(errno)); + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + continue; + } + if (fds.revents & POLLNVAL) { + SCLogError(SC_ERR_AFP_READ, "Invalid polling request"); + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + continue; + } + } else if (r > 0) { + /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ + r = AFPRead(ptv, AFP_LOOP_MODE); + if (r != TM_ECODE_OK) { + SCReturnInt(TM_ECODE_FAILED); + } + } else if ((r < 0) && (errno != EINTR)) { + SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", + errno, strerror(errno)); + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + continue; + } + } + + if (suricata_ctl_flags & SURICATA_STOP || + suricata_ctl_flags & SURICATA_KILL) { + SCReturnInt(TM_ECODE_FAILED); + } + + SCReturnInt(TM_ECODE_OK); +} + /** * \brief Recieves packets from an interface via AF_PACKET socket * @@ -322,19 +504,42 @@ TmEcode ReceiveAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe while (r >= 0) { r = poll(&fds, 1, POLL_TIMEOUT); - if (r > 0) { + if (suricata_ctl_flags != 0) { + break; + } - ret = AFPRead(ptv); - if (ret != TM_ECODE_OK) { - SCReturnInt(TM_ECODE_FAILED); + if (r > 0 && + (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + if (fds.revents & (POLLHUP | POLLRDHUP)) { + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + break; } - if (suricata_ctl_flags != 0) { + if (fds.revents & POLLERR) { + char c; + /* Do a recv to get errno */ + if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1) + continue; /* what, no error? */ + SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", + errno, strerror(errno)); + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; break; } + if (fds.revents & POLLNVAL) { + SCLogError(SC_ERR_AFP_READ, "Invalid polling request"); + close(ptv->socket); + ptv->afp_state = AFP_STATE_DOWN; + break; + } + } else if (r > 0) { + ret = AFPRead(ptv, AFP_WORKER_MODE); + if (ret != TM_ECODE_OK) { + SCReturnInt(TM_ECODE_FAILED); + } if (cnt++ >= afp_max_read_packets) break; - } - if (r < 0) { + } else if ((r < 0) && (errno != EINTR)) { int dbreak = 0; SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", errno, strerror(errno)); @@ -350,11 +555,8 @@ TmEcode ReceiveAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe r = 0; break; } - } - if ( r == 0) { - if (suricata_ctl_flags != 0) { - break; - } + } else if (r == 0) { + /* timeout condition */ if (cnt > 0) break; } @@ -371,9 +573,7 @@ TmEcode ReceiveAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe } if (r < 0) { - SCLogError(SC_ERR_AFP_DISPATCH, "error code %" PRId32, - r); - + SCLogError(SC_ERR_AFP_DISPATCH, "error code %" PRId32, r); SCReturnInt(TM_ECODE_OK); } @@ -384,12 +584,12 @@ TmEcode ReceiveAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe SCReturnInt(TM_ECODE_OK); } -static int getifnumbydev(int fd, const char *ifname, int verbose) +static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { if (verbose) @@ -401,12 +601,12 @@ static int getifnumbydev(int fd, const char *ifname, int verbose) return ifr.ifr_ifindex; } -static int getdevlinktype(int fd, const char *ifname) +static int AFPGetDevLinktype(int fd, const char *ifname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", @@ -414,10 +614,17 @@ static int getdevlinktype(int fd, const char *ifname) return -1; } - return ifr.ifr_hwaddr.sa_family; + switch (ifr.ifr_hwaddr.sa_family) { + case ARPHRD_LOOPBACK: + return LINKTYPE_ETHERNET; + case ARPHRD_PPP: + return LINKTYPE_RAW; + default: + return ifr.ifr_hwaddr.sa_family; + } } -static int createsocket(AFPThreadVars *ptv, char *devname, int verbose) +static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; struct packet_mreq sock_params; @@ -425,7 +632,7 @@ static int createsocket(AFPThreadVars *ptv, char *devname, int verbose) /* open socket */ ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (ptv->socket == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Coudn't create a AF_PACKET socket, error %s", strerror(errno)); + SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); return -1; } SCLogInfo("using interface %s", (char *)devname); @@ -433,10 +640,10 @@ static int createsocket(AFPThreadVars *ptv, char *devname, int verbose) memset(&bind_address, 0, sizeof(bind_address)); bind_address.sll_family = AF_PACKET; bind_address.sll_protocol = htons(ETH_P_ALL); - bind_address.sll_ifindex = getifnumbydev(ptv->socket, devname, verbose); + bind_address.sll_ifindex = AFPGetIfnumByDev(ptv->socket, devname, verbose); if (bind_address.sll_ifindex == -1) { if (verbose) - SCLogError(SC_ERR_AFP_CREATE, "Coudn't find iface %s", devname); + SCLogError(SC_ERR_AFP_CREATE, "Couldn't find iface %s", devname); return -1; } r = bind(ptv->socket, (struct sockaddr *)&bind_address, sizeof(bind_address)); @@ -463,23 +670,44 @@ static int createsocket(AFPThreadVars *ptv, char *devname, int verbose) r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, - "Coudn't switch iface %s to promiscuous, error %s", + "Couldn't switch iface %s to promiscuous, error %s", devname, strerror(errno)); + close(ptv->socket); return -1; } + /* set socket recv buffer size */ + if (ptv->buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); + if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, + &ptv->buffer_size, + sizeof(ptv->buffer_size)) == -1) { + SCLogError(SC_ERR_AFP_CREATE, + "Couldn't set buffer size to %d on iface %s, error %s", + ptv->buffer_size, + devname, + strerror(errno)); + close(ptv->socket); + return -1; + } + } + #ifdef HAVE_PACKET_FANOUT /* add binded socket to fanout group */ - if (ptv->fanout) { + if (AFPConfGetThreads() > 1) { uint32_t option = 0; - uint16_t mode = PACKET_FANOUT_HASH; - uint16_t id = 1; + uint16_t mode = ptv->cluster_type; + uint16_t id = ptv->cluster_id; option = (mode << 16) | (id & 0xffff); r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Coudn't set fanout mode, error %s", strerror(errno)); + close(ptv->socket); return -1; } } @@ -502,7 +730,11 @@ static int createsocket(AFPThreadVars *ptv, char *devname, int verbose) TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); int r; - int value; + intmax_t value; +#ifdef HAVE_PACKET_FANOUT + char *tmpclusterid; + char *tmpctype; +#endif /* use max_pending_packets as AFP read size unless it's bigger than * our size limit */ @@ -522,28 +754,81 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { ptv->tv = tv; ptv->cooked = 0; - strncpy(ptv->iface, initdata, AFP_IFACE_NAME_LENGTH); + strlcpy(ptv->iface, initdata, AFP_IFACE_NAME_LENGTH); ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; - r = createsocket(ptv, initdata, 1); + if ((ConfGetInt("af-packet.buffer-size", &value)) == 1) { + ptv->buffer_size = value; + } else { + ptv->buffer_size = 0; + } + +#ifdef HAVE_PACKET_FANOUT + ptv->cluster_type = PACKET_FANOUT_LB; + ptv->cluster_id = 1; + /* We only set cluster info if the number of reader threads is greater than 1 */ + if (AFPConfGetThreads() > 1) { + if (ConfGet("af-packet.cluster-id", &tmpclusterid) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"could not get af-packet.cluster-id"); + return TM_ECODE_FAILED; + } else { + ptv->cluster_id = (uint16_t)atoi(tmpclusterid); + SCLogDebug("Going to use cluster-id %" PRId32, ptv->cluster_id); + } + + if (ConfGet("af-packet.cluster-type", &tmpctype) != 1) { + SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get af-packet.cluster-type"); + return TM_ECODE_FAILED; + } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { + SCLogInfo("Using round-robin cluster mode for AF_PACKET (thread %s)", + ptv->tv->name); + ptv->cluster_type = PACKET_FANOUT_LB; + } else if (strcmp(tmpctype, "cluster_flow") == 0) { + /* In hash mode, we also ask for defragmentation needed to + * compute the hash */ + uint16_t defrag = 0; + SCLogInfo("Using flow cluster mode for AF_PACKET (thread %s)", + ptv->tv->name); + ConfGetBool("af-packet.defrag", (int *)&defrag); + if (defrag) { + SCLogInfo("Using defrag kernel functionnality for AF_PACKET (thread %s)", + ptv->tv->name); + defrag = PACKET_FANOUT_FLAG_DEFRAG; + } + ptv->cluster_type = PACKET_FANOUT_HASH | defrag; + } else if (strcmp(tmpctype, "cluster_cpu") == 0) { + SCLogInfo("Using cpu cluster mode for AF_PACKET (thread %s)", + ptv->tv->name); + ptv->cluster_type = PACKET_FANOUT_CPU; + } else { + SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); + return TM_ECODE_FAILED; + } + } +#endif + + r = AFPCreateSocket(ptv, initdata, 1); if (r < 0) { - SCLogError(SC_ERR_AFP_CREATE, "Coudn't init AF_PACKET socket"); + SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket"); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } - ptv->datalink = getdevlinktype(ptv->socket, ptv->iface); + ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); switch (ptv->datalink) { case ARPHRD_PPP: case ARPHRD_ATM: ptv->cooked = 1; } - if ((ConfGetBool("af-packet.fanout", &value)) == 1) { - ptv->fanout = value; - } else { - ptv->fanout = 0; +#define T_DATA_SIZE 70000 + ptv->data = SCMalloc(T_DATA_SIZE); + if (ptv->data == NULL) { + SCReturnInt(TM_ECODE_FAILED); } + ptv->datalen = T_DATA_SIZE; +#undef T_DATA_SIZE + *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -557,9 +842,8 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); AFPThreadVars *ptv = (AFPThreadVars *)data; -/** -* \todo Counter output -*/ + + SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** @@ -570,6 +854,12 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) { TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) { AFPThreadVars *ptv = (AFPThreadVars *)data; + if (ptv->data != NULL) { + SCFree(ptv->data); + ptv->data = NULL; + } + ptv->datalen = 0; + close(ptv->socket); SCReturnInt(TM_ECODE_OK); } @@ -643,4 +933,5 @@ TmEcode DecodeAFPThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_OK); } +#endif /* HAVE_AF_PACKET */ /* eof */ diff --git a/src/source-af-packet.h b/src/source-af-packet.h index e7119e487f..23a352d1e9 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -24,7 +24,20 @@ #ifndef __SOURCE_AFP_H__ #define __SOURCE_AFP_H__ +#ifndef HAVE_PACKET_FANOUT /* not defined if linux/if_packet.h trying to force */ +#define HAVE_PACKET_FANOUT 1 + +#define PACKET_FANOUT 18 + +#define PACKET_FANOUT_HASH 0 +#define PACKET_FANOUT_LB 1 +#define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 + +#endif /* HAVE_PACKET_FANOUT */ + void TmModuleReceiveAFPRegister (void); void TmModuleDecodeAFPRegister (void); +int AFPConfGetThreads(); #endif /* __SOURCE_AFP_H__ */ diff --git a/src/suricata.c b/src/suricata.c index e8211c3fb0..6b28ff3096 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -22,6 +22,7 @@ */ #include "suricata-common.h" +#include "config.h" #include #include @@ -393,8 +394,9 @@ void usage(const char *progname) printf("USAGE: %s\n\n", progname); printf("\t-c : path to configuration file\n"); printf("\t-i : run in pcap live mode\n"); -/* TODO add condition ifdef for af_packet */ +#ifdef HAVE_AF_PACKET printf("\t-a : run in af-packet mode\n"); +#endif printf("\t-F : bpf filter file\n"); printf("\t-r : run in pcap file/offline mode\n"); #ifdef NFQ @@ -489,6 +491,9 @@ void SCPrintBuildInfo(void) { #ifdef HAVE_PFRING strlcat(features, "PF_RING ", sizeof(features)); #endif +#ifdef HAVE_AF_PACKET + strlcat(features, "AF_PACKET ", sizeof(features)); +#endif #ifdef HAVE_DAG strlcat(features, "DAG ", sizeof(features)); #endif @@ -865,28 +870,30 @@ int main(int argc, char **argv) strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg)+1) : (sizeof(pcap_dev)))); break; case 'a': - /** \todo TODO fix parasiting of pcap mode */ +#ifdef HAVE_AF_PACKET if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_AFP_DEV; LiveRegisterDevice(optarg); } else if (run_mode == RUNMODE_AFP_DEV) { -#ifdef OS_WIN32 - SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " - "support is not (yet) supported on Windows."); - exit(EXIT_FAILURE); -#else SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple pcap devices to get packets is experimental."); + "multiple devices to get packets is experimental."); LiveRegisterDevice(optarg); -#endif } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); + "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } memset(pcap_dev, 0, sizeof(pcap_dev)); - strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg)+1) : (sizeof(pcap_dev)))); + strlcpy(pcap_dev, optarg, + ((strlen(optarg) < sizeof(pcap_dev)) ? + (strlen(optarg) + 1) : sizeof(pcap_dev))); +#else + SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " + "host, make sure to pass --enable-af-packet to " + "configure when building."); + exit(EXIT_FAILURE); +#endif break; case 'l': if (ConfSet("default-log-dir", optarg, 0) != 1) { @@ -894,8 +901,8 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } if (stat(optarg, &buf) != 0) { - SCLogError(SC_ERR_LOGDIR_CMDLINE, "The logging directory \"%s\" " - "supplied at the commandline (-l %s) doesn't " + SCLogError(SC_ERR_LOGDIR_CMDLINE, "The logging directory \"%s\"" + " supplied at the commandline (-l %s) doesn't " "exist. Shutting down the engine.", optarg, optarg); exit(EXIT_FAILURE); } diff --git a/src/util-device.c b/src/util-device.c index 0c3ccf6311..4850733f1a 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -81,5 +81,6 @@ char *LiveGetDevice(int number) { i++; } + return NULL; } diff --git a/src/util-device.h b/src/util-device.h index 4e1a3f6e31..66be217d12 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -#ifndef _UTIL_DEVICE_H -#define _UTIL_DEVICE_H 1 +#ifndef __UTIL_DEVICE_H__ +#define __UTIL_DEVICE_H__ #include "queue.h" @@ -31,4 +31,4 @@ int LiveRegisterDevice(char *dev); int LiveGetDeviceCount(void); char *LiveGetDevice(int number); -#endif /* _UTIL_DEVICE_H */ +#endif /* __UTIL_DEVICE_H__ */ diff --git a/src/util-error.c b/src/util-error.c index b913a08e00..c7edde4373 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -206,6 +206,9 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_RUNMODE); CASE_CODE (SC_ERR_SHUTDOWN); CASE_CODE (SC_ERR_INVALID_DIRECTION); + CASE_CODE (SC_ERR_AFP_CREATE); + CASE_CODE (SC_ERR_AFP_READ); + CASE_CODE (SC_ERR_AFP_DISPATCH); default: return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 805bd3d5f4..c5229c82ce 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -220,6 +220,7 @@ typedef enum { SC_ERR_AFP_CREATE, SC_ERR_AFP_READ, SC_ERR_AFP_DISPATCH, + SC_ERR_NO_AF_PACKET, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml b/suricata.yaml index 8398025b01..25185dea32 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -160,19 +160,24 @@ af-packet: # Number of receive threads (>1 will enable experimental flow pinned # runmode) threads: 1 - - # Default interface we will listen on. + # default network interface interface: eth0 - # Default clusterid. AF_PACKET will load balance packets based on flow. # All threads/processes that will participate need to have the same # clusterid. cluster-id: 99 - # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. # This is only supported for Linux kernel > 3.1 - # possible value are: "cluster_round_robin" and "cluster_flow" + # possible value are: + # * cluster_round_robin: round robin load balancing + # * cluster_flow: all packets of a given flow are send to the same socket + # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket cluster-type: cluster_round_robin + # In some fragmentation case, the hash can not be computed. If "defrag" is set + # to yes, the kernel will do the needed defragmentation before sending the packets. + defrag: yes + # recv buffer size, increase value could improve performance + # buffer-size: 32768 defrag: max-frags: 65535