/* Copyright (C) 2011 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 Eric Leblond * * AF_PACKET socket runmode * */ #include "suricata-common.h" #include "config.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-af-packet.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified-log.h" #include "alert-unified-alert.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-device.h" #include "util-runmodes.h" #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_autofp; } void RunModeIdsAFPRegister(void) { default_mode_auto = "auto"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto", "Multi threaded af-packet mode", RunModeIdsAFPAuto); 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 extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * \return a AFPIfaceConfig corresponding to the interface name */ void *ParseAFPConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *af_packet_node; AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; intmax_t value; int dispromisc; if (iface == NULL) { return NULL; } if (aconf == NULL) { return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 1; aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = PACKET_FANOUT_HASH; aconf->promisc = 1; /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { SCLogInfo("Unable to find af-packet config using default value"); return aconf; } if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); if (if_root == NULL) { SCLogInfo("Unable to find af-packet config for " "interface %s, using default value", iface); return aconf; } if (ConfGetChildValue(if_root, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (threadsstr != NULL) { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads == 0) { aconf->threads = 1; } if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValue(if_root, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type fron config"); } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->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 (iface %s)", aconf->iface); ConfGetChildValueBool(if_root, "defrag", (int *)&defrag); if (defrag) { SCLogInfo("Using defrag kernel functionnality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); return NULL; } if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) { aconf->buffer_size = value; } else { aconf->buffer_size = 0; } ConfGetChildValueBool(if_root, "disable-promisc", (int *)&dispromisc); if (dispromisc) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } return aconf; } int AFPConfigGeThreadsCount(void *conf) { AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; return afp->threads; } /** * \brief RunModeIdsAFPAuto set up the following thread packet handlers: * - Receive thread (from live iface) * - 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. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) { SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; RunModeInitialize(); TimeModeSetLive(); ConfGet("af-packet.live-interface", &live_dev); ret = RunModeSetLiveCaptureAuto(de_ctx, ParseAFPConfig, "ReceiveAFP", "DecodeAFP", "RecvAFP", live_dev); if (ret != 0) { printf("ERROR: Unable to start runmode\n"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPAuto initialised"); #endif SCReturnInt(0); } int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if AF_PACKET is enabled */ #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; RunModeInitialize(); TimeModeSetLive(); ConfGet("af-packet.live-interface", &live_dev); SCLogDebug("live_dev %s", live_dev); ret = RunModeSetLiveCaptureAutoFp(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "RxAFP", live_dev); if (ret != 0) { printf("ERROR: Unable to start runmode\n"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPAutoFp initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); } /** * \brief Single thread version of the AF_PACKET processing. */ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) { #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; #endif SCEnter(); #ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); ConfGet("af-packet.live-interface", &live_dev); ret = RunModeSetLiveCaptureSingle(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "AFPacket", live_dev); if (ret != 0) { printf("ERROR: Unable to start runmode\n"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPSingle initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); }