suricata
source-dpdk.c
Go to the documentation of this file.
1 /* Copyright (C) 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 dpdk DPDK running mode
20  *
21  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Lukas Sismis <lukas.sismis@gmail.com>
28  *
29  * DPDK capture interface
30  *
31  */
32 
33 #include "suricata-common.h"
34 #include "runmodes.h"
35 #include "decode.h"
36 #include "packet.h"
37 #include "source-dpdk.h"
38 #include "suricata.h"
39 #include "threads.h"
40 #include "threadvars.h"
41 #include "tm-threads.h"
42 #include "tmqh-packetpool.h"
43 #include "util-privs.h"
44 #include "action-globals.h"
45 
46 #ifndef HAVE_DPDK
47 
48 TmEcode NoDPDKSupportExit(ThreadVars *, const void *, void **);
49 
51 {
52  tmm_modules[TMM_RECEIVEDPDK].name = "ReceiveDPDK";
59 }
60 
61 /**
62  * \brief Registration Function for DecodeDPDK.
63  */
65 {
66  tmm_modules[TMM_DECODEDPDK].name = "DecodeDPDK";
73 }
74 
75 /**
76  * \brief this function prints an error message and exits.
77  */
78 TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data)
79 {
80  FatalError("Error creating thread %s: you do not have "
81  "support for DPDK enabled, on Linux host please recompile "
82  "with --enable-dpdk",
83  tv->name);
84 }
85 
86 #else /* We have DPDK support */
87 
88 #include "util-affinity.h"
89 #include "util-dpdk.h"
90 #include "util-dpdk-i40e.h"
91 #include "util-dpdk-bonding.h"
92 #include <numa.h>
93 
94 #define BURST_SIZE 32
95 static struct timeval machine_start_time = { 0, 0 };
96 
97 /**
98  * \brief Structure to hold thread specific variables.
99  */
100 typedef struct DPDKThreadVars_ {
101  /* counters */
102  uint64_t pkts;
103  ThreadVars *tv;
104  TmSlot *slot;
105  LiveDevice *livedev;
106  ChecksumValidationMode checksum_mode;
107  /* references to packet and drop counters */
108  uint16_t capture_dpdk_packets;
109  uint16_t capture_dpdk_rx_errs;
110  uint16_t capture_dpdk_imissed;
111  uint16_t capture_dpdk_rx_no_mbufs;
112  uint16_t capture_dpdk_ierrors;
113  uint16_t capture_dpdk_tx_errs;
114  unsigned int flags;
115  int threads;
116  /* for IPS */
117  DpdkCopyModeEnum copy_mode;
118  uint16_t out_port_id;
119  /* Entry in the peers_list */
120 
121  uint64_t bytes;
122  uint64_t accepted;
123  uint64_t dropped;
124  uint16_t port_id;
125  uint16_t queue_id;
126  int32_t port_socket_id;
127  struct rte_mempool *pkt_mempool;
128  struct rte_mbuf *received_mbufs[BURST_SIZE];
129 } DPDKThreadVars;
130 
131 static TmEcode ReceiveDPDKThreadInit(ThreadVars *, const void *, void **);
132 static void ReceiveDPDKThreadExitStats(ThreadVars *, void *);
133 static TmEcode ReceiveDPDKThreadDeinit(ThreadVars *, void *);
134 static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot);
135 
136 static TmEcode DecodeDPDKThreadInit(ThreadVars *, const void *, void **);
137 static TmEcode DecodeDPDKThreadDeinit(ThreadVars *tv, void *data);
138 static TmEcode DecodeDPDK(ThreadVars *, Packet *, void *);
139 
140 static uint64_t CyclesToMicroseconds(uint64_t cycles);
141 static uint64_t CyclesToSeconds(uint64_t cycles);
142 static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset);
143 static uint64_t DPDKGetSeconds(void);
144 
145 static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset)
146 {
147  for (int i = offset; i < mbuf_cnt; i++) {
148  rte_pktmbuf_free(mbuf_array[i]);
149  }
150 }
151 
152 static uint64_t CyclesToMicroseconds(const uint64_t cycles)
153 {
154  const uint64_t ticks_per_us = rte_get_tsc_hz() / 1000000;
155  if (ticks_per_us == 0) {
156  return 0;
157  }
158  return cycles / ticks_per_us;
159 }
160 
161 static uint64_t CyclesToSeconds(const uint64_t cycles)
162 {
163  const uint64_t ticks_per_s = rte_get_tsc_hz();
164  if (ticks_per_s == 0) {
165  return 0;
166  }
167  return cycles / ticks_per_s;
168 }
169 
170 static void CyclesAddToTimeval(
171  const uint64_t cycles, struct timeval *orig_tv, struct timeval *new_tv)
172 {
173  uint64_t usec = CyclesToMicroseconds(cycles) + orig_tv->tv_usec;
174  new_tv->tv_sec = orig_tv->tv_sec + usec / 1000000;
175  new_tv->tv_usec = (usec % 1000000);
176 }
177 
179 {
180  gettimeofday(&machine_start_time, NULL);
181  machine_start_time.tv_sec -= DPDKGetSeconds();
182 }
183 
184 /**
185  * Initializes real_tv to the correct real time. Adds TSC counter value to the timeval of
186  * the machine start
187  * @param machine_start_tv - timestamp when the machine was started
188  * @param real_tv
189  */
190 static SCTime_t DPDKSetTimevalReal(struct timeval *machine_start_tv)
191 {
192  struct timeval real_tv;
193  CyclesAddToTimeval(rte_get_tsc_cycles(), machine_start_tv, &real_tv);
194  return SCTIME_FROM_TIMEVAL(&real_tv);
195 }
196 
197 /* get number of seconds from the reset of TSC counter (typically from the machine start) */
198 static uint64_t DPDKGetSeconds(void)
199 {
200  return CyclesToSeconds(rte_get_tsc_cycles());
201 }
202 
203 static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
204 {
205  if (strcmp(driver_name, "net_bonding") == 0) {
206  driver_name = BondingDeviceDriverGet(ptv->port_id);
207  }
208 
209  // The PMD Driver i40e has a special way to set the RSS, it can be set via rte_flow rules
210  // and only after the start of the port
211  if (strcmp(driver_name, "net_i40e") == 0)
212  i40eDeviceSetRSS(ptv->port_id, ptv->threads);
213 }
214 
215 static void DevicePreClosePMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
216 {
217  if (strcmp(driver_name, "net_bonding") == 0) {
218  driver_name = BondingDeviceDriverGet(ptv->port_id);
219  }
220 
221  if (strcmp(driver_name, "net_i40e") == 0) {
222 #if RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0)
223  // Flush the RSS rules that have been inserted in the post start section
224  struct rte_flow_error flush_error = { 0 };
225  int32_t retval = rte_flow_flush(ptv->port_id, &flush_error);
226  if (retval != 0) {
227  SCLogError("%s: unable to flush rte_flow rules: %s Flush error msg: %s",
228  ptv->livedev->dev, rte_strerror(-retval), flush_error.message);
229  }
230 #endif /* RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0) */
231  }
232 }
233 
234 /**
235  * Attempts to retrieve NUMA node id on which the caller runs
236  * @return NUMA id on success, -1 otherwise
237  */
238 static int GetNumaNode(void)
239 {
240  int cpu = 0;
241  int node = -1;
242 
243 #if defined(__linux__)
244  cpu = sched_getcpu();
245  node = numa_node_of_cpu(cpu);
246 #else
247  SCLogWarning("NUMA node retrieval is not supported on this OS.");
248 #endif
249 
250  return node;
251 }
252 
253 /**
254  * \brief Registration Function for ReceiveDPDK.
255  * \todo Unit tests are needed for this module.
256  */
258 {
259  tmm_modules[TMM_RECEIVEDPDK].name = "ReceiveDPDK";
260  tmm_modules[TMM_RECEIVEDPDK].ThreadInit = ReceiveDPDKThreadInit;
262  tmm_modules[TMM_RECEIVEDPDK].PktAcqLoop = ReceiveDPDKLoop;
264  tmm_modules[TMM_RECEIVEDPDK].ThreadExitPrintStats = ReceiveDPDKThreadExitStats;
265  tmm_modules[TMM_RECEIVEDPDK].ThreadDeinit = ReceiveDPDKThreadDeinit;
268 }
269 
270 /**
271  * \brief Registration Function for DecodeDPDK.
272  * \todo Unit tests are needed for this module.
273  */
275 {
276  tmm_modules[TMM_DECODEDPDK].name = "DecodeDPDK";
277  tmm_modules[TMM_DECODEDPDK].ThreadInit = DecodeDPDKThreadInit;
278  tmm_modules[TMM_DECODEDPDK].Func = DecodeDPDK;
280  tmm_modules[TMM_DECODEDPDK].ThreadDeinit = DecodeDPDKThreadDeinit;
283 }
284 
285 static inline void DPDKDumpCounters(DPDKThreadVars *ptv)
286 {
287  /* Some NICs (e.g. Intel) do not support queue statistics and the drops can be fetched only on
288  * the port level. Therefore setting it to the first worker to have at least continuous update
289  * on the dropped packets. */
290  if (ptv->queue_id == 0) {
291  struct rte_eth_stats eth_stats;
292  int retval = rte_eth_stats_get(ptv->port_id, &eth_stats);
293  if (unlikely(retval != 0)) {
294  SCLogError("%s: failed to get stats: %s", ptv->livedev->dev, rte_strerror(-retval));
295  return;
296  }
297 
298  StatsSetUI64(ptv->tv, ptv->capture_dpdk_packets,
299  ptv->pkts + eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
300  SC_ATOMIC_SET(ptv->livedev->pkts,
301  eth_stats.ipackets + eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
302  StatsSetUI64(ptv->tv, ptv->capture_dpdk_rx_errs,
303  eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
304  StatsSetUI64(ptv->tv, ptv->capture_dpdk_imissed, eth_stats.imissed);
305  StatsSetUI64(ptv->tv, ptv->capture_dpdk_rx_no_mbufs, eth_stats.rx_nombuf);
306  StatsSetUI64(ptv->tv, ptv->capture_dpdk_ierrors, eth_stats.ierrors);
307  StatsSetUI64(ptv->tv, ptv->capture_dpdk_tx_errs, eth_stats.oerrors);
309  ptv->livedev->drop, eth_stats.imissed + eth_stats.ierrors + eth_stats.rx_nombuf);
310  } else {
311  StatsSetUI64(ptv->tv, ptv->capture_dpdk_packets, ptv->pkts);
312  }
313 }
314 
315 static void DPDKReleasePacket(Packet *p)
316 {
317  int retval;
318  /* Need to be in copy mode and need to detect early release
319  where Ethernet header could not be set (and pseudo packet)
320  When enabling promiscuous mode on Intel cards, 2 ICMPv6 packets are generated.
321  These get into the infinite cycle between the NIC and the switch in some cases */
322  if ((p->dpdk_v.copy_mode == DPDK_COPY_MODE_TAP ||
323  (p->dpdk_v.copy_mode == DPDK_COPY_MODE_IPS && !PacketCheckAction(p, ACTION_DROP)))
324 #if defined(RTE_LIBRTE_I40E_PMD) || defined(RTE_LIBRTE_IXGBE_PMD) || defined(RTE_LIBRTE_ICE_PMD)
325  && !(PKT_IS_ICMPV6(p) && p->icmpv6h->type == 143)
326 #endif
327  ) {
329  retval =
330  rte_eth_tx_burst(p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id, &p->dpdk_v.mbuf, 1);
331  // rte_eth_tx_burst can return only 0 (failure) or 1 (success) because we are only
332  // transmitting burst of size 1 and the function rte_eth_tx_burst returns number of
333  // successfully sent packets.
334  if (unlikely(retval < 1)) {
335  // sometimes a repeated transmit can help to send out the packet
336  rte_delay_us(DPDK_BURST_TX_WAIT_US);
337  retval = rte_eth_tx_burst(
338  p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id, &p->dpdk_v.mbuf, 1);
339  if (unlikely(retval < 1)) {
340  SCLogDebug("Unable to transmit the packet on port %u queue %u",
341  p->dpdk_v.out_port_id, p->dpdk_v.out_queue_id);
342  rte_pktmbuf_free(p->dpdk_v.mbuf);
343  p->dpdk_v.mbuf = NULL;
344  }
345  }
346  } else {
347  rte_pktmbuf_free(p->dpdk_v.mbuf);
348  p->dpdk_v.mbuf = NULL;
349  }
350 
352 }
353 
354 /**
355  * \brief Main DPDK reading Loop function
356  */
357 static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
358 {
359  SCEnter();
360  Packet *p;
361  uint16_t nb_rx;
362  time_t last_dump = 0;
363  time_t current_time;
364  bool segmented_mbufs_warned = 0;
365  SCTime_t t = DPDKSetTimevalReal(&machine_start_time);
366  uint64_t last_timeout_msec = SCTIME_MSECS(t);
367 
368  DPDKThreadVars *ptv = (DPDKThreadVars *)data;
369  TmSlot *s = (TmSlot *)slot;
370 
371  ptv->slot = s->slot_next;
372 
373  // Indicate that the thread is actually running its application level code (i.e., it can poll
374  // packets)
376  PacketPoolWait();
377 
378  rte_eth_stats_reset(ptv->port_id);
379  rte_eth_xstats_reset(ptv->port_id);
380  while (1) {
381  if (unlikely(suricata_ctl_flags != 0)) {
382  SCLogDebug("Stopping Suricata!");
383  if (ptv->queue_id == 0) {
384  rte_eth_dev_stop(ptv->port_id);
385  if (ptv->copy_mode == DPDK_COPY_MODE_TAP || ptv->copy_mode == DPDK_COPY_MODE_IPS) {
386  rte_eth_dev_stop(ptv->out_port_id);
387  }
388  }
389  DPDKDumpCounters(ptv);
390  break;
391  }
392 
393  nb_rx = rte_eth_rx_burst(ptv->port_id, ptv->queue_id, ptv->received_mbufs, BURST_SIZE);
394  if (unlikely(nb_rx == 0)) {
395  t = DPDKSetTimevalReal(&machine_start_time);
396  uint64_t msecs = SCTIME_MSECS(t);
397  if (msecs > last_timeout_msec + 100) {
398  TmThreadsCaptureHandleTimeout(tv, NULL);
399  last_timeout_msec = msecs;
400  }
401  continue;
402  }
403 
404  ptv->pkts += (uint64_t)nb_rx;
405  for (uint16_t i = 0; i < nb_rx; i++) {
407  if (unlikely(p == NULL)) {
408  continue;
409  }
412  if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
414  }
415 
416  p->ts = DPDKSetTimevalReal(&machine_start_time);
417  p->dpdk_v.mbuf = ptv->received_mbufs[i];
418  p->ReleasePacket = DPDKReleasePacket;
419  p->dpdk_v.copy_mode = ptv->copy_mode;
420  p->dpdk_v.out_port_id = ptv->out_port_id;
421  p->dpdk_v.out_queue_id = ptv->queue_id;
422  p->livedev = ptv->livedev;
423 
424  if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) {
426  } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_OFFLOAD) {
427  uint64_t ol_flags = ptv->received_mbufs[i]->ol_flags;
428  if ((ol_flags & RTE_MBUF_F_RX_IP_CKSUM_MASK) == RTE_MBUF_F_RX_IP_CKSUM_GOOD &&
429  (ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) == RTE_MBUF_F_RX_L4_CKSUM_GOOD) {
430  SCLogDebug("HW detected GOOD IP and L4 chsum, ignoring validation");
432  } else {
433  if ((ol_flags & RTE_MBUF_F_RX_IP_CKSUM_MASK) == RTE_MBUF_F_RX_IP_CKSUM_BAD) {
434  SCLogDebug("HW detected BAD IP checksum");
435  // chsum recalc will not be triggered but rule keyword check will be
436  p->level3_comp_csum = 0;
437  }
438  if ((ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) == RTE_MBUF_F_RX_L4_CKSUM_BAD) {
439  SCLogDebug("HW detected BAD L4 chsum");
440  p->level4_comp_csum = 0;
441  }
442  }
443  }
444 
445  if (!rte_pktmbuf_is_contiguous(p->dpdk_v.mbuf) && !segmented_mbufs_warned) {
446  char warn_s[] = "Segmented mbufs detected! Redmine Ticket #6012 "
447  "Check your configuration or report the issue";
448  enum rte_proc_type_t eal_t = rte_eal_process_type();
449  if (eal_t == RTE_PROC_SECONDARY) {
450  SCLogWarning("%s. To avoid segmented mbufs, "
451  "try to increase mbuf size in your primary application",
452  warn_s);
453  } else if (eal_t == RTE_PROC_PRIMARY) {
454  SCLogWarning("%s. To avoid segmented mbufs, "
455  "try to increase MTU in your suricata.yaml",
456  warn_s);
457  }
458 
459  segmented_mbufs_warned = 1;
460  }
461 
462  PacketSetData(p, rte_pktmbuf_mtod(p->dpdk_v.mbuf, uint8_t *),
463  rte_pktmbuf_pkt_len(p->dpdk_v.mbuf));
464  if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
465  TmqhOutputPacketpool(ptv->tv, p);
466  DPDKFreeMbufArray(ptv->received_mbufs, nb_rx - i - 1, i + 1);
467  SCReturnInt(EXIT_FAILURE);
468  }
469  }
470 
471  /* Trigger one dump of stats every second */
472  current_time = DPDKGetSeconds();
473  if (current_time != last_dump) {
474  DPDKDumpCounters(ptv);
475  last_dump = current_time;
476  }
478  }
479 
481 }
482 
483 /**
484  * \brief Init function for ReceiveDPDK.
485  *
486  * \param tv pointer to ThreadVars
487  * \param initdata pointer to the interface passed from the user
488  * \param data pointer gets populated with DPDKThreadVars
489  *
490  */
491 static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void **data)
492 {
493  SCEnter();
494  int retval, thread_numa;
495  DPDKThreadVars *ptv = NULL;
496  DPDKIfaceConfig *dpdk_config = (DPDKIfaceConfig *)initdata;
497 
498  if (initdata == NULL) {
499  SCLogError("DPDK configuration is NULL in thread initialization");
500  goto fail;
501  }
502 
503  ptv = SCCalloc(1, sizeof(DPDKThreadVars));
504  if (unlikely(ptv == NULL)) {
505  SCLogError("Unable to allocate memory");
506  goto fail;
507  }
508 
509  ptv->tv = tv;
510  ptv->pkts = 0;
511  ptv->bytes = 0;
512  ptv->livedev = LiveGetDevice(dpdk_config->iface);
513 
514  ptv->capture_dpdk_packets = StatsRegisterCounter("capture.packets", ptv->tv);
515  ptv->capture_dpdk_rx_errs = StatsRegisterCounter("capture.rx_errors", ptv->tv);
516  ptv->capture_dpdk_tx_errs = StatsRegisterCounter("capture.tx_errors", ptv->tv);
517  ptv->capture_dpdk_imissed = StatsRegisterCounter("capture.dpdk.imissed", ptv->tv);
518  ptv->capture_dpdk_rx_no_mbufs = StatsRegisterCounter("capture.dpdk.no_mbufs", ptv->tv);
519  ptv->capture_dpdk_ierrors = StatsRegisterCounter("capture.dpdk.ierrors", ptv->tv);
520 
521  ptv->copy_mode = dpdk_config->copy_mode;
522  ptv->checksum_mode = dpdk_config->checksum_mode;
523 
524  ptv->threads = dpdk_config->threads;
525  ptv->port_id = dpdk_config->port_id;
526  ptv->out_port_id = dpdk_config->out_port_id;
527  ptv->port_socket_id = dpdk_config->socket_id;
528  // pass the pointer to the mempool and then forget about it. Mempool is freed in thread deinit.
529  ptv->pkt_mempool = dpdk_config->pkt_mempool;
530  dpdk_config->pkt_mempool = NULL;
531 
532  thread_numa = GetNumaNode();
533  if (thread_numa >= 0 && ptv->port_socket_id != SOCKET_ID_ANY &&
534  thread_numa != ptv->port_socket_id) {
535  SC_ATOMIC_ADD(dpdk_config->inconsitent_numa_cnt, 1);
536  SCLogPerf("%s: NIC is on NUMA %d, thread on NUMA %d", dpdk_config->iface,
537  ptv->port_socket_id, thread_numa);
538  }
539 
540  uint16_t queue_id = SC_ATOMIC_ADD(dpdk_config->queue_id, 1);
541  ptv->queue_id = queue_id;
542 
543  // the last thread starts the device
544  if (queue_id == dpdk_config->threads - 1) {
545  retval = rte_eth_dev_start(ptv->port_id);
546  if (retval < 0) {
547  SCLogError("%s: error (%s) during device startup", dpdk_config->iface,
548  rte_strerror(-retval));
549  goto fail;
550  }
551 
552  struct rte_eth_dev_info dev_info;
553  retval = rte_eth_dev_info_get(ptv->port_id, &dev_info);
554  if (retval != 0) {
555  SCLogError("%s: error (%s) when getting device info", dpdk_config->iface,
556  rte_strerror(-retval));
557  goto fail;
558  }
559 
560  // some PMDs requires additional actions only after the device has started
561  DevicePostStartPMDSpecificActions(ptv, dev_info.driver_name);
562 
563  uint16_t inconsistent_numa_cnt = SC_ATOMIC_GET(dpdk_config->inconsitent_numa_cnt);
564  if (inconsistent_numa_cnt > 0 && ptv->port_socket_id != SOCKET_ID_ANY) {
565  SCLogWarning("%s: NIC is on NUMA %d, %u threads on different NUMA node(s)",
566  dpdk_config->iface, ptv->port_socket_id, inconsistent_numa_cnt);
567  } else if (ptv->port_socket_id == SOCKET_ID_ANY) {
568  SCLogNotice(
569  "%s: unable to determine NIC's NUMA node, degraded performance can be expected",
570  dpdk_config->iface);
571  }
572  }
573 
574  *data = (void *)ptv;
575  dpdk_config->DerefFunc(dpdk_config);
577 
578 fail:
579  if (dpdk_config != NULL)
580  dpdk_config->DerefFunc(dpdk_config);
581  if (ptv != NULL)
582  SCFree(ptv);
584 }
585 
586 static void PrintDPDKPortXstats(uint32_t port_id, const char *port_name)
587 {
588  struct rte_eth_xstat *xstats;
589  struct rte_eth_xstat_name *xstats_names;
590 
591  int32_t len = rte_eth_xstats_get(port_id, NULL, 0);
592  if (len < 0)
593  FatalError("Error (%s) getting count of rte_eth_xstats failed on port %s",
594  rte_strerror(-len), port_name);
595 
596  xstats = SCCalloc(len, sizeof(*xstats));
597  if (xstats == NULL)
598  FatalError("Failed to allocate memory for the rte_eth_xstat structure");
599 
600  int32_t ret = rte_eth_xstats_get(port_id, xstats, len);
601  if (ret < 0 || ret > len) {
602  SCFree(xstats);
603  FatalError("Error (%s) getting rte_eth_xstats failed on port %s", rte_strerror(-ret),
604  port_name);
605  }
606  xstats_names = SCCalloc(len, sizeof(*xstats_names));
607  if (xstats_names == NULL) {
608  SCFree(xstats);
609  FatalError("Failed to allocate memory for the rte_eth_xstat_name array");
610  }
611  ret = rte_eth_xstats_get_names(port_id, xstats_names, len);
612  if (ret < 0 || ret > len) {
613  SCFree(xstats);
614  SCFree(xstats_names);
615  FatalError("Error (%s) getting names of rte_eth_xstats failed on port %s",
616  rte_strerror(-ret), port_name);
617  }
618  for (int32_t i = 0; i < len; i++) {
619  if (xstats[i].value > 0)
620  SCLogPerf("Port %u (%s) - %s: %" PRIu64, port_id, port_name, xstats_names[i].name,
621  xstats[i].value);
622  }
623 
624  SCFree(xstats);
625  SCFree(xstats_names);
626 }
627 
628 /**
629  * \brief This function prints stats to the screen at exit.
630  * \param tv pointer to ThreadVars
631  * \param data pointer that gets cast into DPDKThreadVars for ptv
632  */
633 static void ReceiveDPDKThreadExitStats(ThreadVars *tv, void *data)
634 {
635  SCEnter();
636  int retval;
637  DPDKThreadVars *ptv = (DPDKThreadVars *)data;
638 
639  if (ptv->queue_id == 0) {
640  struct rte_eth_stats eth_stats;
641  PrintDPDKPortXstats(ptv->port_id, ptv->livedev->dev);
642  retval = rte_eth_stats_get(ptv->port_id, &eth_stats);
643  if (unlikely(retval != 0)) {
644  SCLogError("%s: failed to get stats (%s)", ptv->livedev->dev, strerror(-retval));
645  SCReturn;
646  }
647  SCLogPerf("%s: total RX stats: packets %" PRIu64 " bytes: %" PRIu64 " missed: %" PRIu64
648  " errors: %" PRIu64 " nombufs: %" PRIu64,
649  ptv->livedev->dev, eth_stats.ipackets, eth_stats.ibytes, eth_stats.imissed,
650  eth_stats.ierrors, eth_stats.rx_nombuf);
651  if (ptv->copy_mode == DPDK_COPY_MODE_TAP || ptv->copy_mode == DPDK_COPY_MODE_IPS)
652  SCLogPerf("%s: total TX stats: packets %" PRIu64 " bytes: %" PRIu64 " errors: %" PRIu64,
653  ptv->livedev->dev, eth_stats.opackets, eth_stats.obytes, eth_stats.oerrors);
654  }
655 
656  DPDKDumpCounters(ptv);
657  SCLogPerf("(%s) received packets %" PRIu64, tv->name, ptv->pkts);
658 }
659 
660 /**
661  * \brief DeInit function closes dpdk at exit.
662  * \param tv pointer to ThreadVars
663  * \param data pointer that gets cast into DPDKThreadVars for ptv
664  */
665 static TmEcode ReceiveDPDKThreadDeinit(ThreadVars *tv, void *data)
666 {
667  SCEnter();
668  DPDKThreadVars *ptv = (DPDKThreadVars *)data;
669 
670  if (ptv->queue_id == 0) {
671  struct rte_eth_dev_info dev_info;
672  int retval = rte_eth_dev_info_get(ptv->port_id, &dev_info);
673  if (retval != 0) {
674  SCLogError("%s: error (%s) when getting device info", ptv->livedev->dev,
675  rte_strerror(-retval));
677  }
678 
679  DevicePreClosePMDSpecificActions(ptv, dev_info.driver_name);
680  }
681 
682  ptv->pkt_mempool = NULL; // MP is released when device is closed
683 
684  SCFree(ptv);
686 }
687 
688 /**
689  * \brief This function passes off to link type decoders.
690  *
691  * DecodeDPDK decodes packets from DPDK and passes
692  * them off to the proper link type decoder.
693  *
694  * \param t pointer to ThreadVars
695  * \param p pointer to the current packet
696  * \param data pointer that gets cast into DPDKThreadVars for ptv
697  */
698 static TmEcode DecodeDPDK(ThreadVars *tv, Packet *p, void *data)
699 {
700  SCEnter();
702 
704 
705  /* update counters */
707 
708  /* If suri has set vlan during reading, we increase vlan counter */
709  if (p->vlan_idx) {
711  }
712 
713  /* call the decoder */
714  DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
715 
717 
719 }
720 
721 static TmEcode DecodeDPDKThreadInit(ThreadVars *tv, const void *initdata, void **data)
722 {
723  SCEnter();
724  DecodeThreadVars *dtv = NULL;
725 
727 
728  if (dtv == NULL)
730 
732 
733  *data = (void *)dtv;
734 
736 }
737 
738 static TmEcode DecodeDPDKThreadDeinit(ThreadVars *tv, void *data)
739 {
740  SCEnter();
741  if (data != NULL)
742  DecodeThreadVarsFree(tv, data);
744 }
745 
746 #endif /* HAVE_DPDK */
747 /* eof */
748 /**
749  * @}
750  */
TmModule_::cap_flags
uint8_t cap_flags
Definition: tm-modules.h:73
PacketCheckAction
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition: packet.c:48
tm-threads.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
TMM_RECEIVEDPDK
@ TMM_RECEIVEDPDK
Definition: tm-threads-common.h:58
ICMPV6Hdr_::type
uint8_t type
Definition: decode-icmpv6.h:145
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:167
CHECKSUM_VALIDATION_OFFLOAD
@ CHECKSUM_VALIDATION_OFFLOAD
Definition: decode.h:50
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
DPDKSetTimevalOfMachineStart
void DPDKSetTimevalOfMachineStart(void)
ThreadVars_::name
char name[16]
Definition: threadvars.h:64
PacketFreeOrRelease
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition: decode.c:191
SCTIME_MSECS
#define SCTIME_MSECS(t)
Definition: util-time.h:58
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1053
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:387
DPDK_COPY_MODE_IPS
@ DPDK_COPY_MODE_IPS
Definition: source-dpdk.h:33
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:99
TMM_DECODEDPDK
@ TMM_DECODEDPDK
Definition: tm-threads-common.h:59
action-globals.h
Packet_::flags
uint32_t flags
Definition: decode.h:467
DpdkCopyModeEnum
DpdkCopyModeEnum
Definition: source-dpdk.h:33
threads.h
Packet_::vlan_idx
uint8_t vlan_idx
Definition: decode.h:458
LiveDevice_
Definition: util-device.h:49
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
StatsSetUI64
void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Sets a value of type double to the local counter.
Definition: counters.c:210
THV_RUNNING
#define THV_RUNNING
Definition: threadvars.h:54
NoDPDKSupportExit
TmEcode NoDPDKSupportExit(ThreadVars *, const void *, void **)
this function prints an error message and exits.
Definition: source-dpdk.c:78
util-privs.h
StatsSyncCountersIfSignalled
#define StatsSyncCountersIfSignalled(tv)
Definition: counters.h:141
CHECKSUM_VALIDATION_DISABLE
@ CHECKSUM_VALIDATION_DISABLE
Definition: decode.h:45
PacketDecodeFinalize
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition: decode.c:147
DPDKIfaceConfig_
Definition: source-dpdk.h:45
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:356
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
tmqh-packetpool.h
TmModule_::PktAcqLoop
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition: tm-modules.h:54
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:84
TmModule_::ThreadDeinit
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:49
Packet_::datalink
int datalink
Definition: decode.h:611
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1056
DecodeRegisterPerfCounters
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition: decode.c:525
Packet_::level3_comp_csum
int32_t level3_comp_csum
Definition: decode.h:531
TmModuleReceiveDPDKRegister
void TmModuleReceiveDPDKRegister(void)
Definition: source-dpdk.c:50
decode.h
Packet_::level4_comp_csum
int32_t level4_comp_csum
Definition: decode.h:533
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:54
TmModule_::PktAcqBreakLoop
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
Definition: tm-modules.h:57
Packet_::ts
SCTime_t ts
Definition: decode.h:475
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:248
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:220
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
util-affinity.h
SCTIME_FROM_TIMEVAL
#define SCTIME_FROM_TIMEVAL(tv)
Definition: util-time.h:71
TmModule_::Func
TmEcode(* Func)(ThreadVars *, Packet *, void *)
Definition: tm-modules.h:52
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
PKT_IS_ICMPV6
#define PKT_IS_ICMPV6(p)
Definition: decode.h:250
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:295
PacketPoolWait
void PacketPoolWait(void)
Definition: tmqh-packetpool.c:69
SCReturn
#define SCReturn
Definition: util-debug.h:273
Packet_::icmpv6h
ICMPV6Hdr * icmpv6h
Definition: decode.h:567
Packet_
Definition: decode.h:430
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:219
TmSlot_
Definition: tm-threads.h:53
PKT_IGNORE_CHECKSUM
#define PKT_IGNORE_CHECKSUM
Definition: decode.h:1016
SCTime_t
Definition: util-time.h:40
Packet_::livedev
struct LiveDevice_ * livedev
Definition: decode.h:590
DPDK_BURST_TX_WAIT_US
#define DPDK_BURST_TX_WAIT_US
Definition: source-dpdk.h:35
TmEcode
TmEcode
Definition: tm-threads-common.h:83
TmModule_::name
const char * name
Definition: tm-modules.h:44
DecodeThreadVars_::counter_vlan
uint16_t counter_vlan
Definition: decode.h:704
runmodes.h
TM_FLAG_RECEIVE_TM
#define TM_FLAG_RECEIVE_TM
Definition: tm-modules.h:31
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
Packet_::ReleasePacket
void(* ReleasePacket)(struct Packet_ *)
Definition: decode.h:519
util-dpdk.h
flags
uint8_t flags
Definition: decode-gre.h:0
DecodeThreadVarsFree
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition: decode.c:707
source-dpdk.h
ChecksumValidationMode
ChecksumValidationMode
Definition: decode.h:44
suricata-common.h
packet.h
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:230
TmModule_::ThreadInit
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:47
FatalError
#define FatalError(...)
Definition: util-debug.h:502
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
TmModule_::ThreadExitPrintStats
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition: tm-modules.h:48
threadvars.h
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:668
util-dpdk-bonding.h
DecodeThreadVarsAlloc
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition: decode.c:688
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:727
util-dpdk-i40e.h
suricata.h
TmSlot_::slot_next
struct TmSlot_ * slot_next
Definition: tm-threads.h:62
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
TmModuleDecodeDPDKRegister
void TmModuleDecodeDPDKRegister(void)
Registration Function for DecodeDPDK.
Definition: source-dpdk.c:64
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:961
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
PacketGetFromQueueOrAlloc
Packet * PacketGetFromQueueOrAlloc(void)
Get a packet. We try to get a packet from the packetpool first, but if that is empty we alloc a packe...
Definition: decode.c:208
SC_CAP_NET_RAW
#define SC_CAP_NET_RAW
Definition: util-privs.h:32
TmModule_::flags
uint8_t flags
Definition: tm-modules.h:76
DPDK_COPY_MODE_TAP
@ DPDK_COPY_MODE_TAP
Definition: source-dpdk.h:33
DecodeUpdatePacketCounters
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition: decode.c:654
LINKTYPE_ETHERNET
#define LINKTYPE_ETHERNET
Definition: decode.h:969
suricata_ctl_flags
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:172