af-packet: multi interface support

This patch adds multi interface support to AF_PACKET. A structure
is used at thread creation to give all needed information to the
input module. Parsing of the options is done in runmode preparation
through a dedicated function which return the configuration in a
structure usable by thread creation.
remotes/origin/master-1.1.x
Eric Leblond 15 years ago committed by Victor Julien
parent 18c6503a08
commit fbca1a4e6b

@ -624,12 +624,10 @@ ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *va
ConfNode *child;
TAILQ_FOREACH(child, &base->head, next) {
SCLogWarning(SC_ERR_MEM_ALLOC,"conf:found one child %s:%s", child->name, child->val);
if (!strncmp(child->val, key, sizeof(child->val))) {
ConfNode *subchild;
TAILQ_FOREACH(subchild, &child->head, next) {
if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) {
SCLogWarning(SC_ERR_MEM_ALLOC,"was looking for %s:%s", subchild->name, subchild->val);
return child;
}
}

@ -56,19 +56,7 @@ static const char *default_mode_autofp = NULL;
const char *RunModeAFPGetDefaultMode(void)
{
#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
return default_mode_autofp;
}
void RunModeIdsAFPRegister(void)
@ -89,6 +77,105 @@ void RunModeIdsAFPRegister(void)
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
*/
AFPIfaceConfig *ParseAFPConfig(char *iface)
{
char *threadsstr = NULL;
ConfNode *if_root;
ConfNode *af_packet_node;
AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
char *tmpclusterid;
char *tmpctype;
intmax_t value;
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;
/* 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;
}
return aconf;
}
/**
* \brief RunModeIdsAFPAuto set up the following thread packet handlers:
* - Receive thread (from live iface)
@ -127,15 +214,26 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
if (nlive == 1) {
char *live_dev = NULL;
char *live_devc = NULL;
if (ConfGet("af-packet.interface", &live_dev) == 0) {
AFPIfaceConfig *aconf;
/* TODO be clever than that */
if (ConfGet("af-packet.live-interface", &live_dev) == 0) {
SCLogError(SC_ERR_RUNMODE, "Failed retrieving "
"af-packet.interface from Conf");
"interface from command line");
exit(EXIT_FAILURE);
}
SCLogDebug("live_dev %s", live_dev);
live_devc = SCStrdup(live_dev);
if (live_dev == NULL) {
printf("Failed to lookup live dev\n");
exit(EXIT_FAILURE);
}
SCLogDebug("live_dev %s", live_dev);
aconf = ParseAFPConfig(live_dev);
if (aconf == NULL) {
printf("Failed to allocate config\n");
exit(EXIT_FAILURE);
}
/* create the threads */
ThreadVars *tv_receiveafp =
@ -152,7 +250,7 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n");
exit(EXIT_FAILURE);
}
TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)live_devc);
TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)aconf);
TmThreadSetCPU(tv_receiveafp, RECEIVE_CPU_SET);
@ -166,16 +264,22 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
for (thread = 0; thread < nlive; thread++) {
char *live_dev = LiveGetDevice(thread);
char *tnamec = NULL;
char *live_devc = NULL;
AFPIfaceConfig *aconf;
if (live_dev == NULL) {
printf("Failed to lookup live dev %d\n", thread);
exit(EXIT_FAILURE);
}
SCLogDebug("live_dev %s", live_dev);
aconf = ParseAFPConfig(live_dev);
if (aconf == NULL) {
printf("Failed to allocate config %d\n", thread);
exit(EXIT_FAILURE);
}
snprintf(tname, sizeof(tname),"RecvAFP-%s", live_dev);
tnamec = SCStrdup(tname);
live_devc = SCStrdup(live_dev);
/* create the threads */
ThreadVars *tv_receiveafp =
@ -192,7 +296,7 @@ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n");
exit(EXIT_FAILURE);
}
TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)live_devc);
TmSlotSetFuncAppend(tv_receiveafp, tm_module, (void *)aconf);
TmThreadSetCPU(tv_receiveafp, RECEIVE_CPU_SET);
@ -449,25 +553,22 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx)
char tname[12];
char qname[12];
char queues[2048] = "";
int afp_threads;
int thread;
char *live_dev = NULL;
char *live_devc = NULL;
RunModeInitialize();
TimeModeSetLive();
/* Available cpus */
uint16_t ncpus = UtilCpuGetNumProcessorsOnline();
/* always create at least one thread */
int nlive = LiveGetDeviceCount();
int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET);
/* always create at least one thread */
if (thread_max == 0)
thread_max = ncpus * threading_detect_ratio;
if (thread_max < 1)
thread_max = 1;
int thread;
RunModeInitialize();
TimeModeSetLive();
for (thread = 0; thread < thread_max; thread++) {
if (strlen(queues) > 0)
strlcat(queues, ",", sizeof(queues));
@ -477,50 +578,112 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx)
}
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);
if (nlive == 1) {
AFPIfaceConfig *aconf;
int afp_thread;
ThreadVars *tv_receive =
TmThreadCreatePacketHandler(thread_name,
"packetpool", "packetpool",
queues, "flow", "varslot");
if (tv_receive == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
if (ConfGet("af-packet.live-interface", &live_dev) == 0) {
SCLogError(SC_ERR_RUNMODE, "Failed retrieving "
"interface from command line");
exit(EXIT_FAILURE);
}
TmModule *tm_module = TmModuleGetByName("ReceiveAFP");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName failed for ReceiveAFP\n");
SCLogDebug("live_dev %s", live_dev);
aconf = ParseAFPConfig(live_dev);
if (aconf == NULL) {
printf("Failed to allocate config %d\n", thread);
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);
SCLogInfo("Going to use %" PRId32 " AF_PACKET receive thread(s)",
aconf->threads);
/* create the threads */
for (afp_thread = 0; afp_thread < aconf->threads; afp_thread++) {
snprintf(tname, sizeof(tname), "RxAFP%"PRIu16, afp_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);
}
TmSlotSetFuncAppend(tv_receive, tm_module, aconf);
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);
}
}
TmSlotSetFuncAppend(tv_receive, tm_module, NULL);
} else { /* Multiple input device */
SCLogInfo("Using %d live device(s).", nlive);
int lthread;
TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET);
for (lthread = 0; lthread < nlive; lthread++) {
char *live_dev = LiveGetDevice(lthread);
AFPIfaceConfig *aconf;
if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
if (live_dev == NULL) {
printf("Failed to lookup live dev %d\n", lthread);
exit(EXIT_FAILURE);
}
SCLogDebug("live_dev %s", live_dev);
aconf = ParseAFPConfig(live_dev);
if (aconf == NULL) {
printf("Failed to allocate config %d\n", lthread);
exit(EXIT_FAILURE);
}
for (thread = 0; thread < aconf->threads; thread++) {
snprintf(tname, sizeof(tname), "RxAFP%s%"PRIu16, live_dev, 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);
}
TmSlotSetFuncAppend(tv_receive, tm_module, aconf);
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);
}
}
}
}
@ -599,9 +762,9 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx)
RunModeInitialize();
TimeModeSetLive();
if (ConfGet("af-packet.interface", &afp_dev) == 0) {
if (ConfGet("af-packet.live-interface", &afp_dev) == 0) {
SCLogError(SC_ERR_RUNMODE, "Failed retrieving "
"af-packet.interface from Conf");
"interface from command line");
exit(EXIT_FAILURE);
}

