suricata
source-netmap.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2021 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 * \defgroup netmap Netmap running mode
20 *
21 * @{
22 */
23 
24 /**
25  * \file
26  *
27  * \author Aleksey Katargin <gureedo@gmail.com>
28  * \author Victor Julien <victor@inliniac.net>
29  * \author Bill Meeks <billmeeks8@gmail.com>
30  *
31  * Netmap socket acquisition support
32  *
33  * Many thanks to Luigi Rizzo for guidance and support.
34  *
35  */
36 
37 #include "suricata.h"
38 #include "suricata-common.h"
39 #include "tm-threads.h"
40 #include "util-bpf.h"
41 #include "util-privs.h"
42 #include "util-validate.h"
43 
44 #include "source-netmap.h"
45 
46 #ifdef HAVE_NETMAP
47 
48 #define NETMAP_WITH_LIBS
49 #ifdef DEBUG
50 #define DEBUG_NETMAP_USER
51 #endif
52 
53 #include <net/netmap_user.h>
54 #include <libnetmap.h>
55 
56 #endif /* HAVE_NETMAP */
57 
58 #include "util-ioctl.h"
59 
60 #ifndef HAVE_NETMAP
61 
62 /**
63 * \brief this function prints an error message and exits.
64 */
65 static TmEcode NoNetmapSupportExit(ThreadVars *tv, const void *initdata, void **data)
66 {
68  "Error creating thread %s: Netmap is not enabled. "
69  "Make sure to pass --enable-netmap to configure when building.",
70  tv->name);
71 }
72 
74 {
75  tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap";
76  tmm_modules[TMM_RECEIVENETMAP].ThreadInit = NoNetmapSupportExit;
78 }
79 
80 /**
81 * \brief Registration Function for DecodeNetmap.
82 */
84 {
85  tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap";
86  tmm_modules[TMM_DECODENETMAP].ThreadInit = NoNetmapSupportExit;
88 }
89 
90 #else /* We have NETMAP support */
91 
92 #define POLL_TIMEOUT 100
93 
94 #if defined(__linux__)
95 #define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL)
96 
97 #ifndef IFF_PPROMISC
98 #define IFF_PPROMISC IFF_PROMISC
99 #endif
100 
101 #else
102 #define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL)
103 #endif
104 
105 enum { NETMAP_FLAG_ZERO_COPY = 1, NETMAP_FLAG_EXCL_RING_ACCESS = 2 };
106 
107 /**
108  * \brief Netmap device instance. Each ring for each device gets its own
109  * device.
110  */
111 typedef struct NetmapDevice_
112 {
113  struct nmport_d *nmd;
114  unsigned int ref;
115  SC_ATOMIC_DECLARE(unsigned int, threads_run);
116  TAILQ_ENTRY(NetmapDevice_) next;
117  // actual ifname can only be 16, but we store a bit more,
118  // like the options string and a 'netmap:' prefix.
119  char ifname[32];
120  int ring;
121  int direction; // 0 rx, 1 tx
122 
123  // autofp: Used to lock a destination ring while we are sending data.
124  SCMutex netmap_dev_lock;
125 } NetmapDevice;
126 
127 /**
128  * \brief Module thread local variables.
129  */
130 typedef struct NetmapThreadVars_
131 {
132  /* receive interface */
133  NetmapDevice *ifsrc;
134  /* dst interface for IPS mode */
135  NetmapDevice *ifdst;
136 
137  int flags;
138  struct bpf_program bpf_prog;
139 
140  /* suricata internals */
141  TmSlot *slot;
142  ThreadVars *tv;
143  LiveDevice *livedev;
144 
145  /* copy from config */
146  int copy_mode;
147  ChecksumValidationMode checksum_mode;
148 
149  /* counters */
150  uint64_t pkts;
151  uint64_t bytes;
152  uint64_t drops;
153  uint16_t capture_kernel_packets;
154  uint16_t capture_kernel_drops;
155 } NetmapThreadVars;
156 
157 typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList;
158 
159 static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist);
160 static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER;
161 
162 /** \brief get RSS RX-queue count
163  * \retval rx_rings RSS RX queue count or 0 on error
164  */
165 int NetmapGetRSSCount(const char *ifname)
166 {
167  struct nmreq_port_info_get req;
168  struct nmreq_header hdr;
169  int rx_rings = 0;
170 
171  /* we need the base interface name to query queues */
172  char base_name[IFNAMSIZ];
173  strlcpy(base_name, ifname, sizeof(base_name));
174  if (strlen(base_name) > 0 &&
175  (base_name[strlen(base_name) - 1] == '^' || base_name[strlen(base_name) - 1] == '*')) {
176  base_name[strlen(base_name) - 1] = '\0';
177  }
178 
179  SCMutexLock(&netmap_devlist_lock);
180 
181  /* open netmap device */
182  int fd = open("/dev/netmap", O_RDWR);
183  if (fd == -1) {
185  "Couldn't open netmap device, error %s",
186  strerror(errno));
187  goto error_open;
188  }
189 
190  /* query netmap interface info */
191  memset(&req, 0, sizeof(req));
192  memset(&hdr, 0, sizeof(hdr));
193  hdr.nr_version = NETMAP_API;
194  hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
195  hdr.nr_body = (uintptr_t)&req;
196  strlcpy(hdr.nr_name, base_name, sizeof(hdr.nr_name));
197 
198  if (ioctl(fd, NIOCCTRL, &hdr) != 0) {
199  SCLogError(SC_ERR_NETMAP_CREATE, "Couldn't query netmap for info about %s, error %s",
200  ifname, strerror(errno));
201  goto error_fd;
202  };
203 
204  /* return RX rings count if it equals TX rings count */
205  if (req.nr_rx_rings == req.nr_tx_rings) {
206  rx_rings = req.nr_rx_rings;
207  }
208 
209 error_fd:
210  close(fd);
211 error_open:
212  SCMutexUnlock(&netmap_devlist_lock);
213  return rx_rings;
214 }
215 
216 static void NetmapDestroyDevice(NetmapDevice *pdev)
217 {
218  nmport_close(pdev->nmd);
219  SCMutexDestroy(&pdev->netmap_dev_lock);
220  SCFree(pdev);
221 }
222 
223 /**
224  * \brief Close or dereference netmap device instance.
225  * \param dev Netmap device instance.
226  * \return Zero on success.
227  */
228 static int NetmapClose(NetmapDevice *dev)
229 {
230  NetmapDevice *pdev, *tmp;
231 
232  SCMutexLock(&netmap_devlist_lock);
233 
234  TAILQ_FOREACH_SAFE (pdev, &netmap_devlist, next, tmp) {
235  if (pdev == dev) {
236  pdev->ref--;
237  if (!pdev->ref) {
238  NetmapDestroyDevice(pdev);
239  }
240  SCMutexUnlock(&netmap_devlist_lock);
241  return 0;
242  }
243  }
244 
245  SCMutexUnlock(&netmap_devlist_lock);
246  return -1;
247 }
248 
249 /**
250  * \brief Close all open netmap device instances.
251  */
252 static void NetmapCloseAll(void)
253 {
254  NetmapDevice *pdev, *tmp;
255 
256  SCMutexLock(&netmap_devlist_lock);
257 
258  TAILQ_FOREACH_SAFE (pdev, &netmap_devlist, next, tmp) {
259  NetmapDestroyDevice(pdev);
260  }
261 
262  SCMutexUnlock(&netmap_devlist_lock);
263 }
264 
265 /**
266  * \brief Open interface in netmap mode.
267  * \param ifname Interface name.
268  * \param promisc Enable promiscuous mode.
269  * \param dev Pointer to requested netmap device instance.
270  * \param verbose Verbose error logging.
271  * \param read Indicates direction: RX or TX
272  * \param zerocopy 1 if zerocopy access requested
273  * \param soft Use Host stack (software) interface
274  * \return Zero on success.
275  */
276 static int NetmapOpen(NetmapIfaceSettings *ns, NetmapDevice **pdevice, int verbose, int read,
277  bool zerocopy, bool soft)
278 {
279  SCEnter();
280  SCLogDebug("ifname %s", ns->iface);
281 
282  char base_name[IFNAMSIZ];
283  strlcpy(base_name, ns->iface, sizeof(base_name));
284  if (strlen(base_name) > 0 &&
285  (base_name[strlen(base_name)-1] == '^' ||
286  base_name[strlen(base_name)-1] == '*'))
287  {
288  base_name[strlen(base_name)-1] = '\0';
289  }
290 
291  if (ns->real) {
292  /* check interface is up */
293  int if_flags = GetIfaceFlags(base_name);
294  if (if_flags == -1) {
295  if (verbose) {
296  SCLogError(SC_ERR_NETMAP_CREATE, "Cannot access network interface '%s' (%s)",
297  base_name, ns->iface);
298  }
299  goto error;
300  }
301 
302  /* bring iface up if it is down */
303  if ((if_flags & IFF_UP) == 0) {
304  SCLogError(SC_ERR_NETMAP_CREATE, "interface '%s' (%s) is down", base_name, ns->iface);
305  goto error;
306  }
307  /* if needed, try to set iface in promisc mode */
308  if (ns->promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) {
309  if_flags |= IFF_PPROMISC;
310  SetIfaceFlags(base_name, if_flags); // TODO reset at exit
311  // TODO move to parse config?
312  }
313  }
314  NetmapDevice *pdev = NULL, *spdev = NULL;
315  pdev = SCCalloc(1, sizeof(*pdev));
316  if (unlikely(pdev == NULL)) {
317  SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed");
318  goto error;
319  }
320  SC_ATOMIC_INIT(pdev->threads_run);
321 
322  SCMutexLock(&netmap_devlist_lock);
323 
324  const int direction = (read != 1);
325  int ring = 0;
326  /* Search for interface in our already opened list. */
327  /* We will find it when opening multiple rings on */
328  /* the device when it exposes multiple RSS queues. */
329  TAILQ_FOREACH(spdev, &netmap_devlist, next) {
330  SCLogDebug("spdev %s", spdev->ifname);
331  if (direction == spdev->direction && strcmp(ns->iface, spdev->ifname) == 0) {
332  ring = spdev->ring + 1;
333  }
334  }
335  SCLogDebug("netmap/%s: using ring %d", ns->iface, ring);
336 
337  const char *opt_R = "R";
338  const char *opt_T = "T";
339  const char *opt_x = "x"; // not for IPS
340  const char *opt_z = "z"; // zero copy, not for IPS
341 
342  /* assemble options string */
343  char optstr[16];
344  if (ns->ips)
345  opt_x = "";
346  // z seems to not play well with multiple opens of a real dev on linux
347  opt_z = "";
348 
349  /*
350  * How netmap endpoint names are selected:
351  *
352  * The following logic within the "retry" loop builds endpoint names.
353  *
354  * IPS Mode:
355  * There are two endpoints: one hardware NIC and either a hardware NIC or host stack "NIC".
356  *
357  * IDS Mode:
358  * One endpoint -- usually a hardware NIC.
359  *
360  * IPS mode -- with one endpoint a host stack "NIC":
361  * When using multiple rings/threads, then the open of the initial Ring 0 MUST
362  * instruct netmap to open multiple Host Stack rings (as the default is to open only a single
363  * pair). This is also critical for the HW NIC endpoint. This is done by adding
364  * “@conf:host-rings=x” suffix option (where “x” is the number of host rings desired)
365  * to BOTH endpoint nmport_open_desc() calls for ring 0 (hardware and host stack).
366  * For subsequent additional ring open calls, omit the suffix option specifying host ring count.
367  *
368  * IPS mode -- both endpoints are hardware NICs:
369  * Do NOT pass any suffix option (even for Ring 0). You do not need to tell netmap how many
370  * rings, because it already knows the correct value from the NIC driver itself. Specifying a
371  * desired ring count when both ends are Hardware NICs confuses netmap, and it seems to default
372  * to using only a single hardware ring. In this scenario, specify only the specific ring number
373  * being opened.
374  */
375 
376  // loop to retry opening if unsupported options are used
377 retry:
378  snprintf(optstr, sizeof(optstr), "%s%s%s", opt_z, opt_x, direction == 0 ? opt_R : opt_T);
379 
380  char devname[128];
381  if (strncmp(ns->iface, "netmap:", 7) == 0) {
382  snprintf(devname, sizeof(devname), "%s}%d%s%s",
383  ns->iface, ring, strlen(optstr) ? "/" : "", optstr);
384  } else if (strlen(ns->iface) > 5 && strncmp(ns->iface, "vale", 4) == 0 && isdigit(ns->iface[4])) {
385  snprintf(devname, sizeof(devname), "%s", ns->iface);
386  } else if (ring == 0 && ns->threads == 1) {
387  /* just a single thread and ring, so don't use ring param */
388  snprintf(devname, sizeof(devname), "netmap:%s%s%s",
389  ns->iface, strlen(optstr) ? "/" : "", optstr);
390  SCLogDebug("device with %s-ring enabled (devname): %s", soft ? "SW" : "HW", devname);
391  } else {
392  /* Going to be using multiple threads and rings */
393  if (ns->sw_ring) {
394  /* Opening a host stack interface */
395  if (ring == 0) {
396  /* Ring 0, so tell netmap how many host rings we want created */
397  snprintf(devname, sizeof(devname), "netmap:%s%d%s%s@conf:host-rings=%d", ns->iface,
398  ring, strlen(optstr) ? "/" : "", optstr, ns->threads);
399  } else {
400  /* Software (host) ring, but not initial open of ring 0 */
401  snprintf(devname, sizeof(devname), "netmap:%s%d%s%s", ns->iface, ring,
402  strlen(optstr) ? "/" : "", optstr);
403  }
404  SCLogDebug("device with SW-ring enabled (devname): %s", devname);
405  } else if (ring == 0 && soft) {
406  /* Ring 0 of HW endpoint, and other endpoint is SW stack,
407  * so request SW host stack rings to match HW rings count.
408  */
409  snprintf(devname, sizeof(devname), "netmap:%s-%d%s%s@conf:host-rings=%d", ns->iface,
410  ring, strlen(optstr) ? "/" : "", optstr, ns->threads);
411  SCLogDebug("device with HW-ring enabled (devname): %s", devname);
412  } else {
413  /* Hardware ring other than ring 0, or both endpoints are HW
414  * and there is no host stack (SW) endpoint */
415  snprintf(devname, sizeof(devname), "netmap:%s-%d%s%s", ns->iface, ring,
416  strlen(optstr) ? "/" : "", optstr);
417  SCLogDebug("device with HW-ring enabled (devname): %s", devname);
418  }
419  }
420 
421  strlcpy(pdev->ifname, ns->iface, sizeof(pdev->ifname));
422 
423  /* have the netmap API parse device name and prepare the port descriptor for us */
424  pdev->nmd = nmport_prepare(devname);
425 
426  if (pdev->nmd != NULL) {
427  /* For RX devices, set the nr_mode flag we need on the netmap port TX rings prior to opening
428  */
429  if (read) {
430  pdev->nmd->reg.nr_flags |= NR_NO_TX_POLL;
431  }
432 
433  /* Now attempt to actually open the netmap port descriptor */
434  if (nmport_open_desc(pdev->nmd) < 0) {
435  /* the open failed, so clean-up the descriptor and fall through to error handler */
436  nmport_close(pdev->nmd);
437  pdev->nmd = NULL;
438  }
439  }
440 
441  if (pdev->nmd == NULL) {
442  if (errno == EINVAL) {
443  if (opt_z[0] == 'z') {
444  SCLogNotice("got '%s' EINVAL: going to retry without 'z'", devname);
445  opt_z = "";
446  goto retry;
447  } else if (opt_x[0] == 'x') {
448  SCLogNotice("dev '%s' got EINVAL: going to retry without 'x'", devname);
449  opt_x = "";
450  goto retry;
451  }
452  }
453 
454  NetmapCloseAll();
455  FatalError(SC_ERR_FATAL, "opening devname %s failed: %s", devname, strerror(errno));
456  }
457 
458  /* Work around bug in libnetmap library where "cur_{r,t}x_ring" values not initialized */
459  SCLogDebug("%s -- cur rings: [%d, %d] first rings: [%d, %d]", devname, pdev->nmd->cur_rx_ring,
460  pdev->nmd->cur_tx_ring, pdev->nmd->first_rx_ring, pdev->nmd->first_tx_ring);
461  pdev->nmd->cur_rx_ring = pdev->nmd->first_rx_ring;
462  pdev->nmd->cur_tx_ring = pdev->nmd->first_tx_ring;
463 
464  SCLogInfo("devname [fd: %d] %s %s opened", pdev->nmd->fd, devname, ns->iface);
465 
466  pdev->direction = direction;
467  pdev->ring = ring;
468  SCMutexInit(&pdev->netmap_dev_lock, NULL);
469  TAILQ_INSERT_TAIL(&netmap_devlist, pdev, next);
470 
471  SCMutexUnlock(&netmap_devlist_lock);
472  *pdevice = pdev;
473 
474  return 0;
475 error:
476  return -1;
477 }
478 
479 /**
480  * \brief PcapDumpCounters
481  * \param ntv
482  */
483 static inline void NetmapDumpCounters(NetmapThreadVars *ntv)
484 {
485  StatsAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts);
486  StatsAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops);
487  (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops);
488  (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts);
489  ntv->drops = 0;
490  ntv->pkts = 0;
491 }
492 
493 /**
494  * \brief Init function for ReceiveNetmap.
495  * \param tv pointer to ThreadVars
496  * \param initdata pointer to the interface passed from the user
497  * \param data pointer gets populated with NetmapThreadVars
498  */
499 static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, const void *initdata, void **data)
500 {
501  SCEnter();
502 
503  NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)initdata;
504  if (initdata == NULL) {
505  SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL");
507  }
508 
509  NetmapThreadVars *ntv = SCCalloc(1, sizeof(*ntv));
510  if (unlikely(ntv == NULL)) {
511  SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed");
512  goto error;
513  }
514 
515  ntv->livedev = LiveGetDevice(aconf->iface_name);
516  if (ntv->livedev == NULL) {
517  SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device");
518  goto error_ntv;
519  }
520 
521  ntv->tv = tv;
522  ntv->checksum_mode = aconf->in.checksum_mode;
523  ntv->copy_mode = aconf->in.copy_mode;
524 
525  /* enable zero-copy mode for workers runmode */
526  char const *active_runmode = RunmodeGetActive();
527  if (strcmp("workers", active_runmode) == 0) {
528  ntv->flags |= NETMAP_FLAG_ZERO_COPY;
529  SCLogDebug("Enabling zero copy mode for %s", aconf->in.iface);
530  } else if (strcmp("autofp", active_runmode) == 0) {
531  ntv->flags |= NETMAP_FLAG_EXCL_RING_ACCESS;
532  }
533 
534  /* Need to insure open of ring 0 conveys requested ring count for open */
535  bool soft = aconf->in.sw_ring || aconf->out.sw_ring;
536  if (NetmapOpen(&aconf->in, &ntv->ifsrc, 1, 1, (ntv->flags & NETMAP_FLAG_ZERO_COPY) != 0,
537  soft) != 0) {
538  goto error_ntv;
539  }
540 
541  if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
542  if (NetmapOpen(&aconf->out, &ntv->ifdst, 1, 0, (ntv->flags & NETMAP_FLAG_ZERO_COPY) != 0,
543  soft) != 0) {
544  goto error_src;
545  }
546  }
547 
548  /* basic counters */
549  ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets",
550  ntv->tv);
551  ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
552  ntv->tv);
553 
554  if (aconf->in.bpf_filter) {
555  SCLogConfig("Using BPF '%s' on iface '%s'",
556  aconf->in.bpf_filter, ntv->ifsrc->ifname);
557  char errbuf[PCAP_ERRBUF_SIZE];
558  if (SCBPFCompile(default_packet_size, /* snaplen_arg */
559  LINKTYPE_ETHERNET, /* linktype_arg */
560  &ntv->bpf_prog, /* program */
561  aconf->in.bpf_filter, /* const char *buf */
562  1, /* optimize */
563  PCAP_NETMASK_UNKNOWN, /* mask */
564  errbuf,
565  sizeof(errbuf)) == -1)
566  {
567  SCLogError(SC_ERR_NETMAP_CREATE, "Failed to compile BPF \"%s\": %s",
568  aconf->in.bpf_filter,
569  errbuf);
570  goto error_dst;
571  }
572  }
573 
574  SCLogDebug("thread: %s polling on fd: %d", tv->name, ntv->ifsrc->nmd->fd);
575 
576  *data = (void *)ntv;
577  aconf->DerefFunc(aconf);
579 
580 error_dst:
581  if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
582  NetmapClose(ntv->ifdst);
583  }
584 
585 error_src:
586  NetmapClose(ntv->ifsrc);
587 
588 error_ntv:
589  SCFree(ntv);
590 
591 error:
592  aconf->DerefFunc(aconf);
594 }
595 
596 /**
597  * \brief Output packet to destination interface or drop.
598  * \param ntv Thread local variables.
599  * \param p Source packet.
600  */
601 static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p)
602 {
603  if (ntv->copy_mode == NETMAP_COPY_MODE_IPS) {
604  if (PacketTestAction(p, ACTION_DROP)) {
605  return TM_ECODE_OK;
606  }
607  }
608  DEBUG_VALIDATE_BUG_ON(ntv->ifdst == NULL);
609 
610  /* Lock the destination netmap ring while writing to it */
611  if (ntv->flags & NETMAP_FLAG_EXCL_RING_ACCESS) {
612  SCMutexLock(&ntv->ifdst->netmap_dev_lock);
613  }
614 
615  /* attempt to write the packet into the netmap ring buffer(s) */
616  if (nmport_inject(ntv->ifdst->nmd, GET_PKT_DATA(p), GET_PKT_LEN(p)) == 0) {
617  if (ntv->flags & NETMAP_FLAG_EXCL_RING_ACCESS) {
618  SCMutexUnlock(&ntv->ifdst->netmap_dev_lock);
619  }
620  SCLogDebug("failed to send %s -> %s", ntv->ifsrc->ifname, ntv->ifdst->ifname);
621  ntv->drops++;
622  return TM_ECODE_FAILED;
623  }
624 
625  SCLogDebug("sent successfully: %s(%d)->%s(%d) (%u)", ntv->ifsrc->ifname, ntv->ifsrc->ring,
626  ntv->ifdst->ifname, ntv->ifdst->ring, GET_PKT_LEN(p));
627 
628  /* Instruct netmap to push the data on the TX ring on the destination port */
629  ioctl(ntv->ifdst->nmd->fd, NIOCTXSYNC, 0);
630  if (ntv->flags & NETMAP_FLAG_EXCL_RING_ACCESS) {
631  SCMutexUnlock(&ntv->ifdst->netmap_dev_lock);
632  }
633  return TM_ECODE_OK;
634 }
635 
636 /**
637  * \brief Packet release routine.
638  * \param p Packet.
639  */
640 static void NetmapReleasePacket(Packet *p)
641 {
642  NetmapThreadVars *ntv = (NetmapThreadVars *)p->netmap_v.ntv;
643 
644  if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) {
645  NetmapWritePacket(ntv, p);
646  }
647 
649 }
650 
651 static void NetmapProcessPacket(NetmapThreadVars *ntv, const struct nm_pkthdr *ph)
652 {
653  if (ntv->bpf_prog.bf_len) {
654  struct pcap_pkthdr pkthdr = { {0, 0}, ph->len, ph->len };
655  if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, ph->buf) == 0) {
656  return;
657  }
658  }
659 
661  if (unlikely(p == NULL)) {
662  return;
663  }
664 
666  p->livedev = ntv->livedev;
668  p->ts = ph->ts;
669  ntv->pkts++;
670  ntv->bytes += ph->len;
671 
672  if (ntv->flags & NETMAP_FLAG_ZERO_COPY) {
673  if (PacketSetData(p, (uint8_t *)ph->buf, ph->len) == -1) {
674  TmqhOutputPacketpool(ntv->tv, p);
675  return;
676  }
677  } else {
678  if (PacketCopyData(p, (uint8_t *)ph->buf, ph->len) == -1) {
679  TmqhOutputPacketpool(ntv->tv, p);
680  return;
681  }
682  }
683 
684  p->ReleasePacket = NetmapReleasePacket;
685  p->netmap_v.ntv = ntv;
686 
687  SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)",
688  GET_PKT_LEN(p), p, GET_PKT_DATA(p));
689 
690  (void)TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p);
691 }
692 
693 /**
694  * \brief Copy netmap rings data into Packet structures.
695  * \param *d nmport_d (or nm_desc) netmap if structure.
696  * \param cnt int count of packets to read (-1 = all).
697  * \param *ntv NetmapThreadVars.
698  */
699 static TmEcode NetmapReadPackets(struct nmport_d *d, int cnt, NetmapThreadVars *ntv)
700 {
701  struct nm_pkthdr hdr;
702  int last_ring = d->last_rx_ring - d->first_rx_ring + 1;
703  int cur_ring, got = 0, cur_rx_ring = d->cur_rx_ring;
704 
705  memset(&hdr, 0, sizeof(hdr));
706  hdr.flags = NM_MORE_PKTS;
707 
708  if (cnt == 0)
709  cnt = -1;
710 
711  for (cur_ring = 0; cur_ring < last_ring && cnt != got; cur_ring++, cur_rx_ring++) {
712  struct netmap_ring *ring;
713 
714  if (cur_rx_ring > d->last_rx_ring)
715  cur_rx_ring = d->first_rx_ring;
716 
717  ring = NETMAP_RXRING(d->nifp, cur_rx_ring);
718 
719  /* cycle through the non-empty ring slots to fetch their data */
720  for (; !nm_ring_empty(ring) && cnt != got; got++) {
721  u_int idx, i;
722  u_char *oldbuf;
723  struct netmap_slot *slot;
724 
725  if (hdr.buf) { /* from previous round */
726  NetmapProcessPacket(ntv, &hdr);
727  }
728 
729  i = ring->cur;
730  slot = &ring->slot[i];
731  idx = slot->buf_idx;
732  d->cur_rx_ring = cur_rx_ring;
733  hdr.slot = slot;
734  oldbuf = hdr.buf = (u_char *)NETMAP_BUF(ring, idx);
735  hdr.len = hdr.caplen = slot->len;
736 
737  /* loop through the ring slots to get packet data */
738  while (slot->flags & NS_MOREFRAG) {
739  /* packet can be fragmented across multiple slots, */
740  /* so loop until we find the slot with the flag */
741  /* cleared, signalling the end of the packet data. */
742  u_char *nbuf;
743  u_int oldlen = slot->len;
744  i = nm_ring_next(ring, i);
745  slot = &ring->slot[i];
746  hdr.len += slot->len;
747  nbuf = (u_char *)NETMAP_BUF(ring, slot->buf_idx);
748 
749  if (oldbuf != NULL && nbuf - oldbuf == ring->nr_buf_size &&
750  oldlen == ring->nr_buf_size) {
751  hdr.caplen += slot->len;
752  oldbuf = nbuf;
753  } else {
754  oldbuf = NULL;
755  }
756  }
757 
758  hdr.ts = ring->ts;
759  ring->head = ring->cur = nm_ring_next(ring, i);
760  }
761  }
762 
763  if (hdr.buf) { /* from previous round */
764  hdr.flags = 0;
765  NetmapProcessPacket(ntv, &hdr);
766  }
767  return got;
768 }
769 
770 /**
771  * \brief Main netmap reading loop function
772  */
773 static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot)
774 {
775  SCEnter();
776 
777  TmSlot *s = (TmSlot *)slot;
778  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
779  struct pollfd fds;
780 
781  ntv->slot = s->slot_next;
782  fds.fd = ntv->ifsrc->nmd->fd;
783  fds.events = POLLIN;
784 
785  SCLogDebug("thread %s polling on %d", tv->name, fds.fd);
786  for(;;) {
787  if (unlikely(suricata_ctl_flags != 0)) {
788  break;
789  }
790 
791  /* make sure we have at least one packet in the packet pool,
792  * to prevent us from alloc'ing packets at line rate */
793  PacketPoolWait();
794 
795  int r = poll(&fds, 1, POLL_TIMEOUT);
796 
797  if (r < 0) {
798  /* error */
799  if (errno != EINTR)
801  "Error polling netmap from iface '%s': (%d" PRIu32 ") %s",
802  ntv->ifsrc->ifname, errno, strerror(errno));
803  continue;
804 
805  } else if (r == 0) {
806  /* no events, timeout */
807  /* sync counters */
808  NetmapDumpCounters(ntv);
810 
811  /* poll timed out, lets handle the timeout */
812  TmThreadsCaptureHandleTimeout(tv, NULL);
813  continue;
814  }
815 
816  if (unlikely(fds.revents & POLL_EVENTS)) {
817  if (fds.revents & POLLERR) {
819  "Error reading netmap data via polling from iface '%s': (%d" PRIu32 ") %s",
820  ntv->ifsrc->ifname, errno, strerror(errno));
821  } else if (fds.revents & POLLNVAL) {
822  SCLogError(SC_ERR_NETMAP_READ, "Invalid polling request");
823  }
824  continue;
825  }
826 
827  if (likely(fds.revents & POLLIN)) {
828  /* have data on RX ring, so copy to Packet for processing */
829  NetmapReadPackets(ntv->ifsrc->nmd, -1, ntv);
830  }
831 
832  NetmapDumpCounters(ntv);
834  }
835 
836  NetmapDumpCounters(ntv);
839 }
840 
841 /**
842  * \brief This function prints stats to the screen at exit.
843  * \param tv pointer to ThreadVars
844  * \param data pointer that gets cast into NetmapThreadVars for ntv
845  */
846 static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data)
847 {
848  SCEnter();
849  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
850 
851  NetmapDumpCounters(ntv);
852  SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "",
853  tv->name,
854  StatsGetLocalCounterValue(tv, ntv->capture_kernel_packets),
855  StatsGetLocalCounterValue(tv, ntv->capture_kernel_drops),
856  ntv->bytes);
857 }
858 
859 /**
860  * \brief
861  * \param tv
862  * \param data Pointer to NetmapThreadVars.
863  */
864 static TmEcode ReceiveNetmapThreadDeinit(ThreadVars *tv, void *data)
865 {
866  SCEnter();
867 
868  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
869 
870  if (ntv->ifsrc) {
871  NetmapClose(ntv->ifsrc);
872  ntv->ifsrc = NULL;
873  }
874  if (ntv->ifdst) {
875  NetmapClose(ntv->ifdst);
876  ntv->ifdst = NULL;
877  }
878  if (ntv->bpf_prog.bf_insns) {
879  SCBPFFree(&ntv->bpf_prog);
880  }
881 
882  SCFree(ntv);
883 
885 }
886 
887 /**
888  * \brief Prepare netmap decode thread.
889  * \param tv Thread local variables.
890  * \param initdata Thread config.
891  * \param data Pointer to DecodeThreadVars placed here.
892  */
893 static TmEcode DecodeNetmapThreadInit(ThreadVars *tv, const void *initdata, void **data)
894 {
895  SCEnter();
896 
898  if (dtv == NULL)
900 
902 
903  *data = (void *)dtv;
904 
906 }
907 
908 /**
909  * \brief This function passes off to link type decoders.
910  *
911  * \param t pointer to ThreadVars
912  * \param p pointer to the current packet
913  * \param data pointer that gets cast into NetmapThreadVars for ntv
914  */
915 static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data)
916 {
917  SCEnter();
918 
920 
922 
923  /* update counters */
925 
927 
929 
931 }
932 
933 /**
934  * \brief
935  * \param tv
936  * \param data Pointer to DecodeThreadVars.
937  */
938 static TmEcode DecodeNetmapThreadDeinit(ThreadVars *tv, void *data)
939 {
940  SCEnter();
941 
942  if (data != NULL)
943  DecodeThreadVarsFree(tv, data);
944 
946 }
947 
948 /**
949  * \brief Registration Function for ReceiveNetmap.
950  */
952 {
953  tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap";
954  tmm_modules[TMM_RECEIVENETMAP].ThreadInit = ReceiveNetmapThreadInit;
955  tmm_modules[TMM_RECEIVENETMAP].PktAcqLoop = ReceiveNetmapLoop;
956  tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = ReceiveNetmapThreadExitStats;
957  tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = ReceiveNetmapThreadDeinit;
960 }
961 
962 /**
963  * \brief Registration Function for DecodeNetmap.
964  */
966 {
967  tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap";
968  tmm_modules[TMM_DECODENETMAP].ThreadInit = DecodeNetmapThreadInit;
969  tmm_modules[TMM_DECODENETMAP].Func = DecodeNetmap;
970  tmm_modules[TMM_DECODENETMAP].ThreadDeinit = DecodeNetmapThreadDeinit;
973 }
974 
975 #endif /* HAVE_NETMAP */
976 
977 /**
978 * @}
979 */
TmModule_::cap_flags
uint8_t cap_flags
Definition: tm-modules.h:67
tm-threads.h
ThreadVars_::name
char name[16]
Definition: threadvars.h:65
PacketFreeOrRelease
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition: decode.c:172
SC_ERR_INVALID_VALUE
@ SC_ERR_INVALID_VALUE
Definition: util-error.h:160
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:273
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1207
util-bpf.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
NETMAP_COPY_MODE_NONE
@ NETMAP_COPY_MODE_NONE
Definition: source-netmap.h:30
NetmapIfaceSettings_::checksum_mode
ChecksumValidationMode checksum_mode
Definition: source-netmap.h:51
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
LiveDevice_
Definition: util-device.h:40
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
SC_ERR_NETMAP_CREATE
@ SC_ERR_NETMAP_CREATE
Definition: util-error.h:295
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:253
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
NetmapIfaceConfig_::out
NetmapIfaceSettings out
Definition: source-netmap.h:64
util-privs.h
StatsSyncCountersIfSignalled
#define StatsSyncCountersIfSignalled(tv)
Definition: counters.h:137
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:295
PacketDecodeFinalize
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition: decode.c:125
RunmodeGetActive
char * RunmodeGetActive(void)
Definition: runmodes.c:198
TmModuleReceiveNetmapRegister
void TmModuleReceiveNetmapRegister(void)
Definition: source-netmap.c:73
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:375
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:83
NetmapIfaceSettings_::iface
char iface[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:40
NetmapIfaceSettings_::ips
bool ips
Definition: source-netmap.h:46
TmModule_::PktAcqLoop
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition: tm-modules.h:54
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:82
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
TmModule_::ThreadDeinit
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:49
TAILQ_ENTRY
#define TAILQ_ENTRY(type)
Definition: queue.h:240
Packet_::datalink
int datalink
Definition: decode.h:591
NetmapGetRSSCount
int NetmapGetRSSCount(const char *ifname)
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1210
DecodeRegisterPerfCounters
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition: decode.c:495
TAILQ_HEAD_INITIALIZER
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:237
TmModuleDecodeNetmapRegister
void TmModuleDecodeNetmapRegister(void)
Registration Function for DecodeNetmap.
Definition: source-netmap.c:83
NetmapIfaceConfig_::DerefFunc
void(* DerefFunc)(void *)
Definition: source-netmap.h:67
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:51
NetmapIfaceSettings_::real
bool real
Definition: source-netmap.h:45
NETMAP_COPY_MODE_IPS
@ NETMAP_COPY_MODE_IPS
Definition: source-netmap.h:32
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
NetmapIfaceSettings_::sw_ring
bool sw_ring
Definition: source-netmap.h:43
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:279
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:236
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
TmModule_::Func
TmEcode(* Func)(ThreadVars *, Packet *, void *)
Definition: tm-modules.h:52
SC_ERR_INVALID_ARGUMENT
@ SC_ERR_INVALID_ARGUMENT
Definition: util-error.h:43
NetmapIfaceSettings_
Definition: source-netmap.h:38
TMM_DECODENETMAP
@ TMM_DECODENETMAP
Definition: tm-threads-common.h:59
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
NetmapIfaceSettings_::threads
uint16_t threads
Definition: source-netmap.h:49
StatsGetLocalCounterValue
uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id)
Get the value of the local copy of the counter that hold this id.
Definition: counters.c:1243
SC_ATOMIC_DECLARE
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
Definition: util-atomic.h:281
PacketPoolWait
void PacketPoolWait(void)
Definition: tmqh-packetpool.c:84
Packet_
Definition: decode.h:417
TM_FLAG_DECODE_TM
#define TM_FLAG_DECODE_TM
Definition: tm-modules.h:32
tmm_modules
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.c:33
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:235
source-netmap.h
TmSlot_
Definition: tm-threads.h:52
Packet_::livedev
struct LiveDevice_ * livedev
Definition: decode.h:570
TmEcode
TmEcode
Definition: tm-threads-common.h:81
NetmapIfaceSettings_::promisc
bool promisc
Definition: source-netmap.h:44
SC_ERR_NETMAP_READ
@ SC_ERR_NETMAP_READ
Definition: util-error.h:296
TmModule_::name
const char * name
Definition: tm-modules.h:44
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:330
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
TM_FLAG_RECEIVE_TM
#define TM_FLAG_RECEIVE_TM
Definition: tm-modules.h:31
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:30
default_packet_size
uint32_t default_packet_size
Definition: decode.c:72
Packet_::ReleasePacket
void(* ReleasePacket)(struct Packet_ *)
Definition: decode.h:499
NetmapIfaceSettings_::bpf_filter
const char * bpf_filter
Definition: source-netmap.h:52
flags
uint8_t flags
Definition: decode-gre.h:0
DecodeThreadVarsFree
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition: decode.c:672
NetmapIfaceConfig_
Definition: source-netmap.h:56
Packet_::ts
struct timeval ts
Definition: decode.h:460
ChecksumValidationMode
ChecksumValidationMode
Definition: decode.h:42
suricata-common.h
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:224
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
SCBPFFree
void SCBPFFree(struct bpf_program *program)
Definition: util-bpf.c:34
TmModule_::ThreadInit
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:47
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
TmModule_::ThreadExitPrintStats
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition: tm-modules.h:48
util-validate.h
TMM_RECEIVENETMAP
@ TMM_RECEIVENETMAP
Definition: tm-threads-common.h:58
StatsAddUI64
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:148
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
POLL_TIMEOUT
#define POLL_TIMEOUT
Definition: source-af-packet.c:171
SC_ERR_NO_NETMAP
@ SC_ERR_NO_NETMAP
Definition: util-error.h:294
SCFree
#define SCFree(p)
Definition: util-mem.h:61
NetmapIfaceConfig_::iface_name
char iface_name[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:58
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:644
NetmapIfaceSettings_::copy_mode
int copy_mode
Definition: source-netmap.h:50
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
bpf_program
Definition: source-af-packet.c:78
util-ioctl.h
DecodeThreadVarsAlloc
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition: decode.c:653
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:231
PacketSetData
int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Set data for Packet and set length when zero copy is used.
Definition: decode.c:692
PacketPoolGetPacket
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
Definition: tmqh-packetpool.c:185
SCBPFCompile
int SCBPFCompile(int snaplen_arg, int linktype_arg, struct bpf_program *program, const char *buf, int optimize, uint32_t mask, char *errbuf, size_t errbuf_len)
Definition: util-bpf.c:40
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
NetmapIfaceConfig_::in
NetmapIfaceSettings in
Definition: source-netmap.h:61
suricata.h
likely
#define likely(expr)
Definition: util-optimize.h:32
TmSlot_::slot_next
struct TmSlot_ * slot_next
Definition: tm-threads.h:61
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:232
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:942
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
SCMutex
#define SCMutex
Definition: threads-debug.h:114
SC_CAP_NET_RAW
#define SC_CAP_NET_RAW
Definition: util-privs.h:32
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
TmModule_::flags
uint8_t flags
Definition: tm-modules.h:70
DecodeUpdatePacketCounters
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition: decode.c:619
LINKTYPE_ETHERNET
#define LINKTYPE_ETHERNET
Definition: decode.h:1127
suricata_ctl_flags
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:200