suricata
runmode-af-xdp.c
Go to the documentation of this file.
1 /* Copyright (C) 2022 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \ingroup afxdppacket
20  *
21  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Richard McConnell <richard_mcconnell@rapid7.com>
28  *
29  * AF_XDP socket runmode
30  *
31  */
32 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1
33 #define SC_PCAP_DONT_INCLUDE_PCAP_H 1
35 #include "tm-threads.h"
36 #include "conf.h"
37 #include "runmodes.h"
38 #include "runmode-af-xdp.h"
39 #include "output.h"
40 #include "log-httplog.h"
41 #include "detect-engine-mpm.h"
42 
43 #include "alert-fastlog.h"
44 #include "alert-debuglog.h"
45 
46 #include "flow-bypass.h"
47 
48 #include "util-conf.h"
49 #include "util-debug.h"
50 #include "util-time.h"
51 #include "util-cpu.h"
52 #include "util-affinity.h"
53 #include "util-device.h"
54 #include "util-runmodes.h"
55 #include "util-ioctl.h"
56 #include "util-ebpf.h"
57 #include "util-byte.h"
58 
59 #include "source-af-xdp.h"
60 
61 #ifdef HAVE_AF_XDP
62 #include <linux/if_xdp.h>
63 #include <linux/if_link.h>
64 #include <xdp/xsk.h>
65 #endif
66 
67 const char *RunModeAFXDPGetDefaultMode(void)
68 {
69  return "workers";
70 }
71 
73 {
74  RunModeRegisterNewRunMode(RUNMODE_AFXDP_DEV, "single", "Single threaded af-xdp mode",
75  RunModeIdsAFXDPSingle, NULL);
77  "Workers af-xdp mode, each thread does all"
78  " tasks from acquisition to logging",
80 
81  return;
82 }
83 
84 #ifdef HAVE_AF_XDP
85 
86 #define DEFAULT_BUSY_POLL_TIME 20
87 #define DEFAULT_BUSY_POLL_BUDGET 64
88 #define DEFAULT_GRO_FLUSH_TIMEOUT 2000000
89 #define DEFAULT_NAPI_HARD_IRQS 2
90 
91 static void AFXDPDerefConfig(void *conf)
92 {
93  AFXDPIfaceConfig *pfp = (AFXDPIfaceConfig *)conf;
94  /* Pcap config is used only once but cost of this low. */
95  if (SC_ATOMIC_SUB(pfp->ref, 1) <= 1) {
96  SCFree(pfp);
97  }
98 }
99 
100 static TmEcode ConfigSetThreads(AFXDPIfaceConfig *aconf, const char *entry_str)
101 {
102  SCEnter();
103  const char *active_runmode = RunmodeGetActive();
104 
105  if (active_runmode && !strcmp("single", active_runmode)) {
106  aconf->threads = 1;
107  SCReturnInt(0);
108  }
109 
110  if (entry_str == NULL) {
111  SCLogError("Number of threads for interface \"%s\" not specified", aconf->iface);
113  }
114 
115  const int nr_queues = GetIfaceRSSQueuesNum(aconf->iface);
116 
117  if (strcmp(entry_str, "auto") == 0) {
118 
119  const int nr_cores = (int)UtilCpuGetNumProcessorsOnline();
120 
121  /* Threads limited to MIN(cores vs queues) */
122  aconf->threads = (nr_cores <= nr_queues) ? nr_cores : nr_queues;
123  const char *sys_type = nr_cores <= nr_queues ? "cores" : "queues";
124 
125  SCLogPerf("%u %s, so using %u threads", aconf->threads, sys_type, aconf->threads);
127  }
128 
129  if (StringParseInt32(&aconf->threads, 10, 0, entry_str) < 0) {
130  SCLogError("Threads entry for interface %s contain non-numerical characters - \"%s\"",
131  aconf->iface, entry_str);
133  }
134 
135  if (aconf->threads < 0) {
136  SCLogError("Interface %s has a negative number of threads", aconf->iface);
138  }
139 
140  if (aconf->threads > nr_queues) {
141  SCLogWarning(
142  "Selected threads greater than configured queues, using: %d thread(s)", nr_queues);
143  aconf->threads = nr_queues;
144  }
145 
147 }
148 
149 /**
150  * \brief extract information from config file
151  *
152  * The returned structure will be freed by the thread init function.
153  * This is thus necessary to copy the structure before giving it
154  * to thread or to reparse the file for each thread (and thus have
155  * new structure.
156  *
157  * \return a AFXDPIfaceConfig corresponding to the interface name
158  */
159 static void *ParseAFXDPConfig(const char *iface)
160 {
161  const char *confstr = NULL;
162  ConfNode *if_root;
163  ConfNode *if_default = NULL;
164  ConfNode *af_xdp_node = NULL;
165  int conf_val = 0;
166  intmax_t conf_val_int = 0;
167  bool boolval = false;
168 
169  if (iface == NULL) {
170  return NULL;
171  }
172 
173  AFXDPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf));
174  if (unlikely(aconf == NULL)) {
175  return NULL;
176  }
177 
178  /* default/basic config setup */
179  strlcpy(aconf->iface, iface, sizeof(aconf->iface));
180  aconf->DerefFunc = AFXDPDerefConfig;
181  aconf->threads = 1;
182  aconf->promisc = 1;
183  aconf->enable_busy_poll = true;
184  aconf->busy_poll_time = DEFAULT_BUSY_POLL_TIME;
185  aconf->busy_poll_budget = DEFAULT_BUSY_POLL_BUDGET;
186  aconf->mode = XDP_FLAGS_UPDATE_IF_NOEXIST;
187  aconf->gro_flush_timeout = DEFAULT_GRO_FLUSH_TIMEOUT;
188  aconf->napi_defer_hard_irqs = DEFAULT_NAPI_HARD_IRQS;
189  aconf->mem_alignment = XSK_UMEM__DEFAULT_FLAGS;
190 
191  /* Find initial node */
192  af_xdp_node = ConfGetNode("af-xdp");
193  if (af_xdp_node == NULL) {
194  SCLogInfo("unable to find af-xdp config using default values");
195  goto finalize;
196  }
197 
198  if_root = ConfFindDeviceConfig(af_xdp_node, iface);
199  if_default = ConfFindDeviceConfig(af_xdp_node, "default");
200 
201  if (if_root == NULL && if_default == NULL) {
202  SCLogInfo("unable to find af-xdp config for "
203  "interface \"%s\" or \"default\", using default values",
204  iface);
205  goto finalize;
206  }
207 
208  /* If there is no setting for current interface use default one as main iface */
209  if (if_root == NULL) {
210  if_root = if_default;
211  if_default = NULL;
212  }
213 
214  /* Threading */
215  confstr = "auto";
216  (void)ConfGetChildValueWithDefault(if_root, if_default, "threads", &confstr);
217  if (ConfigSetThreads(aconf, confstr) != TM_ECODE_OK) {
218  aconf->DerefFunc(aconf);
219  return NULL;
220  }
221 
222  SC_ATOMIC_RESET(aconf->ref);
223  (void)SC_ATOMIC_ADD(aconf->ref, aconf->threads);
224 
225  /* Promisc Mode */
226  (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
227  if (boolval) {
228  SCLogConfig("Disabling promiscuous mode on iface %s", aconf->iface);
229  aconf->promisc = 0;
230  }
231 
232 #ifdef HAVE_AF_XDP
233  /* AF_XDP socket mode options */
234  if (ConfGetChildValueWithDefault(if_root, if_default, "force-xdp-mode", &confstr) == 1) {
235  if (strncasecmp(confstr, "drv", 3) == 0) {
236  aconf->mode |= XDP_FLAGS_DRV_MODE;
237  } else if (strncasecmp(confstr, "skb", 3) == 0) {
238  aconf->mode |= XDP_FLAGS_SKB_MODE;
239  } else if (strncasecmp(confstr, "none", 4) == 0) {
240  } else {
241  SCLogWarning("Incorrect af-xdp xdp-mode setting, default (none) shall be applied");
242  }
243  }
244 
245  /* copy and zerocopy binding options */
246  if (ConfGetChildValueWithDefault(if_root, if_default, "force-bind-mode", &confstr) == 1) {
247  if (strncasecmp(confstr, "zero", 4) == 0) {
248  aconf->bind_flags |= XDP_ZEROCOPY;
249  } else if (strncasecmp(confstr, "copy", 4) == 0) {
250  aconf->bind_flags |= XDP_COPY;
251  } else if (strncasecmp(confstr, "none", 4) == 0) {
252  } else {
253  SCLogWarning("Incorrect af-xdp copy-mode setting, default (none) shall be applied");
254  }
255  }
256 
257  /* memory alignment mode selection */
258  if (ConfGetChildValueWithDefault(if_root, if_default, "mem-unaligned", &confstr) == 1) {
259  if (strncasecmp(confstr, "yes", 3) == 0) {
260  aconf->mem_alignment = XDP_UMEM_UNALIGNED_CHUNK_FLAG;
261  }
262  }
263 
264  /* Busy polling options */
265  if (ConfGetChildValueBoolWithDefault(if_root, if_default, "enable-busy-poll", &conf_val) == 1) {
266  if (conf_val == 0) {
267  aconf->enable_busy_poll = false;
268  }
269  }
270 
271  if (aconf->enable_busy_poll) {
272  if (ConfGetChildValueIntWithDefault(if_root, if_default, "busy-poll-time", &conf_val_int) ==
273  1) {
274  if (conf_val_int) {
275  aconf->busy_poll_time = conf_val_int;
276  }
277  }
278 
280  if_root, if_default, "busy-poll-budget", &conf_val_int) == 1) {
281  if (conf_val_int) {
282  aconf->busy_poll_budget = conf_val_int;
283  }
284  }
285 
286  /* 0 value is valid for these Linux tunable's */
288  if_root, if_default, "gro-flush-timeout", &conf_val_int) == 1) {
289  aconf->gro_flush_timeout = conf_val_int;
290  }
291 
293  if_root, if_default, "napi-defer-hard-irq", &conf_val_int) == 1) {
294  aconf->napi_defer_hard_irqs = conf_val_int;
295  }
296  }
297 #endif
298 
299 finalize:
300  if (LiveGetOffload() == 0) {
301  if (GetIfaceOffloading(iface, 0, 1) == 1) {
302  SCLogWarning("Using AF_XDP with offloading activated leads to capture problems");
303  }
304  } else {
306  }
307 
308  return aconf;
309 }
310 
311 static int AFXDPConfigGetThreadsCount(void *conf)
312 {
313  if (conf == NULL)
314  FatalError("Configuration file is NULL");
315 
316  AFXDPIfaceConfig *afxdp_conf = (AFXDPIfaceConfig *)conf;
317  return afxdp_conf->threads;
318 }
319 
320 #endif /* HAVE_AF_XDP */
321 
322 /**
323  * \brief Single thread version of the AF_XDP processing.
324  */
326 {
327  SCEnter();
328 
329 #ifdef HAVE_AF_XDP
330  int ret;
331  const char *live_dev = NULL;
332 
334  TimeModeSetLive();
335 
336  (void)ConfGet("af-xdp.live-interface", &live_dev);
337 
339  FatalError("Unable to init AF_XDP queue protection.");
340  }
341 
342  ret = RunModeSetLiveCaptureSingle(ParseAFXDPConfig, AFXDPConfigGetThreadsCount, "ReceiveAFXDP",
343  "DecodeAFXDP", thread_name_single, live_dev);
344  if (ret != 0) {
345  FatalError("Unable to start runmode");
346  }
347 
348  SCLogDebug("RunModeIdsAFXDPSingle initialised");
349 
350 #endif /* HAVE_AF_XDP */
351  SCReturnInt(0);
352 }
353 
354 /**
355  * \brief Workers version of the AF_XDP processing.
356  *
357  * Start N threads with each thread doing all the work.
358  *
359  */
361 {
362  SCEnter();
363 
364 #ifdef HAVE_AF_XDP
365  int ret;
366  const char *live_dev = NULL;
367 
369  TimeModeSetLive();
370 
371  (void)ConfGet("af-xdp.live-interface", &live_dev);
372 
374  FatalError("Unable to init AF_XDP queue protection.");
375  }
376 
377  ret = RunModeSetLiveCaptureWorkers(ParseAFXDPConfig, AFXDPConfigGetThreadsCount, "ReceiveAFXDP",
378  "DecodeAFXDP", thread_name_workers, live_dev);
379  if (ret != 0) {
380  FatalError("Unable to start runmode");
381  }
382 
383  SCLogDebug("RunModeIdsAFXDPWorkers initialised");
384 
385 #endif /* HAVE_AF_XDP */
386  SCReturnInt(0);
387 }
388 /**
389  * @}
390  */
thread_name_workers
const char * thread_name_workers
Definition: runmodes.c:81
RUNMODE_AFXDP_DEV
@ RUNMODE_AFXDP_DEV
Definition: runmodes.h:38
util-byte.h
tm-threads.h
flow-bypass.h
RunModeSetLiveCaptureWorkers
int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
Definition: util-runmodes.c:322
alert-debuglog.h
AFXDPIfaceConfig::mode
uint32_t mode
Definition: source-af-xdp.h:36
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
AFXDPIfaceConfig::iface
char iface[AFXDP_IFACE_NAME_LENGTH]
Definition: source-af-xdp.h:30
ConfGetChildValueBoolWithDefault
int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val)
Definition: conf.c:508
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
LiveGetOffload
int LiveGetOffload(void)
Definition: util-device.c:81
AFXDPIfaceConfig::mem_alignment
int mem_alignment
Definition: source-af-xdp.h:38
AFXDPIfaceConfig::gro_flush_timeout
uint32_t gro_flush_timeout
Definition: source-af-xdp.h:42
AFXDPIfaceConfig::DerefFunc
void(* DerefFunc)(void *)
Definition: source-af-xdp.h:46
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:181
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
RunModeInitialize
void RunModeInitialize(void)
Definition: runmodes.c:985
util-runmodes.h
RunModeRegisterNewRunMode
void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void), void(*RunModeIsIPSEnabled)(void))
Registers a new runmode.
Definition: runmodes.c:491
RunmodeGetActive
char * RunmodeGetActive(void)
Definition: runmodes.c:217
StringParseInt32
int StringParseInt32(int32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:622
ConfGetChildValueIntWithDefault
int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val)
Definition: conf.c:460
RunModeAFXDPGetDefaultMode
const char * RunModeAFXDPGetDefaultMode(void)
Definition: runmode-af-xdp.c:67
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
thread_name_single
const char * thread_name_single
Definition: runmodes.c:80
AFXDPIfaceConfig::napi_defer_hard_irqs
uint32_t napi_defer_hard_irqs
Definition: source-af-xdp.h:43
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:84
AFXDPQueueProtectionInit
TmEcode AFXDPQueueProtectionInit(void)
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
util-device.h
util-debug.h
AFXDPIfaceConfig::enable_busy_poll
bool enable_busy_poll
Definition: source-af-xdp.h:39
util-cpu.h
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:242
GetIfaceRSSQueuesNum
int GetIfaceRSSQueuesNum(const char *dev)
Definition: util-ioctl.c:718
ConfFindDeviceConfig
ConfNode * ConfFindDeviceConfig(ConfNode *node, const char *iface)
Find the configuration node for a specific device.
Definition: util-conf.c:130
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect-engine-mpm.h
util-ebpf.h
AFXDPIfaceConfig::busy_poll_budget
uint32_t busy_poll_budget
Definition: source-af-xdp.h:41
util-affinity.h
AFXDPIfaceConfig::promisc
int promisc
Definition: source-af-xdp.h:33
ConfGetChildValueWithDefault
int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr)
Definition: conf.c:376
util-time.h
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
AFXDPIfaceConfig::bind_flags
uint32_t bind_flags
Definition: source-af-xdp.h:37
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:342
AFXDPIfaceConfig::threads
int threads
Definition: source-af-xdp.h:32
AFXDPIfaceConfig::busy_poll_time
uint32_t busy_poll_time
Definition: source-af-xdp.h:40
conf.h
TmEcode
TmEcode
Definition: tm-threads-common.h:83
GetIfaceOffloading
int GetIfaceOffloading(const char *dev, int csum, int other)
output offloading status of the link
Definition: util-ioctl.c:675
DisableIfaceOffloading
int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
Definition: util-ioctl.c:688
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
TimeModeSetLive
void TimeModeSetLive(void)
Definition: util-time.c:99
alert-fastlog.h
RunModeIdsAFXDPRegister
void RunModeIdsAFXDPRegister(void)
Definition: runmode-af-xdp.c:72
util-conf.h
suricata-common.h
source-af-xdp.h
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:230
FatalError
#define FatalError(...)
Definition: util-debug.h:502
RunModeIdsAFXDPWorkers
int RunModeIdsAFXDPWorkers(void)
Workers version of the AF_XDP processing.
Definition: runmode-af-xdp.c:360
log-httplog.h
SC_ATOMIC_RESET
#define SC_ATOMIC_RESET(name)
wrapper for reinitializing an atomic variable.
Definition: util-atomic.h:324
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
AFXDPIfaceConfig
Definition: source-af-xdp.h:29
runmode-af-xdp.h
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
util-ioctl.h
RunModeSetLiveCaptureSingle
int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
Definition: util-runmodes.c:351
RunModeIdsAFXDPSingle
int RunModeIdsAFXDPSingle(void)
Single thread version of the AF_XDP processing.
Definition: runmode-af-xdp.c:325
UtilCpuGetNumProcessorsOnline
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
Definition: util-cpu.c:108
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
output.h