af-packet: test if fanout is supported before use

Older system may pretend they can support FANOUT but then fail to
work at runtime. CentOS6 is an example of this. It would fail to
start up with the default configuration with errors like:

[15770] 21/6/2016 -- 16:00:13 - (tm-threads.c:2168) <Notice> (TmThreadWaitOnThreadInit) -- all 4 packet processing threads, 4 management threads initialized, engine started.
[15785] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) <Error> (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available
[15785] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) <Error> (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error
[15770] 21/6/2016 -- 16:00:13 - (suricata.c:2664) <Notice> (main) -- Signal Received.  Stopping engine.
[15787] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) <Error> (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available
[15788] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) <Error> (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available
[15786] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1907) <Error> (AFPCreateSocket) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Coudn't set fanout mode, error Protocol not available
[15789] 21/6/2016 -- 16:00:13 - (flow-manager.c:693) <Perf> (FlowManager) -- 0 new flows, 0 established flows were timed out, 0 flows in closed state
[15787] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) <Error> (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error
[15788] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) <Error> (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error
[15786] 21/6/2016 -- 16:00:13 - (source-af-packet.c:1337) <Error> (ReceiveAFPLoop) -- [ERRCODE: SC_ERR_AFP_CREATE(190)] - Couldn't init AF_PACKET socket, fatal error

This patch adds a test that if run before the number of threads
is determined. If the test fails, only 1 thread is created.
pull/2164/head
Victor Julien 9 years ago
parent ab65b6f83b
commit 402bdf9b2b

@ -387,6 +387,19 @@ void *ParseAFPConfig(const char *iface)
finalize: finalize:
/* if the number of threads is not 1, we need to first check if fanout
* functions on this system. */
if (aconf->threads != 1) {
if (AFPIsFanoutSupported() == 0) {
if (aconf->threads != 0) {
SCLogNotice("fanout not supported on this system, falling "
"back to 1 capture thread");
}
aconf->threads = 1;
}
}
/* try to automagically set the proper number of threads */
if (aconf->threads == 0) { if (aconf->threads == 0) {
int rss_queues; int rss_queues;
aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); aconf->threads = (int)UtilCpuGetNumProcessorsOnline();

@ -1809,6 +1809,30 @@ mmap_err:
return AFP_FATAL_ERROR; return AFP_FATAL_ERROR;
} }
/** \brief test if we can use FANOUT. Older kernels like those in
* CentOS6 have HAVE_PACKET_FANOUT defined but fail to work
*/
int AFPIsFanoutSupported(void)
{
#ifdef HAVE_PACKET_FANOUT
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd != -1) {
uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG;
uint16_t id = 99;
uint32_t option = (mode << 16) | (id & 0xffff);
int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option));
close(fd);
if (r < 0) {
SCLogPerf("fanout not supported by kernel: %s", strerror(errno));
return 0;
}
return 1;
}
#endif
return 0;
}
static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
{ {
int r; int r;

@ -147,4 +147,6 @@ TmEcode AFPPeersListCheck();
void AFPPeersListClean(); void AFPPeersListClean();
int AFPGetLinkType(const char *ifname); int AFPGetLinkType(const char *ifname);
int AFPIsFanoutSupported(void);
#endif /* __SOURCE_AFP_H__ */ #endif /* __SOURCE_AFP_H__ */

Loading…
Cancel
Save