diff --git a/src/runmodes.c b/src/runmodes.c index 658a2fe6f8..80e93fd44c 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -11,6 +11,8 @@ #include "tm-threads.h" #include "util-debug.h" #include "util-time.h" +#include "util-cpu.h" +#include "util-byte.h" #include "conf.h" #include "queue.h" @@ -1851,3 +1853,791 @@ int RunModeIdsPfring4(DetectEngineCtx *de_ctx, char *iface) { return 0; } +/** + * \brief RunModeIdsPcapAuto set up the following thread packet handlers: + * - Receive thread (from iface pcap) + * - Decode thread + * - Stream thread + * - Detect: If we have only 1 cpu, it will setup one Detect thread + * If we have more than one, it will setup num_cpus - 1 + * starting from the second cpu available. + * - Respond/Reject thread + * - Outputs thread + * By default the threads will use the first cpu available + * except the Detection threads if we have more than one cpu + * + * \param de_ctx pointer to the Detection Engine + * \param iface pointer to the name of the interface from which we will + * fetch the packets + * \retval 0 if all goes well. (If any problem is detected the engine will + * exit()) + */ +int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx, char *iface) { + SCEnter(); + /* tname = Detect + cpuid, this is 11bytes length as max */ + char tname[12]; + uint16_t cpu = 0; + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + TimeModeSetLive(); + /* create the threads */ + ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcap","packetpool","packetpool","pickup-queue","simple","1slot_noinout"); + if (tv_receivepcap == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceivePcap"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivepcap,tm_module,(void *)iface); + + TmThreadSetCPUAffinity(tv_receivepcap, 0); + + if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue","simple","decode-queue1","simple","1slot"); + if (tv_decode1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Decode1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("DecodePcap"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodePcap failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_decode1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_decode1, 0); + + if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot"); + if (tv_stream1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Stream1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_stream1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_stream1, 0); + + if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + for (cpu = 0; cpu < ncpus; cpu++) { + snprintf(tname, 11,"Detect%"PRIu16, cpu); + if (tname == NULL) + break; + + char *thread_name = strdup(tname); + SCLogInfo("Assigning %s affinity to cpu %u", thread_name, cpu); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name,"stream-queue1","simple","verdict-queue","simple","1slot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_detect_ncpu,tm_module,(void *)de_ctx); + + TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); + /* If we have more than one core/cpu, the first Detect thread + * (at cpu 0) will have less priority (higher 'nice' value) + * In this case we will set the thread priority to +10 (default is 0) + */ + if (cpu == 0 && ncpus > 1) { + TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); + } + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject","verdict-queue","simple","alert-queue","simple","1slot"); + if (tv_rreject == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName for RespondReject failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_rreject,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_rreject, 0); + + if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", + "alert-queue", "simple", "packetpool", "packetpool", "varslot"); + SetupOutputs(tv_outputs); + + TmThreadSetCPUAffinity(tv_outputs, 0); + + if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + +/** + * \brief RunModeFilePcapAuto set up the following thread packet handlers: + * - Receive thread (from pcap file) + * - Decode thread + * - Stream thread + * - Detect: If we have only 1 cpu, it will setup one Detect thread + * If we have more than one, it will setup num_cpus - 1 + * starting from the second cpu available. + * - Outputs thread + * By default the threads will use the first cpu available + * except the Detection threads if we have more than one cpu + * + * \param de_ctx pointer to the Detection Engine + * \param file pointer to the name of the file from which we will fetch + * the packets + * \retval 0 if all goes well. (If any problem is detected the engine will + * exit()) + */ +int RunModeFilePcapAuto(DetectEngineCtx *de_ctx, char *file) { + SCEnter(); + char tname[12]; + uint16_t cpu = 0; + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + SCLogDebug("file %s", file); + TimeModeSetOffline(); + + /* create the threads */ + ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcapFile","packetpool","packetpool","pickup-queue","simple","1slot"); + if (tv_receivepcap == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceivePcapFile"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivepcap,tm_module,file); + + TmThreadSetCPUAffinity(tv_receivepcap, 0); + + if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue","simple","decode-queue1","simple","1slot"); + if (tv_decode1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Decode1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("DecodePcapFile"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodePcap failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_decode1,tm_module,NULL); + TmThreadSetCPUAffinity(tv_decode1, 0); + + if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot"); + if (tv_stream1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Stream1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_stream1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_stream1, 0); + + if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + for (cpu = 0; cpu < ncpus; cpu++) { + snprintf(tname, 11,"Detect%"PRIu16, cpu); + if (tname == NULL) + break; + + char *thread_name = strdup(tname); + SCLogInfo("Assigning %s affinity to cpu %u", thread_name, cpu); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name,"stream-queue1","simple","alert-queue1","simple","1slot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_detect_ncpu,tm_module,(void *)de_ctx); + + TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); + /* If we have more than one core/cpu, the first Detect thread + * (at cpu 0) will have less priority (higher 'nice' value) + * In this case we will set the thread priority to +10 (default is 0) + */ + if (cpu == 0 && ncpus > 1) { + TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); + } + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", + "alert-queue1", "simple", "packetpool", "packetpool", "varslot"); + SetupOutputs(tv_outputs); + + TmThreadSetCPUAffinity(tv_outputs, 0); + + if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + +/** + * \brief RunModeIpsIPFWAuto set up the following thread packet handlers: + * - Receive thread (from IPFW) + * - Decode thread + * - Stream thread + * - Detect: If we have only 1 cpu, it will setup one Detect thread + * If we have more than one, it will setup num_cpus - 1 + * starting from the second cpu available. + * - Veredict thread (IPFW) + * - Respond/Reject thread + * - Outputs thread + * By default the threads will use the first cpu available + * except the Detection threads if we have more than one cpu + * + * \param de_ctx pointer to the Detection Engine + * \retval 0 if all goes well. (If any problem is detected the engine will + * exit()) + */ +int RunModeIpsIPFWAuto(DetectEngineCtx *de_ctx) { + SCEnter(); + char tname[12]; + uint16_t cpu = 0; + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + TimeModeSetLive(); + + /* create the threads */ + ThreadVars *tv_receiveipfw = TmThreadCreatePacketHandler("ReceiveIPFW","packetpool","packetpool","pickup-queue","simple","1slot_noinout"); + + if (tv_receiveipfw == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceiveIPFW"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceiveIPFW\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receiveipfw,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_receiveipfw, 0); + + if (TmThreadSpawn(tv_receiveipfw) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue","simple","decode-queue1","simple","1slot"); + if (tv_decode1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Decode1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("DecodeIPFW"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodeIPFW failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_decode1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_decode1, 0); + + if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot"); + if (tv_stream1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Stream1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_stream1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_stream1, 0); + + if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + for (cpu = 0; cpu < ncpus; cpu++) { + snprintf(tname, 11,"Detect%"PRIu16, cpu); + if (tname == NULL) + break; + + char *thread_name = strdup(tname); + SCLogInfo("Assigning %s affinity to cpu %u", thread_name, cpu); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name,"stream-queue1","simple","verdict-queue","simple","1slot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_detect_ncpu,tm_module,(void *)de_ctx); + + TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); + /* If we have more than one core/cpu, the first Detect thread + * (at cpu 0) will have less priority (higher 'nice' value) + * In this case we will set the thread priority to +10 (default is 0) + */ + if (cpu == 0 && ncpus > 1) { + TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); + } + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + ThreadVars *tv_verdict = TmThreadCreatePacketHandler("Verdict","verdict-queue","simple","respond-queue","simple","1slot"); + if (tv_verdict == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("VerdictIPFW"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName VerdictIPFW failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_verdict,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_verdict, 0); + + if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject","respond-queue","simple","alert-queue1","simple","1slot"); + if (tv_rreject == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName for RespondReject failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_rreject,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_rreject, 0); + + if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", + "alert-queue1", "simple", "packetpool", "packetpool", "varslot"); + + TmThreadSetCPUAffinity(tv_outputs, 0); + SetupOutputs(tv_outputs); + if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + +/** + * \brief RunModeIpsNFQAuto set up the following thread packet handlers: + * - Receive thread (from NFQ) + * - Decode thread + * - Stream thread + * - Detect: If we have only 1 cpu, it will setup one Detect thread + * If we have more than one, it will setup num_cpus - 1 + * starting from the second cpu available. + * - Veredict thread (NFQ) + * - Respond/Reject thread + * - Outputs thread + * By default the threads will use the first cpu available + * except the Detection threads if we have more than one cpu + * + * \param de_ctx pointer to the Detection Engine + * \param nfqid pointer to the netfilter queue id + * \retval 0 if all goes well. (If any problem is detected the engine will + * exit()) + */ +int RunModeIpsNFQAuto(DetectEngineCtx *de_ctx, char *nfq_id) { + SCEnter(); + char tname[12]; + uint16_t cpu = 0; + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + TimeModeSetLive(); + + /* create the threads */ + ThreadVars *tv_receivenfq = TmThreadCreatePacketHandler("ReceiveNFQ","packetpool","packetpool","pickup-queue","simple","1slot_noinout"); + if (tv_receivenfq == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceiveNFQ"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceiveNFQ\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivenfq,tm_module,nfq_id); + TmThreadSetCPUAffinity(tv_receivenfq, 0); + + if (TmThreadSpawn(tv_receivenfq) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue","simple","decode-queue1","simple","1slot"); + if (tv_decode1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Decode1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("DecodeNFQ"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodeNFQ failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_decode1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_decode1, 0); + + if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot"); + if (tv_stream1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Stream1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_stream1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_stream1, 0); + + if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + for (cpu = 0; cpu < ncpus; cpu++) { + snprintf(tname, 11,"Detect%"PRIu16, cpu); + if (tname == NULL) + break; + + char *thread_name = strdup(tname); + SCLogInfo("Assigning %s affinity to cpu %u", thread_name, cpu); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name,"stream-queue1","simple","verdict-queue","simple","1slot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_detect_ncpu,tm_module,(void *)de_ctx); + + TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); + /* If we have more than one core/cpu, the first Detect thread + * (at cpu 0) will have less priority (higher 'nice' value) + * In this case we will set the thread priority to +10 (default is 0) + */ + if (cpu == 0 && ncpus > 1) { + TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); + } + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + ThreadVars *tv_verdict = TmThreadCreatePacketHandler("Verdict","verdict-queue","simple","respond-queue","simple","1slot"); + if (tv_verdict == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("VerdictNFQ"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName VerdictNFQ failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_verdict,tm_module,nfq_id); + + TmThreadSetCPUAffinity(tv_verdict, 0); + + if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject","respond-queue","simple","alert-queue1","simple","1slot"); + if (tv_rreject == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName for RespondReject failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_rreject,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_rreject, 0); + + if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", + "alert-queue1", "simple", "packetpool", "packetpool", "varslot"); + SetupOutputs(tv_outputs); + TmThreadSetCPUAffinity(tv_outputs, 0); + if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + +/** + * \brief RunModeIdsPfringAuto set up the following thread packet handlers: + * - Receive thread (from pfring) + * - Decode thread + * - Stream thread + * - Detect: If we have only 1 cpu, it will setup one Detect thread + * If we have more than one, it will setup num_cpus - 1 + * starting from the second cpu available. + * - Respond/Reject thread + * - Outputs thread + * By default the threads will use the first cpu available + * except the Detection threads if we have more than one cpu + * + * \param de_ctx pointer to the Detection Engine + * \param iface pointer to the name of the network interface to listen packets + * \retval 0 if all goes well. (If any problem is detected the engine will + * exit()) + */ +int RunModeIdsPfringAuto(DetectEngineCtx *de_ctx, char *iface) { + SCEnter(); + char tname[12]; + uint16_t cpu = 0; + + /* Available cpus */ + uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + + TimeModeSetLive(); + + /* create the threads */ + ThreadVars *tv_receivepfring = TmThreadCreatePacketHandler("ReceivePfring","packetpool","packetpool","pickup-queue1","simple","1slot"); + if (tv_receivepfring == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + TmModule *tm_module = TmModuleGetByName("ReceivePfring"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceivePfring\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivepfring,tm_module,(void *)iface); + + TmThreadSetCPUAffinity(tv_receivepfring, 0); + + if (TmThreadSpawn(tv_receivepfring) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue1","simple","decode-queue1","simple","1slot"); + if (tv_decode1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Decode1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("DecodePfring"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName DecodePfring failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_decode1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_decode1, 0); + + if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot"); + if (tv_stream1 == NULL) { + printf("ERROR: TmThreadsCreate failed for Stream1\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("StreamTcp"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_stream1,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_stream1, 0); + + if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + for (cpu = 0; cpu < ncpus; cpu++) { + snprintf(tname, 11,"Detect%"PRIu16, cpu); + if (tname == NULL) + break; + + char *thread_name = strdup(tname); + SCLogInfo("Assigning %s affinity to cpu %u", thread_name, cpu); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name,"stream-queue1","simple","verdict-queue","simple","1slot"); + if (tv_detect_ncpu == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("Detect"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName Detect failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_detect_ncpu,tm_module,(void *)de_ctx); + + TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); + /* If we have more than one core/cpu, the first Detect thread + * (at cpu 0) will have less priority (higher 'nice' value) + * In this case we will set the thread priority to +10 (default is 0) + */ + if (cpu == 0 && ncpus > 1) { + TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); + } + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } + + ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject","verdict-queue","simple","alert-queue1","simple","1slot"); + if (tv_rreject == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName for RespondReject failed\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_rreject,tm_module,NULL); + + TmThreadSetCPUAffinity(tv_rreject, 0); + + if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", + "alert-queue1", "simple", "packetpool", "packetpool", "varslot"); + SetupOutputs(tv_outputs); + + TmThreadSetCPUAffinity(tv_outputs, 0); + + if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + diff --git a/src/runmodes.h b/src/runmodes.h index a8b4e99a1c..bff18a6b56 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -6,18 +6,24 @@ void RunModeInitializeOutputs(void); int RunModeIdsPcap(DetectEngineCtx *, char *); int RunModeIdsPcap2(DetectEngineCtx *, char *); int RunModeIdsPcap3(DetectEngineCtx *, char *); +int RunModeIdsPcapAuto(DetectEngineCtx *, char *); int RunModeIpsNFQ(DetectEngineCtx *, char *); +int RunModeIpsNFQAuto(DetectEngineCtx *, char *); int RunModeFilePcap(DetectEngineCtx *, char *); int RunModeFilePcap2(DetectEngineCtx *, char *); +int RunModeFilePcapAuto(DetectEngineCtx *, char *); int RunModeIdsPfring(DetectEngineCtx *, char *); int RunModeIdsPfring2(DetectEngineCtx *, char *); int RunModeIdsPfring3(DetectEngineCtx *, char *); int RunModeIdsPfring4(DetectEngineCtx *, char *); +int RunModeIdsPfringAuto(DetectEngineCtx *, char *); int RunModeIpsIPFW(DetectEngineCtx *); +int RunModeIpsIPFWAuto(DetectEngineCtx *); + void RunModeShutDown(void); #endif /* __RUNMODES_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 4a69059b9c..332d0ebc2e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -777,30 +777,37 @@ int main(int argc, char **argv) RunModeInitializeOutputs(); if (run_mode == MODE_PCAP_DEV) { //RunModeIdsPcap3(de_ctx, pcap_dev); - RunModeIdsPcap2(de_ctx, pcap_dev); + //RunModeIdsPcap2(de_ctx, pcap_dev); //RunModeIdsPcap(de_ctx, pcap_dev); + RunModeIdsPcapAuto(de_ctx, pcap_dev); } else if (run_mode == MODE_PCAP_FILE) { - RunModeFilePcap(de_ctx, pcap_file); + //RunModeFilePcap(de_ctx, pcap_file); //RunModeFilePcap2(de_ctx, pcap_file); + RunModeFilePcapAuto(de_ctx, pcap_file); } else if (run_mode == MODE_PFRING) { //RunModeIdsPfring3(de_ctx, pfring_dev); //RunModeIdsPfring2(de_ctx, pfring_dev); //RunModeIdsPfring(de_ctx, pfring_dev); - RunModeIdsPfring4(de_ctx, pfring_dev); + //RunModeIdsPfring4(de_ctx, pfring_dev); + RunModeIdsPfringAuto(de_ctx, pfring_dev); } else if (run_mode == MODE_NFQ) { - RunModeIpsNFQ(de_ctx, nfq_id); + //RunModeIpsNFQ(de_ctx, nfq_id); + RunModeIpsNFQAuto(de_ctx, nfq_id); } else if (run_mode == MODE_IPFW) { - RunModeIpsIPFW(de_ctx); + //RunModeIpsIPFW(de_ctx); + RunModeIpsIPFWAuto(de_ctx); } else { SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting"); exit(EXIT_FAILURE); } + TmThreadPrioSummary("Suricata main()"); + /* Spawn the flow manager thread */ FlowManagerThreadSpawn(); diff --git a/src/threads.h b/src/threads.h index 0911f6feac..30496b09f2 100644 --- a/src/threads.h +++ b/src/threads.h @@ -10,6 +10,20 @@ #ifdef OS_FREEBSD #include +#define PRIO_LOW 20 +#define PRIO_MEDIUM 31 +#define PRIO_HIGH 40 +#else +#ifdef OS_DARWIN +#include +#define PRIO_LOW 20 +#define PRIO_MEDIUM 31 +#define PRIO_HIGH 40 +#else /* LINUX */ +#define PRIO_LOW 40 +#define PRIO_MEDIUM 50 +#define PRIO_HIGH 60 +#endif /* DARWIN */ #endif /* OS_FREEBSD */ #include @@ -37,12 +51,21 @@ tid; \ }) #else +#ifdef OS_DARWIN +#define SCGetThreadIdLong(...) ({ \ + thread_port_t tpid; \ + tpid = mach_thread_self(); \ + u_long tid = (u_long)tpid; \ + tid; \ +}) +#else #define SCGetThreadIdLong(...) ({ \ pid_t tmpthid; \ tmpthid = syscall(SYS_gettid); \ u_long tid = (u_long)tmpthid; \ tid; \ }) +#endif /* OS DARWIN*/ #endif /* OS FREEBSD */ /** Mutex Functions */ diff --git a/src/threadvars.h b/src/threadvars.h index 2d6e9da93d..8103cb1dc0 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -55,8 +55,9 @@ typedef struct ThreadVars_ { void *(*tm_func)(void *); void *tm_slots; - char set_cpu_affinity; /** bool: 0 no, 1 yes */ - int cpu_affinity; /** cpu or core number to set affinity to */ + uint8_t thread_setup_flags; + uint16_t cpu_affinity; /** cpu or core number to set affinity to */ + int thread_priority; /** priority (real time) for this thread. Look at threads.h */ /* the perf counter context and the perf counter array */ SCPerfContext sc_perf_pctx; @@ -69,5 +70,9 @@ typedef struct ThreadVars_ { struct ThreadVars_ *prev; } ThreadVars; +/** Thread setup flags: */ +#define THREAD_SET_AFFINITY 0x01 /** CPU/Core affinity */ +#define THREAD_SET_PRIORITY 0x02 /** Real time priority */ + #endif /* __THREADVARS_H__ */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 1bd1fbbea8..d7ff34ad82 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -14,6 +14,9 @@ #include "tmqh-packetpool.h" #include "threads.h" #include "util-debug.h" +#include +#include + #ifdef OS_FREEBSD #include @@ -32,7 +35,7 @@ #endif /* OS_FREEBSD */ /* prototypes */ -static int SetCPUAffinity(int cpu); +static int SetCPUAffinity(uint16_t cpu); /* root of the threadvars list */ ThreadVars *tv_root[TVT_MAX] = { NULL }; @@ -115,8 +118,8 @@ void *TmThreadsSlot1NoIn(void *td) { char run = 1; TmEcode r = TM_ECODE_OK; - if (tv->set_cpu_affinity == 1) - SetCPUAffinity(tv->cpu_affinity); + if (tv->thread_setup_flags != 0) + TmThreadSetupOptions(tv); if (s->s.SlotThreadInit != NULL) { r = s->s.SlotThreadInit(tv, s->s.slot_initdata, &s->s.slot_data); @@ -179,8 +182,8 @@ void *TmThreadsSlot1NoOut(void *td) { char run = 1; TmEcode r = TM_ECODE_OK; - if (tv->set_cpu_affinity == 1) - SetCPUAffinity(tv->cpu_affinity); + if (tv->thread_setup_flags != 0) + TmThreadSetupOptions(tv); if (s->s.SlotThreadInit != NULL) { r = s->s.SlotThreadInit(tv, s->s.slot_initdata, &s->s.slot_data); @@ -236,8 +239,8 @@ void *TmThreadsSlot1NoInOut(void *td) { char run = 1; TmEcode r = TM_ECODE_OK; - if (tv->set_cpu_affinity == 1) - SetCPUAffinity(tv->cpu_affinity); + if (tv->thread_setup_flags != 0) + TmThreadSetupOptions(tv); SCLogDebug("%s starting", tv->name); @@ -297,8 +300,8 @@ void *TmThreadsSlot1(void *td) { char run = 1; TmEcode r = TM_ECODE_OK; - if (tv->set_cpu_affinity == 1) - SetCPUAffinity(tv->cpu_affinity); + if (tv->thread_setup_flags != 0) + TmThreadSetupOptions(tv); SCLogDebug("%s starting", tv->name); @@ -414,8 +417,8 @@ void *TmThreadsSlotVar(void *td) { TmEcode r = TM_ECODE_OK; TmSlot *slot = NULL; - if (tv->set_cpu_affinity == 1) - SetCPUAffinity(tv->cpu_affinity); + if (tv->thread_setup_flags != 0) + TmThreadSetupOptions(tv); //printf("TmThreadsSlot1: %s starting\n", tv->name); @@ -575,10 +578,14 @@ void TmVarSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) { } } -/* called from the thread */ -static int SetCPUAffinity(int cpu) { +/** + * \brief Set the thread affinity on the calling thread + * \param cpuid id of the core/cpu to setup the affinity + * \retval 0 if all goes well; -1 if something is wrong + */ +static int SetCPUAffinity(uint16_t cpuid) { - printf("Setting CPU Affinity for thread %lu to CPU %" PRId32 "\n", SCGetThreadIdLong(), cpu); + int cpu = (int)cpuid; cpu_set_t cs; @@ -596,17 +603,73 @@ static int SetCPUAffinity(int cpu) { if (r != 0) { printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, strerror(errno)); + return -1; } + SCLogInfo("CPU Affinity for thread %lu set to CPU %" PRId32, SCGetThreadIdLong(), cpu); return 0; } -TmEcode TmThreadSetCPUAffinity(ThreadVars *tv, int cpu) { - tv->set_cpu_affinity = 1; + +/** + * \brief Set the thread options (thread priority) + * \param tv pointer to the ThreadVars to setup the thread priority + * \retval TM_ECOE_OK + */ +TmEcode TmThreadSetThreadPriority(ThreadVars *tv, int prio) { + tv->thread_setup_flags |= THREAD_SET_PRIORITY; + tv->thread_priority = prio; + return TM_ECODE_OK; +} + +/** + * \brief Print a summary of the default thread priority, and the min and max values + * supported by the system/policy + */ +void TmThreadPrioSummary(char *tname) +{ + SCEnter(); + pthread_attr_t attr; + pthread_attr_init(&attr); + int my_policy; + struct sched_param my_param; + + pthread_getschedparam (pthread_self (), &my_policy, &my_param); + + SCLogInfo("at %s, threading policy: %s, priority %"PRId32"\n", tname, + (my_policy == SCHED_FIFO ? "Fifo" : (my_policy == SCHED_RR ? "RR" + : (my_policy == SCHED_OTHER ? "Other" : "unknown"))), + my_param.sched_priority); + + SCLogInfo("at %s, Min prio: %"PRId32" Max prio: %"PRId32"", tname, sched_get_priority_min(my_policy), sched_get_priority_max(my_policy)); +} + + +/** + * \brief Set the thread options (cpu affinity) + * \param tv pointer to the ThreadVars to setup the affinity + * \retval TM_ECOE_OK + */ +TmEcode TmThreadSetCPUAffinity(ThreadVars *tv, uint16_t cpu) { + tv->thread_setup_flags |= THREAD_SET_AFFINITY; tv->cpu_affinity = cpu; return TM_ECODE_OK; } +/** + * \brief Set the thread options (cpu affinitythread) + * Priority should be already set by pthread_create + * \param tv pointer to the ThreadVars of the calling thread + */ +TmEcode TmThreadSetupOptions(ThreadVars *tv) { + if (tv->thread_setup_flags & THREAD_SET_AFFINITY) { + SCLogInfo("Setting affinity for \"%s\" Module to cpu/core %"PRIu16", thread id %lu", tv->name, tv->cpu_affinity, SCGetThreadIdLong()); + SetCPUAffinity(tv->cpu_affinity); + } + TmThreadPrioSummary(tv->name); + return TM_ECODE_OK; +} + /** * \brief Creates and returns the TV instance for a new thread. * @@ -879,6 +942,8 @@ void TmThreadKillThreads(void) { TmEcode TmThreadSpawn(ThreadVars *tv) { pthread_attr_t attr; + struct sched_param param; + int ret = 0; if (tv->tm_func == NULL) { printf("ERROR: no thread function set\n"); @@ -887,6 +952,38 @@ TmEcode TmThreadSpawn(ThreadVars *tv) /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); + + pthread_attr_getschedparam(&attr, ¶m); + + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + if (ret != 0) { + SCLogInfo("Error setting thread explicit Scheduling"); + } else { + + if (tv->thread_setup_flags & THREAD_SET_PRIORITY) { + /* Then we need to change the policy. SCHED_OTHER doesn't allow + * to change it. So we have to choose SCHED_RR or SCHED_FIFO + */ + + + ret = pthread_attr_setschedpolicy(&attr, SCHED_RR); + if (ret != 0) { + SCLogInfo("Error setting thread policy to SCHED_RR"); + } else { + SCLogInfo("Thread policy SCHED_RR set for thread %s. Old prio: %"PRId32, tv->name, param.sched_priority); + + param.sched_priority = tv->thread_priority; + ret = pthread_attr_setschedparam(&attr, ¶m); + if (ret != 0) { + SCLogInfo("Error setting thread priority"); + /* Get the old default priority */ + pthread_attr_getschedparam(&attr, ¶m); + } else { + SCLogInfo("Thread priority %"PRId32" set for thread %s", tv->thread_priority, tv->name); + } + } + } + } pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int rc = pthread_create(&tv->t, &attr, tv->tm_func, (void *)tv); diff --git a/src/tm-threads.h b/src/tm-threads.h index 51aa57782f..d22660ac8a 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -36,7 +36,13 @@ void TmThreadKillThreads(void); void TmThreadAppend(ThreadVars *, int); -TmEcode TmThreadSetCPUAffinity(ThreadVars *, int); +TmEcode TmThreadSetCPUAffinity(ThreadVars *, uint16_t); + +TmEcode TmThreadSetThreadPriority(ThreadVars *, int); + +TmEcode TmThreadSetupOptions(ThreadVars *); + +void TmThreadPrioSummary(char *); void TmThreadInitMC(ThreadVars *);