suricata
source-netmap.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-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 * \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 *
30 * Netmap socket acquisition support
31 *
32 * Many thanks to Luigi Rizzo for guidance and support.
33 *
34 */
35 
36 
37 #include "suricata-common.h"
38 #include "suricata.h"
39 #include "decode.h"
40 #include "threads.h"
41 #include "threadvars.h"
42 #include "tm-threads.h"
43 #include "conf.h"
44 #include "util-bpf.h"
45 #include "util-debug.h"
46 #include "util-device.h"
47 #include "util-error.h"
48 #include "util-privs.h"
49 #include "util-optimize.h"
50 #include "util-checksum.h"
51 #include "util-validate.h"
52 
53 #include "tmqh-packetpool.h"
54 #include "source-netmap.h"
55 #include "runmodes.h"
56 
57 #ifdef HAVE_NETMAP
58 
59 #if HAVE_SYS_IOCTL_H
60 #include <sys/ioctl.h>
61 #endif
62 
63 #if HAVE_SYS_MMAN_H
64 #include <sys/mman.h>
65 #endif
66 
67 #define NETMAP_WITH_LIBS
68 #ifdef DEBUG
69 #define DEBUG_NETMAP_USER
70 #endif
71 #include <net/netmap_user.h>
72 
73 #endif /* HAVE_NETMAP */
74 
75 #include "util-ioctl.h"
76 
77 #ifndef HAVE_NETMAP
78 
79 /**
80 * \brief this function prints an error message and exits.
81 */
82 static TmEcode NoNetmapSupportExit(ThreadVars *tv, const void *initdata, void **data)
83 {
84  SCLogError(SC_ERR_NO_NETMAP,"Error creating thread %s: you do not have "
85  "support for netmap enabled, please recompile "
86  "with --enable-netmap", tv->name);
87  exit(EXIT_FAILURE);
88 }
89 
91 {
92  tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap";
93  tmm_modules[TMM_RECEIVENETMAP].ThreadInit = NoNetmapSupportExit;
95 }
96 
97 /**
98 * \brief Registration Function for DecodeNetmap.
99 */
101 {
102  tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap";
103  tmm_modules[TMM_DECODENETMAP].ThreadInit = NoNetmapSupportExit;
105 }
106 
107 #else /* We have NETMAP support */
108 
109 #define POLL_TIMEOUT 100
110 
111 #if defined(__linux__)
112 #define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL)
113 
114 #ifndef IFF_PPROMISC
115 #define IFF_PPROMISC IFF_PROMISC
116 #endif
117 
118 #else
119 #define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL)
120 #endif
121 
122 enum {
123  NETMAP_OK,
124  NETMAP_FAILURE,
125 };
126 
127 enum {
128  NETMAP_FLAG_ZERO_COPY = 1,
129 };
130 
131 /**
132  * \brief Netmap device instance. Each ring for each device gets its own
133  * device.
134  */
135 typedef struct NetmapDevice_
136 {
137  struct nm_desc *nmd;
138  unsigned int ref;
139  SC_ATOMIC_DECLARE(unsigned int, threads_run);
140  TAILQ_ENTRY(NetmapDevice_) next;
141  // actual ifname can only be 16, but we store a bit more,
142  // like the options string and a 'netmap:' prefix.
143  char ifname[32];
144  int ring;
145  int direction; // 0 rx, 1 tx
146 } NetmapDevice;
147 
148 /**
149  * \brief Module thread local variables.
150  */
151 typedef struct NetmapThreadVars_
152 {
153  /* receive inteface */
154  NetmapDevice *ifsrc;
155  /* dst interface for IPS mode */
156  NetmapDevice *ifdst;
157 
158  int flags;
159  struct bpf_program bpf_prog;
160 
161  /* suricata internals */
162  TmSlot *slot;
163  ThreadVars *tv;
164  LiveDevice *livedev;
165 
166  /* copy from config */
167  int copy_mode;
168  ChecksumValidationMode checksum_mode;
169 
170  /* counters */
171  uint64_t pkts;
172  uint64_t bytes;
173  uint64_t drops;
174  uint16_t capture_kernel_packets;
175  uint16_t capture_kernel_drops;
176 } NetmapThreadVars;
177 
178 typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList;
179 
180 static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist);
181 static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER;
182 
183 /** \brief get RSS RX-queue count
184  * \retval rx_rings RSS RX queue count or 0 on error
185  */
186 int NetmapGetRSSCount(const char *ifname)
187 {
188  struct nmreq nm_req;
189  int rx_rings = 0;
190 
191  SCMutexLock(&netmap_devlist_lock);
192 
193  /* open netmap */
194  int fd = open("/dev/netmap", O_RDWR);
195  if (fd == -1) {
197  "Couldn't open netmap device, error %s",
198  strerror(errno));
199  goto error_open;
200  }
201 
202  /* query netmap info */
203  memset(&nm_req, 0, sizeof(nm_req));
204  strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name));
205  nm_req.nr_version = NETMAP_API;
206 
207  if (ioctl(fd, NIOCGINFO, &nm_req) != 0) {
209  "Couldn't query netmap for %s, error %s",
210  ifname, strerror(errno));
211  goto error_fd;
212  };
213 
214  rx_rings = nm_req.nr_rx_rings;
215 
216 error_fd:
217  close(fd);
218 error_open:
219  SCMutexUnlock(&netmap_devlist_lock);
220  return rx_rings;
221 }
222 
223 /**
224  * \brief Open interface in netmap mode.
225  * \param ifname Interface name.
226  * \param promisc Enable promiscuous mode.
227  * \param dev Pointer to requested netmap device instance.
228  * \param verbose Verbose error logging.
229  * \return Zero on success.
230  */
231 static int NetmapOpen(NetmapIfaceSettings *ns,
232  NetmapDevice **pdevice, int verbose, int read, bool zerocopy)
233 {
234  SCEnter();
235  SCLogDebug("ifname %s", ns->iface);
236 
237  char base_name[IFNAMSIZ];
238  strlcpy(base_name, ns->iface, sizeof(base_name));
239  if (strlen(base_name) > 0 &&
240  (base_name[strlen(base_name)-1] == '^' ||
241  base_name[strlen(base_name)-1] == '*'))
242  {
243  base_name[strlen(base_name)-1] = '\0';
244  }
245 
246  if (ns->real) {
247  /* check interface is up */
248  int if_flags = GetIfaceFlags(base_name);
249  if (if_flags == -1) {
250  if (verbose) {
252  "Can not access to interface '%s' (%s)",
253  base_name, ns->iface);
254  }
255  goto error;
256  }
257 
258  /* bring iface up if it is down */
259  if ((if_flags & IFF_UP) == 0) {
260  SCLogError(SC_ERR_NETMAP_CREATE, "interface '%s' (%s) is down", base_name, ns->iface);
261  goto error;
262  }
263  /* if needed, try to set iface in promisc mode */
264  if (ns->promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) {
265  if_flags |= IFF_PPROMISC;
266  SetIfaceFlags(base_name, if_flags); // TODO reset at exit
267  // TODO move to parse config?
268  }
269  }
270  NetmapDevice *pdev = NULL, *spdev = NULL;
271  pdev = SCMalloc(sizeof(*pdev));
272  if (unlikely(pdev == NULL)) {
273  SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed");
274  goto error;
275  }
276  memset(pdev, 0, sizeof(*pdev));
277  SC_ATOMIC_INIT(pdev->threads_run);
278 
279  SCMutexLock(&netmap_devlist_lock);
280 
281  const int direction = (read != 1);
282  int ring = 0;
283  /* search interface in our already opened list */
284  TAILQ_FOREACH(spdev, &netmap_devlist, next) {
285  SCLogDebug("spdev %s", spdev->ifname);
286  if (direction == spdev->direction && strcmp(ns->iface, spdev->ifname) == 0) {
287  ring = spdev->ring + 1;
288  }
289  }
290  SCLogDebug("netmap/%s: using ring %d", ns->iface, ring);
291 
292  const char *opt_R = "R";
293  const char *opt_T = "T";
294  const char *opt_x = "x"; // not for IPS
295  const char *opt_z = "z"; // zero copy, not for IPS
296 
297  // FreeBSD 11 doesn't have R and T.
298 #if NETMAP_API<=11
299  opt_R = "";
300  opt_T = "";
301 #endif
302  /* assemble options string */
303  char optstr[16];
304  if (ns->ips)
305  opt_x = "";
306 // z seems to not play well with multiple opens of a real dev on linux
307 // if (!zerocopy || ips)
308  opt_z = "";
309 
310  // loop to retry opening if unsupported options are used
311 retry:
312  snprintf(optstr, sizeof(optstr), "%s%s%s", opt_z, opt_x, direction == 0 ? opt_R : opt_T);
313 
314  char devname[128];
315  if (strncmp(ns->iface, "netmap:", 7) == 0) {
316  snprintf(devname, sizeof(devname), "%s}%d%s%s",
317  ns->iface, ring, strlen(optstr) ? "/" : "", optstr);
318  } else if (strlen(ns->iface) > 5 && strncmp(ns->iface, "vale", 4) == 0 && isdigit(ns->iface[4])) {
319  snprintf(devname, sizeof(devname), "%s", ns->iface);
320  } else if (ns->iface[strlen(ns->iface)-1] == '*' ||
321  ns->iface[strlen(ns->iface)-1] == '^') {
322  SCLogDebug("device with SW-ring enabled (ns->iface): %s",ns->iface);
323  snprintf(devname, sizeof(devname), "netmap:%s", ns->iface);
324  SCLogDebug("device with SW-ring enabled (devname): %s",devname);
325  /* just a single ring, so don't use ring param */
326  } else if (ring == 0 && ns->threads == 1) {
327  snprintf(devname, sizeof(devname), "netmap:%s%s%s",
328  ns->iface, strlen(optstr) ? "/" : "", optstr);
329  } else {
330  snprintf(devname, sizeof(devname), "netmap:%s-%d%s%s",
331  ns->iface, ring, strlen(optstr) ? "/" : "", optstr);
332  }
333  strlcpy(pdev->ifname, ns->iface, sizeof(pdev->ifname));
334 
335  pdev->nmd = nm_open(devname, NULL, 0, NULL);
336  if (pdev->nmd == NULL) {
337  if (errno == EINVAL && opt_z[0] == 'z') {
338  SCLogNotice("got '%s' EINVAL: going to retry without 'z'", devname);
339  opt_z = "";
340  goto retry;
341  } else if (errno == EINVAL && opt_x[0] == 'x') {
342  SCLogNotice("dev '%s' got EINVAL: going to retry without 'x'", devname);
343  opt_x = "";
344  goto retry;
345  }
346 
347  SCLogError(SC_ERR_NETMAP_CREATE, "opening devname %s failed: %s",
348  devname, strerror(errno));
349  exit(EXIT_FAILURE);
350  }
351  SCLogDebug("devname %s %s opened", devname, ns->iface);
352 
353  pdev->direction = direction;
354  pdev->ring = ring;
355  TAILQ_INSERT_TAIL(&netmap_devlist, pdev, next);
356 
357  SCLogNotice("opened %s from %s: %p", devname, ns->iface, pdev->nmd);
358  SCMutexUnlock(&netmap_devlist_lock);
359  *pdevice = pdev;
360 
361  return 0;
362 error:
363  return -1;
364 }
365 
366 /**
367  * \brief Close or dereference netmap device instance.
368  * \param pdev Netmap device instance.
369  * \return Zero on success.
370  */
371 static int NetmapClose(NetmapDevice *dev)
372 {
373  NetmapDevice *pdev, *tmp;
374 
375  SCMutexLock(&netmap_devlist_lock);
376 
377  TAILQ_FOREACH_SAFE(pdev, &netmap_devlist, next, tmp) {
378  if (pdev == dev) {
379  pdev->ref--;
380  if (!pdev->ref) {
381  nm_close(pdev->nmd);
382  SCFree(pdev);
383  }
384  SCMutexUnlock(&netmap_devlist_lock);
385  return 0;
386  }
387  }
388 
389  SCMutexUnlock(&netmap_devlist_lock);
390  return -1;
391 }
392 
393 /**
394  * \brief PcapDumpCounters
395  * \param ntv
396  */
397 static inline void NetmapDumpCounters(NetmapThreadVars *ntv)
398 {
399  StatsAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts);
400  StatsAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops);
401  (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops);
402  (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts);
403  ntv->drops = 0;
404  ntv->pkts = 0;
405 }
406 
407 /**
408  * \brief Init function for ReceiveNetmap.
409  * \param tv pointer to ThreadVars
410  * \param initdata pointer to the interface passed from the user
411  * \param data pointer gets populated with NetmapThreadVars
412  */
413 static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, const void *initdata, void **data)
414 {
415  SCEnter();
416  NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)initdata;
417 
418  if (initdata == NULL) {
419  SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL");
421  }
422 
423  NetmapThreadVars *ntv = SCMalloc(sizeof(*ntv));
424  if (unlikely(ntv == NULL)) {
425  SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed");
426  goto error;
427  }
428  memset(ntv, 0, sizeof(*ntv));
429 
430  ntv->tv = tv;
431  ntv->checksum_mode = aconf->in.checksum_mode;
432  ntv->copy_mode = aconf->in.copy_mode;
433 
434  ntv->livedev = LiveGetDevice(aconf->iface_name);
435  if (ntv->livedev == NULL) {
436  SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device");
437  goto error_ntv;
438  }
439 
440  /* enable zero-copy mode for workers runmode */
441  char const *active_runmode = RunmodeGetActive();
442  if (strcmp("workers", active_runmode) == 0) {
443  ntv->flags |= NETMAP_FLAG_ZERO_COPY;
444  SCLogDebug("Enabling zero copy mode for %s", aconf->in.iface);
445  }
446 
447  if (NetmapOpen(&aconf->in, &ntv->ifsrc, 1, 1,
448  (ntv->flags & NETMAP_FLAG_ZERO_COPY) != 0) != 0) {
449  goto error_ntv;
450  }
451 
452  if (unlikely(aconf->in.sw_ring && aconf->in.threads > 1)) {
454  "Interface '%s+'. "
455  "Thread count can't be greater than 1 for SW ring.",
456  aconf->iface_name);
457  goto error_src;
458  }
459 
460  if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
461  SCLogDebug("IPS: opening out iface %s", aconf->out.iface);
462  if (NetmapOpen(&aconf->out, &ntv->ifdst,
463  1, 0, false) != 0) {
464  goto error_src;
465  }
466  }
467 
468  /* basic counters */
469  ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets",
470  ntv->tv);
471  ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
472  ntv->tv);
473 
474  if (aconf->in.bpf_filter) {
475  SCLogConfig("Using BPF '%s' on iface '%s'",
476  aconf->in.bpf_filter, ntv->ifsrc->ifname);
477  char errbuf[PCAP_ERRBUF_SIZE];
478  if (SCBPFCompile(default_packet_size, /* snaplen_arg */
479  LINKTYPE_ETHERNET, /* linktype_arg */
480  &ntv->bpf_prog, /* program */
481  aconf->in.bpf_filter, /* const char *buf */
482  1, /* optimize */
483  PCAP_NETMASK_UNKNOWN, /* mask */
484  errbuf,
485  sizeof(errbuf)) == -1)
486  {
487  SCLogError(SC_ERR_NETMAP_CREATE, "Failed to compile BPF \"%s\": %s",
488  aconf->in.bpf_filter,
489  errbuf);
490  goto error_dst;
491  }
492  }
493 
494  *data = (void *)ntv;
495  aconf->DerefFunc(aconf);
497 error_dst:
498  if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) {
499  NetmapClose(ntv->ifdst);
500  }
501 error_src:
502  NetmapClose(ntv->ifsrc);
503 error_ntv:
504  SCFree(ntv);
505 error:
506  aconf->DerefFunc(aconf);
508 }
509 
510 /**
511  * \brief Output packet to destination interface or drop.
512  * \param ntv Thread local variables.
513  * \param p Source packet.
514  */
515 static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p)
516 {
517  if (ntv->copy_mode == NETMAP_COPY_MODE_IPS) {
519  return TM_ECODE_OK;
520  }
521  }
522  DEBUG_VALIDATE_BUG_ON(ntv->ifdst == NULL);
523 
524  if (nm_inject(ntv->ifdst->nmd, GET_PKT_DATA(p), GET_PKT_LEN(p)) == 0) {
525  SCLogDebug("failed to send %s -> %s",
526  ntv->ifsrc->ifname, ntv->ifdst->ifname);
527  ntv->drops++;
528  }
529  SCLogDebug("sent succesfully: %s(%d)->%s(%d) (%u)",
530  ntv->ifsrc->ifname, ntv->ifsrc->ring,
531  ntv->ifdst->ifname, ntv->ifdst->ring, GET_PKT_LEN(p));
532 
533  ioctl(ntv->ifdst->nmd->fd, NIOCTXSYNC, 0);
534  return TM_ECODE_OK;
535 }
536 
537 /**
538  * \brief Packet release routine.
539  * \param p Packet.
540  */
541 static void NetmapReleasePacket(Packet *p)
542 {
543  NetmapThreadVars *ntv = (NetmapThreadVars *)p->netmap_v.ntv;
544 
545  if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) {
546  NetmapWritePacket(ntv, p);
547  }
548 
550 }
551 
552 static void NetmapCallback(u_char *user, const struct nm_pkthdr *ph, const u_char *d)
553 {
554  NetmapThreadVars *ntv = (NetmapThreadVars *)user;
555 
556  if (ntv->bpf_prog.bf_len) {
557  struct pcap_pkthdr pkthdr = { {0, 0}, ph->len, ph->len };
558  if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, d) == 0) {
559  return;
560  }
561  }
562 
564  if (unlikely(p == NULL)) {
565  return;
566  }
567 
569  p->livedev = ntv->livedev;
571  p->ts = ph->ts;
572  ntv->pkts++;
573  ntv->bytes += ph->len;
574 
575  if (ntv->flags & NETMAP_FLAG_ZERO_COPY) {
576  if (PacketSetData(p, (uint8_t *)d, ph->len) == -1) {
577  TmqhOutputPacketpool(ntv->tv, p);
578  return;
579  }
580  } else {
581  if (PacketCopyData(p, (uint8_t *)d, ph->len) == -1) {
582  TmqhOutputPacketpool(ntv->tv, p);
583  return;
584  }
585  }
586 
587  p->ReleasePacket = NetmapReleasePacket;
588  p->netmap_v.ntv = ntv;
589 
590  SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)",
591  GET_PKT_LEN(p), p, GET_PKT_DATA(p));
592 
593  if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) {
594  TmqhOutputPacketpool(ntv->tv, p);
595  return;
596  }
597  return;
598 }
599 
600 /**
601  * \brief Main netmap reading loop function
602  */
603 static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot)
604 {
605  SCEnter();
606 
607  TmSlot *s = (TmSlot *)slot;
608  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
609  struct pollfd fds;
610 
611  ntv->slot = s->slot_next;
612  fds.fd = ntv->ifsrc->nmd->fd;
613  fds.events = POLLIN;
614 
615  for(;;) {
616  if (unlikely(suricata_ctl_flags != 0)) {
617  break;
618  }
619 
620  /* make sure we have at least one packet in the packet pool,
621  * to prevent us from alloc'ing packets at line rate */
622  PacketPoolWait();
623 
624  int r = poll(&fds, 1, POLL_TIMEOUT);
625  if (r < 0) {
626  /* error */
627  if (errno != EINTR)
629  "Error polling netmap from iface '%s': (%d" PRIu32 ") %s",
630  ntv->ifsrc->ifname, errno, strerror(errno));
631  continue;
632 
633  } else if (r == 0) {
634  /* no events, timeout */
635  //SCLogDebug("(%s:%d-%d) Poll timeout", ntv->ifsrc->ifname,
636  // ntv->src_ring_from, ntv->src_ring_to);
637 
638  /* sync counters */
639  NetmapDumpCounters(ntv);
641 
642  /* poll timed out, lets handle the timeout */
643  TmThreadsCaptureHandleTimeout(tv, ntv->slot, NULL);
644  continue;
645  }
646 
647  if (unlikely(fds.revents & POLL_EVENTS)) {
648  if (fds.revents & POLLERR) {
649  //SCLogError(SC_ERR_NETMAP_READ,
650  // "Error reading data from iface '%s': (%d" PRIu32 ") %s",
651  // ntv->ifsrc->ifname, errno, strerror(errno));
652  } else if (fds.revents & POLLNVAL) {
654  "Invalid polling request");
655  }
656  continue;
657  }
658 
659  if (likely(fds.revents & POLLIN)) {
660  nm_dispatch(ntv->ifsrc->nmd, -1, NetmapCallback, (void *)ntv);
661  }
662 
663  NetmapDumpCounters(ntv);
665  }
666 
667  NetmapDumpCounters(ntv);
670 }
671 
672 /**
673  * \brief This function prints stats to the screen at exit.
674  * \param tv pointer to ThreadVars
675  * \param data pointer that gets cast into NetmapThreadVars for ntv
676  */
677 static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data)
678 {
679  SCEnter();
680  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
681 
682  NetmapDumpCounters(ntv);
683  SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "",
684  tv->name,
685  StatsGetLocalCounterValue(tv, ntv->capture_kernel_packets),
686  StatsGetLocalCounterValue(tv, ntv->capture_kernel_drops),
687  ntv->bytes);
688 }
689 
690 /**
691  * \brief
692  * \param tv
693  * \param data Pointer to NetmapThreadVars.
694  */
695 static TmEcode ReceiveNetmapThreadDeinit(ThreadVars *tv, void *data)
696 {
697  SCEnter();
698 
699  NetmapThreadVars *ntv = (NetmapThreadVars *)data;
700 
701  if (ntv->ifsrc) {
702  NetmapClose(ntv->ifsrc);
703  ntv->ifsrc = NULL;
704  }
705  if (ntv->ifdst) {
706  NetmapClose(ntv->ifdst);
707  ntv->ifdst = NULL;
708  }
709  if (ntv->bpf_prog.bf_insns) {
710  SCBPFFree(&ntv->bpf_prog);
711  }
712 
713  SCFree(ntv);
714 
716 }
717 
718 /**
719  * \brief Prepare netmap decode thread.
720  * \param tv Thread local avariables.
721  * \param initdata Thread config.
722  * \param data Pointer to DecodeThreadVars placed here.
723  */
724 static TmEcode DecodeNetmapThreadInit(ThreadVars *tv, const void *initdata, void **data)
725 {
726  SCEnter();
727 
729  if (dtv == NULL)
731 
733 
734  *data = (void *)dtv;
735 
737 }
738 
739 /**
740  * \brief This function passes off to link type decoders.
741  *
742  * DecodeNetmap reads packets from the PacketQueue and passes
743  * them off to the proper link type decoder.
744  *
745  * \param t pointer to ThreadVars
746  * \param p pointer to the current packet
747  * \param data pointer that gets cast into NetmapThreadVars for ntv
748  * \param pq pointer to the current PacketQueue
749  * \param postpq
750  */
751 static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
752 {
753  SCEnter();
754 
755  DecodeThreadVars *dtv = (DecodeThreadVars *)data;
756 
757  /* XXX HACK: flow timeout can call us for injected pseudo packets
758  * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */
759  if (p->flags & PKT_PSEUDO_STREAM_END)
761 
762  /* update counters */
763  DecodeUpdatePacketCounters(tv, dtv, p);
764 
765  DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
766 
767  PacketDecodeFinalize(tv, dtv, p);
768 
770 }
771 
772 /**
773  * \brief
774  * \param tv
775  * \param data Pointer to DecodeThreadVars.
776  */
777 static TmEcode DecodeNetmapThreadDeinit(ThreadVars *tv, void *data)
778 {
779  SCEnter();
780 
781  if (data != NULL)
782  DecodeThreadVarsFree(tv, data);
783 
785 }
786 
787 /**
788  * \brief Registration Function for ReceiveNetmap.
789  */
791 {
792  tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap";
793  tmm_modules[TMM_RECEIVENETMAP].ThreadInit = ReceiveNetmapThreadInit;
794  tmm_modules[TMM_RECEIVENETMAP].PktAcqLoop = ReceiveNetmapLoop;
795  tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = ReceiveNetmapThreadExitStats;
796  tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = ReceiveNetmapThreadDeinit;
799 }
800 
801 /**
802  * \brief Registration Function for DecodeNetmap.
803  */
805 {
806  tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap";
807  tmm_modules[TMM_DECODENETMAP].ThreadInit = DecodeNetmapThreadInit;
808  tmm_modules[TMM_DECODENETMAP].Func = DecodeNetmap;
809  tmm_modules[TMM_DECODENETMAP].ThreadDeinit = DecodeNetmapThreadDeinit;
812 }
813 
814 #endif /* HAVE_NETMAP */
815 
816 /**
817 * @}
818 */
#define SCMutex
#define TM_FLAG_DECODE_TM
Definition: tm-modules.h:32
uint16_t flags
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition: decode.c:614
#define SCLogDebug(...)
Definition: util-debug.h:335
#define SC_ATOMIC_DECLARE(type, name)
wrapper to declare an atomic variable including a (spin) lock to protect it.
Definition: util-atomic.h:56
uint8_t cap_flags
Definition: tm-modules.h:67
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
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
uint8_t flags
Definition: tm-modules.h:70
#define PACKET_TEST_ACTION(p, a)
Definition: decode.h:857
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition: decode.c:115
#define POLL_TIMEOUT
#define unlikely(expr)
Definition: util-optimize.h:35
TmEcode(* Func)(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *)
Definition: tm-modules.h:52
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition: decode.c:474
NetmapIfaceSettings in
Definition: source-netmap.h:63
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:356
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:201
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition: tm-modules.h:54
void(* ReleasePacket)(struct Packet_ *)
Definition: decode.h:484
#define SCMutexLock(mut)
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition: decode.c:162
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
char * RunmodeGetActive(void)
Definition: runmodes.c:187
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1135
#define TM_FLAG_RECEIVE_TM
Definition: tm-modules.h:31
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:943
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
#define SCMutexUnlock(mut)
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
int datalink
Definition: decode.h:574
#define SCMUTEX_INITIALIZER
void(* DerefFunc)(void *)
Definition: source-netmap.h:69
void TmModuleReceiveNetmapRegister(void)
Definition: source-netmap.c:90
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
Structure to hold thread specific data for all decode modules.
Definition: decode.h:632
int NetmapGetRSSCount(const char *ifname)
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:49
#define SCEnter(...)
Definition: util-debug.h:337
struct TmSlot_ * slot_next
Definition: tm-threads.h:87
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:41
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1094
void TmModuleDecodeNetmapRegister(void)
Registration Function for DecodeNetmap.
#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
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition: tm-modules.h:48
NetmapIfaceSettings out
Definition: source-netmap.h:66
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Set data for Packet and set length when zeo copy is used.
Definition: decode.c:653
#define SC_CAP_NET_RAW
Definition: util-privs.h:32
void PacketPoolWait(void)
char iface[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:42
const char * name
Definition: tm-modules.h:44
#define SCMalloc(a)
Definition: util-mem.h:222
ChecksumValidationMode checksum_mode
Definition: source-netmap.h:53
#define SCFree(a)
Definition: util-mem.h:322
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.h:73
#define TAILQ_ENTRY(type)
Definition: queue.h:330
uint32_t default_packet_size
Definition: decode.h:617
#define SCLogPerf(...)
Definition: util-debug.h:261
#define StatsSyncCountersIfSignalled(tv)
Definition: counters.h:137
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:47
ChecksumValidationMode
Definition: decode.h:40
#define GET_PKT_DATA(p)
Definition: decode.h:225
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition: decode.c:580
char name[16]
Definition: threadvars.h:59
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1132
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:259
#define LINKTYPE_ETHERNET
Definition: decode.h:1073
struct LiveDevice_ * livedev
Definition: decode.h:553
Per thread variable structure.
Definition: threadvars.h:57
struct timeval ts
Definition: decode.h:451
char iface_name[NETMAP_IFACE_NAME_LENGTH]
Definition: source-netmap.h:60
#define GET_PKT_LEN(p)
Definition: decode.h:224
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:327
#define ACTION_DROP
uint32_t flags
Definition: decode.h:443
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:147
#define likely(expr)
Definition: util-optimize.h:32
void SCBPFFree(struct bpf_program *program)
Definition: util-bpf.c:35
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition: decode.c:633
#define DEBUG_VALIDATE_BUG_ON(exp)
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:1244