@ -157,6 +157,8 @@ typedef struct AFPThreadVars_
int cluster_id;
int cluster_type;
int threads;
ThreadVars *tv;
TmSlot *slot;
@ -209,24 +211,6 @@ void TmModuleDecodeAFPRegister (void) {
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.
@ -697,7 +681,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
#ifdef HAVE_PACKET_FANOUT
/* add binded socket to fanout group */
if (AFPConfGetThreads() > 1) {
if (ptv->threads > 1) {
uint32_t option = 0;
uint16_t mode = ptv->cluster_type;
uint16_t id = ptv->cluster_id;
@ -730,11 +714,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
SCEnter();
int r;
intmax_t value;
#ifdef HAVE_PACKET_FANOUT
char *tmpclusterid;
char *tmpctype;
#endif
AFPIfaceConfig *afpconfig = initdata;
/* use max_pending_packets as AFP read size unless it's bigger than
* our size limit */
@ -754,60 +734,24 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
ptv->tv = tv;
ptv->cooked = 0;
strlcpy(ptv->iface, initdata, AFP_IFACE_NAME_LENGTH);
strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH);
ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0';
if ((ConfGetInt("af-packet.buffer-size", &value)) == 1) {
ptv->buffer_size = value;
} else {
ptv->buffer_size = 0;
}
ptv->buffer_size = afpconfig->buffer_size;
ptv->threads = 1;
#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;
}
if (afpconfig->threads > 1) {
ptv->cluster_id = afpconfig->cluster_id;
ptv->cluster_type = afpconfig->cluster_type;
ptv->threads = afpconfig->threads;
}
#endif
r = AFPCreateSocket(ptv, initdata, 1);
r = AFPCreateSocket(ptv, ptv->iface, 1);
if (r < 0) {
SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket");
SCFree(ptv);
@ -831,6 +775,9 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
*data = (void *)ptv;
/* we've received a single use structure, we can free it */
SCFree(initdata);
SCReturnInt(TM_ECODE_OK);
}

@ -36,6 +36,21 @@
#endif /* HAVE_PACKET_FANOUT */
#define AFP_FILE_MAX_PKTS 256
#define AFP_IFACE_NAME_LENGTH 48
typedef struct AFPIfaceConfig_
{
char iface[AFP_IFACE_NAME_LENGTH];
/* number of threads */
int threads;
/* socket buffer size */
int buffer_size;
/* cluster param */
int cluster_id;
int cluster_type;
} AFPIfaceConfig;
void TmModuleReceiveAFPRegister (void);
void TmModuleDecodeAFPRegister (void);
int AFPConfGetThreads();

@ -1423,7 +1423,7 @@ int main(int argc, char **argv)
PfringLoadConfig();
#endif /* HAVE_PFRING */
} else if (run_mode == RUNMODE_AFP_DEV) {
if (ConfSet("af-packet.interface", pcap_dev, 0) != 1) {
if (ConfSet("af-packet.live-interface", pcap_dev, 0) != 1) {
fprintf(stderr, "ERROR: Failed to set af-packet.interface\n");
exit(EXIT_FAILURE);
}

Loading…
Cancel
Save