suricata
runmode-netmap.c
Go to the documentation of this file.
1 /* Copyright (C) 2014-2018 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 netmap
20 *
21 * @{
22 */
23 
24 /**
25 * \file
26 *
27 * \author Aleksey Katargin <gureedo@gmail.com>
28 *
29 * Netmap runmode
30 *
31 */
32 
33 #include "suricata-common.h"
34 #include "config.h"
35 #include "tm-threads.h"
36 #include "conf.h"
37 #include "runmodes.h"
38 #include "runmode-netmap.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-prelude.h"
45 #include "alert-unified2-alert.h"
46 #include "alert-debuglog.h"
47 
48 #include "util-debug.h"
49 #include "util-time.h"
50 #include "util-cpu.h"
51 #include "util-affinity.h"
52 #include "util-device.h"
53 #include "util-runmodes.h"
54 #include "util-ioctl.h"
55 
56 #include "source-netmap.h"
57 
58 extern int max_pending_packets;
59 
60 const char *RunModeNetmapGetDefaultMode(void)
61 {
62  return "workers";
63 }
64 
66 {
68  "Single threaded netmap mode",
71  "Workers netmap mode, each thread does all"
72  " tasks from acquisition to logging",
75  "Multi threaded netmap mode. Packets from "
76  "each flow are assigned to a single detect "
77  "thread.",
79  return;
80 }
81 
82 #ifdef HAVE_NETMAP
83 
84 static void NetmapDerefConfig(void *conf)
85 {
86  NetmapIfaceConfig *pfp = (NetmapIfaceConfig *)conf;
87  /* config is used only once but cost of this low. */
88  if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) {
89  SCFree(pfp);
90  }
91 }
92 
93 static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface,
94  ConfNode *if_root, ConfNode *if_default)
95 {
96  ns->threads = 0;
97  ns->promisc = true;
100  strlcpy(ns->iface, iface, sizeof(ns->iface));
101 
102  if (ns->iface[0]) {
103  size_t len = strlen(ns->iface);
104  if (ns->iface[len-1] == '+') {
106  "netmap interface %s uses obsolete '+' notation. "
107  "Using '^' instead.", ns->iface);
108  ns->iface[len-1] = '^';
109  ns->sw_ring = true;
110  } else if (ns->iface[len-1] == '^') {
111  ns->sw_ring = true;
112  }
113  }
114 
115  /* prefixed with netmap or vale means it's not a real interface
116  * and we don't check offloading. */
117  if (strncmp(ns->iface, "netmap:", 7) != 0 &&
118  strncmp(ns->iface, "vale", 4) != 0) {
119  ns->real = true;
120  }
121 
122  const char *bpf_filter = NULL;
123  if (ConfGet("bpf-filter", &bpf_filter) == 1) {
124  if (strlen(bpf_filter) > 0) {
125  ns->bpf_filter = bpf_filter;
126  SCLogInfo("Going to use command-line provided bpf filter '%s'",
127  ns->bpf_filter);
128  }
129  }
130 
131  if (if_root == NULL && if_default == NULL) {
132  SCLogInfo("Unable to find netmap config for "
133  "interface \"%s\" or \"default\", using default values",
134  iface);
135  goto finalize;
136 
137  /* If there is no setting for current interface use default one as main iface */
138  } else if (if_root == NULL) {
139  if_root = if_default;
140  if_default = NULL;
141  }
142 
143  const char *threadsstr = NULL;
144  if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) {
145  ns->threads = 0;
146  ns->threads_auto = true;
147  } else {
148  if (strcmp(threadsstr, "auto") == 0) {
149  ns->threads = 0;
150  ns->threads_auto = true;
151  } else {
152  ns->threads = atoi(threadsstr);
153  }
154  }
155 
156  /* load netmap bpf filter */
157  /* command line value has precedence */
158  if (ns->bpf_filter == NULL) {
159  if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) {
160  if (strlen(bpf_filter) > 0) {
161  ns->bpf_filter = bpf_filter;
162  SCLogInfo("Going to use bpf filter %s", ns->bpf_filter);
163  }
164  }
165  }
166 
167  int boolval = 0;
168  (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
169  if (boolval) {
170  SCLogInfo("Disabling promiscuous mode on iface %s", ns->iface);
171  ns->promisc = false;
172  }
173 
174  const char *tmpctype;
175  if (ConfGetChildValueWithDefault(if_root, if_default,
176  "checksum-checks", &tmpctype) == 1)
177  {
178  if (strcmp(tmpctype, "auto") == 0) {
180  } else if (ConfValIsTrue(tmpctype)) {
182  } else if (ConfValIsFalse(tmpctype)) {
184  } else {
185  SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid value for "
186  "checksum-checks for %s", iface);
187  }
188  }
189 
190  const char *copymodestr;
191  if (ConfGetChildValueWithDefault(if_root, if_default,
192  "copy-mode", &copymodestr) == 1)
193  {
194  if (strcmp(copymodestr, "ips") == 0) {
196  } else if (strcmp(copymodestr, "tap") == 0) {
198  } else {
199  SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid copy-mode "
200  "(valid are tap, ips)");
201  }
202  }
203 
204 finalize:
205 
206  ns->ips = (ns->copy_mode != NETMAP_COPY_MODE_NONE);
207 
208  if (ns->sw_ring) {
209  /* just one thread per interface supported */
210  ns->threads = 1;
211  } else if (ns->threads_auto) {
212  /* As NetmapGetRSSCount used to be broken on Linux,
213  * fall back to GetIfaceRSSQueuesNum if needed. */
214  ns->threads = NetmapGetRSSCount(ns->iface);
215  if (ns->threads == 0) {
217  }
218  }
219  if (ns->threads <= 0) {
220  ns->threads = 1;
221  }
222 
223  return 0;
224 }
225 
226 /**
227 * \brief extract information from config file
228 *
229 * The returned structure will be freed by the thread init function.
230 * This is thus necessary to or copy the structure before giving it
231 * to thread or to reparse the file for each thread (and thus have
232 * new structure.
233 *
234 * \return a NetmapIfaceConfig corresponding to the interface name
235 */
236 static void *ParseNetmapConfig(const char *iface_name)
237 {
238  ConfNode *if_root = NULL;
239  ConfNode *if_default = NULL;
240  const char *out_iface = NULL;
241 
242  if (iface_name == NULL) {
243  return NULL;
244  }
245 
246  NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
247  if (unlikely(aconf == NULL)) {
248  return NULL;
249  }
250  memset(aconf, 0, sizeof(*aconf));
251 
252  aconf->DerefFunc = NetmapDerefConfig;
253  strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name));
254  SC_ATOMIC_INIT(aconf->ref);
255  (void) SC_ATOMIC_ADD(aconf->ref, 1);
256 
257  /* Find initial node */
258  ConfNode *netmap_node = ConfGetNode("netmap");
259  if (netmap_node == NULL) {
260  SCLogInfo("Unable to find netmap config using default value");
261  } else {
262  if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name);
263  if_default = ConfFindDeviceConfig(netmap_node, "default");
264  }
265 
266  /* parse settings for capture iface */
267  ParseNetmapSettings(&aconf->in, aconf->iface_name, if_root, if_default);
268 
269  /* if we have a copy iface, parse that as well */
270  if (netmap_node != NULL &&
271  ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1)
272  {
273  if (strlen(out_iface) > 0) {
274  if_root = ConfFindDeviceConfig(netmap_node, out_iface);
275  ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default);
276 
277  /* if one side of the IPS peering uses a sw_ring, we will default
278  * to using a single ring/thread on the other side as well. Only
279  * if thread variable is set to 'auto'. So the user can override
280  * this. */
281  if (aconf->out.sw_ring && aconf->in.threads_auto) {
282  aconf->out.threads = aconf->in.threads = 1;
283  } else if (aconf->in.sw_ring && aconf->out.threads_auto) {
284  aconf->out.threads = aconf->in.threads = 1;
285  }
286  }
287  }
288 
289  /* netmap needs all offloading to be disabled */
290  if (aconf->in.real) {
291  char base_name[sizeof(aconf->in.iface)];
292  strlcpy(base_name, aconf->in.iface, sizeof(base_name));
293  /* for a sw_ring enabled device name, strip the trailing char */
294  if (aconf->in.sw_ring) {
295  base_name[strlen(base_name) - 1] = '\0';
296  }
297 
298  if (LiveGetOffload() == 0) {
299  (void)GetIfaceOffloading(base_name, 1, 1);
300  } else {
301  DisableIfaceOffloading(LiveGetDevice(base_name), 1, 1);
302  }
303  }
304 
305  SC_ATOMIC_RESET(aconf->ref);
306  (void) SC_ATOMIC_ADD(aconf->ref, aconf->in.threads);
307  SCLogPerf("Using %d threads for interface %s", aconf->in.threads,
308  aconf->iface_name);
309 
310  return aconf;
311 }
312 
313 static int NetmapConfigGeThreadsCount(void *conf)
314 {
315  NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)conf;
316  return aconf->in.threads;
317 }
318 
319 int NetmapRunModeIsIPS()
320 {
321  int nlive = LiveGetDeviceCount();
322  int ldev;
323  ConfNode *if_root;
324  ConfNode *if_default = NULL;
325  ConfNode *netmap_node;
326  int has_ips = 0;
327  int has_ids = 0;
328 
329  /* Find initial node */
330  netmap_node = ConfGetNode("netmap");
331  if (netmap_node == NULL) {
332  return 0;
333  }
334 
335  if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default");
336 
337  for (ldev = 0; ldev < nlive; ldev++) {
338  const char *live_dev = LiveGetDeviceName(ldev);
339  if (live_dev == NULL) {
340  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
341  return 0;
342  }
343  const char *copymodestr = NULL;
344  if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);
345 
346  if (if_root == NULL) {
347  if (if_default == NULL) {
348  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
349  return 0;
350  }
351  if_root = if_default;
352  }
353 
354  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
355  if (strcmp(copymodestr, "ips") == 0) {
356  has_ips = 1;
357  } else {
358  has_ids = 1;
359  }
360  } else {
361  has_ids = 1;
362  }
363  }
364 
365  if (has_ids && has_ips) {
366  SCLogInfo("Netmap mode using IPS and IDS mode");
367  for (ldev = 0; ldev < nlive; ldev++) {
368  const char *live_dev = LiveGetDeviceName(ldev);
369  if (live_dev == NULL) {
370  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
371  return 0;
372  }
373  if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);
374  const char *copymodestr = NULL;
375 
376  if (if_root == NULL) {
377  if (if_default == NULL) {
378  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
379  return 0;
380  }
381  if_root = if_default;
382  }
383 
384  if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
385  (strcmp(copymodestr, "ips") == 0))) {
387  "Netmap IPS mode used and interface '%s' is in IDS or TAP mode. "
388  "Sniffing '%s' but expect bad result as stream-inline is activated.",
389  live_dev, live_dev);
390  }
391  }
392  }
393 
394  return has_ips;
395 }
396 
397 #endif // #ifdef HAVE_NETMAP
398 
400 {
401  SCEnter();
402 
403 #ifdef HAVE_NETMAP
404  int ret;
405  const char *live_dev = NULL;
406 
408 
409  TimeModeSetLive();
410 
411  (void)ConfGet("netmap.live-interface", &live_dev);
412 
413  SCLogDebug("live_dev %s", live_dev);
414 
416  ParseNetmapConfig,
417  NetmapConfigGeThreadsCount,
418  "ReceiveNetmap",
419  "DecodeNetmap", thread_name_autofp,
420  live_dev);
421  if (ret != 0) {
422  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
423  exit(EXIT_FAILURE);
424  }
425 
426  SCLogDebug("RunModeIdsNetmapAutoFp initialised");
427 #endif /* HAVE_NETMAP */
428 
429  SCReturnInt(0);
430 }
431 
432 /**
433 * \brief Single thread version of the netmap processing.
434 */
436 {
437  SCEnter();
438 
439 #ifdef HAVE_NETMAP
440  int ret;
441  const char *live_dev = NULL;
442 
444  TimeModeSetLive();
445 
446  (void)ConfGet("netmap.live-interface", &live_dev);
447 
449  ParseNetmapConfig,
450  NetmapConfigGeThreadsCount,
451  "ReceiveNetmap",
452  "DecodeNetmap", thread_name_single,
453  live_dev);
454  if (ret != 0) {
455  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
456  exit(EXIT_FAILURE);
457  }
458 
459  SCLogDebug("RunModeIdsNetmapSingle initialised");
460 
461 #endif /* HAVE_NETMAP */
462  SCReturnInt(0);
463 }
464 
465 /**
466 * \brief Workers version of the netmap processing.
467 *
468 * Start N threads with each thread doing all the work.
469 *
470 */
472 {
473  SCEnter();
474 
475 #ifdef HAVE_NETMAP
476  int ret;
477  const char *live_dev = NULL;
478 
480  TimeModeSetLive();
481 
482  (void)ConfGet("netmap.live-interface", &live_dev);
483 
485  ParseNetmapConfig,
486  NetmapConfigGeThreadsCount,
487  "ReceiveNetmap",
488  "DecodeNetmap", thread_name_workers,
489  live_dev);
490  if (ret != 0) {
491  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
492  exit(EXIT_FAILURE);
493  }
494 
495  SCLogDebug("RunModeIdsNetmapWorkers initialised");
496 
497 #endif /* HAVE_NETMAP */
498  SCReturnInt(0);
499 }
500 
501 /**
502 * @}
503 */
const char * LiveGetDeviceName(int number)
Get a pointer to the device name at idx.
Definition: util-device.c:177
#define SCLogDebug(...)
Definition: util-debug.h:335
ConfNode * ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value)
Lookup for a key value under a specific node.
Definition: conf.c:860
void RunModeInitialize(void)
Definition: runmodes.c:900
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
const char * bpf_filter
Definition: source-netmap.h:54
const char * RunModeNetmapGetDefaultMode(void)
#define unlikely(expr)
Definition: util-optimize.h:35
NetmapIfaceSettings in
Definition: source-netmap.h:63
const char * thread_name_single
Definition: runmodes.c:62
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
#define SC_ATOMIC_RESET(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:90
void TimeModeSetLive(void)
Definition: util-time.c:90
int RunModeIdsNetmapSingle(void)
Single thread version of the netmap processing.
int LiveGetDeviceCount(void)
Get the number of registered devices.
Definition: util-device.c:157
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:124
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
int GetIfaceOffloading(const char *dev, int csum, int other)
output offloading status of the link
Definition: util-ioctl.c:694
int RunModeIdsNetmapAutoFp(void)
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
ConfNode * ConfFindDeviceConfig(ConfNode *node, const char *iface)
Find the configuration node for a specific device.
Definition: util-conf.c:129
int RunModeSetLiveCaptureAutoFp(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:89
void(* DerefFunc)(void *)
Definition: source-netmap.h:69
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
int NetmapGetRSSCount(const char *ifname)
#define SCEnter(...)
Definition: util-debug.h:337
int ConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:591
int max_pending_packets
Definition: suricata.c:215
#define SCReturnInt(x)
Definition: util-debug.h:341
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:236
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
NetmapIfaceSettings out
Definition: source-netmap.h:66
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:566
int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
char iface[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:42
Definition: conf.h:32
#define SCMalloc(a)
Definition: util-mem.h:222
ChecksumValidationMode checksum_mode
Definition: source-netmap.h:53
int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr)
Definition: conf.c:416
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCFree(a)
Definition: util-mem.h:322
void RunModeIdsNetmapRegister(void)
int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
Definition: util-ioctl.c:707
int GetIfaceRSSQueuesNum(const char *pcap_dev)
Definition: util-ioctl.c:737
const char * thread_name_autofp
Definition: runmodes.c:61
#define SCLogPerf(...)
Definition: util-debug.h:261
int RunModeIdsNetmapWorkers(void)
Workers version of the netmap processing.
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val)
Definition: conf.c:543
void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:419
uint8_t len
char iface_name[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:60
int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
int LiveGetOffload(void)
Definition: util-device.c:79
int NetmapRunModeIsIPS(void)
const char * thread_name_workers
Definition: runmodes.c:63