app/dumpcap: add new packet capture application
[dpdk.git] / app / dumpcap / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Microsoft Corporation
3  *
4  * DPDK application to dump network traffic
5  * This is designed to look and act like the Wireshark
6  * dumpcap program.
7  */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <getopt.h>
12 #include <inttypes.h>
13 #include <limits.h>
14 #include <signal.h>
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/queue.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
23 #include <time.h>
24 #include <unistd.h>
25
26 #include <rte_alarm.h>
27 #include <rte_bpf.h>
28 #include <rte_config.h>
29 #include <rte_debug.h>
30 #include <rte_eal.h>
31 #include <rte_errno.h>
32 #include <rte_ethdev.h>
33 #include <rte_lcore.h>
34 #include <rte_malloc.h>
35 #include <rte_mbuf.h>
36 #include <rte_mempool.h>
37 #include <rte_pcapng.h>
38 #include <rte_pdump.h>
39 #include <rte_ring.h>
40 #include <rte_string_fns.h>
41 #include <rte_time.h>
42 #include <rte_version.h>
43
44 #include <pcap/pcap.h>
45 #include <pcap/bpf.h>
46
47 #define RING_NAME "capture-ring"
48 #define MONITOR_INTERVAL  (500 * 1000)
49 #define MBUF_POOL_CACHE_SIZE 32
50 #define BURST_SIZE 32
51 #define SLEEP_THRESHOLD 1000
52
53 /* command line flags */
54 static const char *progname;
55 static bool quit_signal;
56 static bool group_read;
57 static bool quiet;
58 static bool promiscuous_mode = true;
59 static bool use_pcapng = true;
60 static char *output_name;
61 static const char *filter_str;
62 static unsigned int ring_size = 2048;
63 static const char *capture_comment;
64 static uint32_t snaplen = RTE_MBUF_DEFAULT_BUF_SIZE;
65 static bool dump_bpf;
66 static struct {
67         uint64_t  duration;     /* nanoseconds */
68         unsigned long packets;  /* number of packets in file */
69         size_t size;            /* file size (bytes) */
70 } stop;
71
72 /* Running state */
73 static struct rte_bpf_prm *bpf_prm;
74 static uint64_t start_time, end_time;
75 static uint64_t packets_received;
76 static size_t file_size;
77
78 struct interface {
79         TAILQ_ENTRY(interface) next;
80         uint16_t port;
81         char name[RTE_ETH_NAME_MAX_LEN];
82
83         struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];
84 };
85
86 TAILQ_HEAD(interface_list, interface);
87 static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
88 static struct interface *port2intf[RTE_MAX_ETHPORTS];
89
90 /* Can do either pcap or pcapng format output */
91 typedef union {
92         rte_pcapng_t  *pcapng;
93         pcap_dumper_t *dumper;
94 } dumpcap_out_t;
95
96 static void usage(void)
97 {
98         printf("Usage: %s [options] ...\n\n", progname);
99         printf("Capture Interface:\n"
100                "  -i <interface>           name or port index of interface\n"
101                "  -f <capture filter>      packet filter in libpcap filter syntax\n");
102         printf("  -s <snaplen>, --snapshot-length <snaplen>\n"
103                "                           packet snapshot length (def: %u)\n",
104                RTE_MBUF_DEFAULT_BUF_SIZE);
105         printf("  -p, --no-promiscuous-mode\n"
106                "                           don't capture in promiscuous mode\n"
107                "  -D, --list-interfaces    print list of interfaces and exit\n"
108                "  -d                       print generated BPF code for capture filter\n"
109                "\n"
110                "Stop conditions:\n"
111                "  -c <packet count>        stop after n packets (def: infinite)\n"
112                "  -a <autostop cond.> ..., --autostop <autostop cond.> ...\n"
113                "                           duration:NUM - stop after NUM seconds\n"
114                "                           filesize:NUM - stop this file after NUM kB\n"
115                "                            packets:NUM - stop after NUM packets\n"
116                "Output (files):\n"
117                "  -w <filename>            name of file to save (def: tempfile)\n"
118                "  -g                       enable group read access on the output file(s)\n"
119                "  -n                       use pcapng format instead of pcap (default)\n"
120                "  -P                       use libpcap format instead of pcapng\n"
121                "  --capture-comment <comment>\n"
122                "                           add a capture comment to the output file\n"
123                "\n"
124                "Miscellaneous:\n"
125                "  -q                       don't report packet capture counts\n"
126                "  -v, --version            print version information and exit\n"
127                "  -h, --help               display this help and exit\n"
128                "\n"
129                "Use Ctrl-C to stop capturing at any time.\n");
130 }
131
132 static const char *version(void)
133 {
134         static char str[128];
135
136         snprintf(str, sizeof(str),
137                  "%s 1.0 (%s)\n", progname, rte_version());
138         return str;
139 }
140
141 /* Parse numeric argument from command line */
142 static unsigned long get_uint(const char *arg, const char *name,
143                              unsigned int limit)
144 {
145         unsigned long u;
146         char *endp;
147
148         u = strtoul(arg, &endp, 0);
149         if (*arg == '\0' || *endp != '\0')
150                 rte_exit(EXIT_FAILURE,
151                          "Specified %s \"%s\" is not a valid number\n",
152                          name, arg);
153         if (limit && u > limit)
154                 rte_exit(EXIT_FAILURE,
155                          "Specified %s \"%s\" is too large (greater than %u)\n",
156                          name, arg, limit);
157
158         return u;
159 }
160
161 /* Set auto stop values */
162 static void auto_stop(char *opt)
163 {
164         char *value, *endp;
165
166         value = strchr(opt, ':');
167         if (value == NULL)
168                 rte_exit(EXIT_FAILURE,
169                          "Missing colon in auto stop parameter\n");
170
171         *value++ = '\0';
172         if (strcmp(opt, "duration") == 0) {
173                 double interval = strtod(value, &endp);
174
175                 if (*value == '\0' || *endp != '\0' || interval <= 0)
176                         rte_exit(EXIT_FAILURE,
177                                  "Invalid duration \"%s\"\n", value);
178                 stop.duration = NSEC_PER_SEC * interval;
179         } else if (strcmp(opt, "filesize") == 0) {
180                 stop.size = get_uint(value, "filesize", 0) * 1024;
181         } else if (strcmp(opt, "packets") == 0) {
182                 stop.packets = get_uint(value, "packets", 0);
183         } else {
184                 rte_exit(EXIT_FAILURE,
185                          "Unknown autostop parameter \"%s\"\n", opt);
186         }
187 }
188
189 /* Add interface to list of interfaces to capture */
190 static void add_interface(uint16_t port, const char *name)
191 {
192         struct interface *intf;
193
194         intf = malloc(sizeof(*intf));
195         if (!intf)
196                 rte_exit(EXIT_FAILURE, "no memory for interface\n");
197
198         memset(intf, 0, sizeof(*intf));
199         rte_strscpy(intf->name, name, sizeof(intf->name));
200
201         printf("Capturing on '%s'\n", name);
202
203         port2intf[port] = intf;
204         TAILQ_INSERT_TAIL(&interfaces, intf, next);
205 }
206
207 /* Select all valid DPDK interfaces */
208 static void select_all_interfaces(void)
209 {
210         char name[RTE_ETH_NAME_MAX_LEN];
211         uint16_t p;
212
213         RTE_ETH_FOREACH_DEV(p) {
214                 if (rte_eth_dev_get_name_by_port(p, name) < 0)
215                         continue;
216                 add_interface(p, name);
217         }
218 }
219
220 /*
221  * Choose interface to capture if no -i option given.
222  * Select the first DPDK port, this matches what dumpcap does.
223  */
224 static void set_default_interface(void)
225 {
226         char name[RTE_ETH_NAME_MAX_LEN];
227         uint16_t p;
228
229         RTE_ETH_FOREACH_DEV(p) {
230                 if (rte_eth_dev_get_name_by_port(p, name) < 0)
231                         continue;
232                 add_interface(p, name);
233                 return;
234         }
235         rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
236 }
237
238 /* Lookup interface by name or port and add it to the list */
239 static void select_interface(const char *arg)
240 {
241         uint16_t port;
242
243         if (strcmp(arg, "*"))
244                 select_all_interfaces();
245         else if (rte_eth_dev_get_port_by_name(arg, &port) == 0)
246                 add_interface(port, arg);
247         else {
248                 char name[RTE_ETH_NAME_MAX_LEN];
249
250                 port = get_uint(arg, "port_number", UINT16_MAX);
251                 if (rte_eth_dev_get_name_by_port(port, name) < 0)
252                         rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
253                                  port);
254                 add_interface(port, name);
255         }
256 }
257
258 /* Display list of possible interfaces that can be used. */
259 static void show_interfaces(void)
260 {
261         char name[RTE_ETH_NAME_MAX_LEN];
262         uint16_t p;
263
264         RTE_ETH_FOREACH_DEV(p) {
265                 if (rte_eth_dev_get_name_by_port(p, name) < 0)
266                         continue;
267                 printf("%u. %s\n", p, name);
268         }
269 }
270
271 static void compile_filter(void)
272 {
273         struct bpf_program bf;
274         pcap_t *pcap;
275
276         pcap = pcap_open_dead(DLT_EN10MB, snaplen);
277         if (!pcap)
278                 rte_exit(EXIT_FAILURE, "can not open pcap\n");
279
280         if (pcap_compile(pcap, &bf, filter_str,
281                          1, PCAP_NETMASK_UNKNOWN) != 0)
282                 rte_exit(EXIT_FAILURE, "pcap filter string not valid (%s)\n",
283                          pcap_geterr(pcap));
284
285         bpf_prm = rte_bpf_convert(&bf);
286         if (bpf_prm == NULL)
287                 rte_exit(EXIT_FAILURE,
288                          "bpf convert failed\n");
289
290         if (dump_bpf) {
291                 printf("cBPF program (%u insns)\n", bf.bf_len);
292                 bpf_dump(&bf, 1);
293                 printf("\neBPF program (%u insns)\n", bpf_prm->nb_ins);
294                 rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
295                 exit(0);
296         }
297
298         /* Don't care about original program any more */
299         pcap_freecode(&bf);
300         pcap_close(pcap);
301 }
302
303 /*
304  * Parse command line options.
305  * These are chosen to be similar to dumpcap command.
306  */
307 static void parse_opts(int argc, char **argv)
308 {
309         static const struct option long_options[] = {
310                 { "autostop",        required_argument, NULL, 'a' },
311                 { "capture-comment", required_argument, NULL, 0 },
312                 { "help",            no_argument,       NULL, 'h' },
313                 { "interface",       required_argument, NULL, 'i' },
314                 { "list-interfaces", no_argument,       NULL, 'D' },
315                 { "no-promiscuous-mode", no_argument,   NULL, 'p' },
316                 { "output-file",     required_argument, NULL, 'w' },
317                 { "ring-buffer",     required_argument, NULL, 'b' },
318                 { "snapshot-length", required_argument, NULL, 's' },
319                 { "version",         no_argument,       NULL, 'v' },
320                 { NULL },
321         };
322         int option_index, c;
323
324         for (;;) {
325                 c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqs:vw:",
326                                 long_options, &option_index);
327                 if (c == -1)
328                         break;
329
330                 switch (c) {
331                 case 0:
332                         switch (option_index) {
333                         case 0:
334                                 capture_comment = optarg;
335                                 break;
336                         default:
337                                 usage();
338                                 exit(1);
339                         }
340                         break;
341                 case 'a':
342                         auto_stop(optarg);
343                         break;
344                 case 'b':
345                         rte_exit(EXIT_FAILURE,
346                                  "multiple files not implemented\n");
347                         break;
348                 case 'c':
349                         stop.packets = get_uint(optarg, "packet_count", 0);
350                         break;
351                 case 'd':
352                         dump_bpf = true;
353                         break;
354                 case 'D':
355                         show_interfaces();
356                         exit(0);
357                 case 'f':
358                         filter_str = optarg;
359                         break;
360                 case 'g':
361                         group_read = true;
362                         break;
363                 case 'h':
364                         printf("%s\n\n", version());
365                         usage();
366                         exit(0);
367                 case 'i':
368                         select_interface(optarg);
369                         break;
370                 case 'n':
371                         use_pcapng = true;
372                         break;
373                 case 'N':
374                         ring_size = get_uint(optarg, "packet_limit", 0);
375                         break;
376                 case 'p':
377                         promiscuous_mode = false;
378                         break;
379                 case 'P':
380                         use_pcapng = false;
381                         break;
382                 case 'q':
383                         quiet = true;
384                         break;
385                 case 's':
386                         snaplen = get_uint(optarg, "snap_len", 0);
387                         break;
388                 case 'w':
389                         output_name = optarg;
390                         break;
391                 case 'v':
392                         printf("%s\n", version());
393                         exit(0);
394                 default:
395                         fprintf(stderr, "Invalid option: %s\n",
396                                 argv[optind - 1]);
397                         usage();
398                         exit(1);
399                 }
400         }
401 }
402
403 static void
404 signal_handler(int sig_num __rte_unused)
405 {
406         __atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
407 }
408
409 /* Return the time since 1/1/1970 in nanoseconds */
410 static uint64_t create_timestamp(void)
411 {
412         struct timespec now;
413
414         clock_gettime(CLOCK_MONOTONIC, &now);
415         return rte_timespec_to_ns(&now);
416 }
417
418 static void
419 cleanup_pdump_resources(void)
420 {
421         struct interface *intf;
422
423         TAILQ_FOREACH(intf, &interfaces, next) {
424                 rte_pdump_disable(intf->port,
425                                   RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
426                 if (promiscuous_mode)
427                         rte_eth_promiscuous_disable(intf->port);
428         }
429 }
430
431 /* Alarm signal handler, used to check that primary process */
432 static void
433 monitor_primary(void *arg __rte_unused)
434 {
435         if (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED))
436                 return;
437
438         if (rte_eal_primary_proc_alive(NULL)) {
439                 rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
440         } else {
441                 fprintf(stderr,
442                         "Primary process is no longer active, exiting...\n");
443                 __atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
444         }
445 }
446
447 /* Setup handler to check when primary exits. */
448 static void
449 enable_primary_monitor(void)
450 {
451         int ret;
452
453         /* Once primary exits, so will pdump. */
454         ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
455         if (ret < 0)
456                 fprintf(stderr, "Fail to enable monitor:%d\n", ret);
457 }
458
459 static void
460 disable_primary_monitor(void)
461 {
462         int ret;
463
464         ret = rte_eal_alarm_cancel(monitor_primary, NULL);
465         if (ret < 0)
466                 fprintf(stderr, "Fail to disable monitor:%d\n", ret);
467 }
468
469 static void
470 report_packet_stats(dumpcap_out_t out)
471 {
472         struct rte_pdump_stats pdump_stats;
473         struct interface *intf;
474         uint64_t ifrecv, ifdrop;
475         double percent;
476
477         fputc('\n', stderr);
478         TAILQ_FOREACH(intf, &interfaces, next) {
479                 if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
480                         continue;
481
482                 /* do what Wiretap does */
483                 ifrecv = pdump_stats.accepted + pdump_stats.filtered;
484                 ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
485
486                 if (use_pcapng)
487                         rte_pcapng_write_stats(out.pcapng, intf->port, NULL,
488                                                start_time, end_time,
489                                                ifrecv, ifdrop);
490
491                 if (ifrecv == 0)
492                         percent = 0;
493                 else
494                         percent = 100. * ifrecv / (ifrecv + ifdrop);
495
496                 fprintf(stderr,
497                         "Packets received/dropped on interface '%s': "
498                         "%"PRIu64 "/%" PRIu64 " (%.1f)\n",
499                         intf->name, ifrecv, ifdrop, percent);
500         }
501 }
502
503 /*
504  * Start DPDK EAL with arguments.
505  * Unlike most DPDK programs, this application does not use the
506  * typical EAL command line arguments.
507  * We don't want to expose all the DPDK internals to the user.
508  */
509 static void dpdk_init(void)
510 {
511         static const char * const args[] = {
512                 "dumpcap", "--proc-type", "secondary",
513                 "--log-level", "notice"
514
515         };
516         const int eal_argc = RTE_DIM(args);
517         char **eal_argv;
518         unsigned int i;
519
520         /* DPDK API requires mutable versions of command line arguments. */
521         eal_argv = calloc(eal_argc + 1, sizeof(char *));
522         if (eal_argv == NULL)
523                 rte_panic("No memory\n");
524
525         eal_argv[0] = strdup(progname);
526         for (i = 1; i < RTE_DIM(args); i++)
527                 eal_argv[i] = strdup(args[i]);
528
529         if (rte_eal_init(eal_argc, eal_argv) < 0)
530                 rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
531
532         if (rte_eth_dev_count_avail() == 0)
533                 rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
534 }
535
536 /* Create packet ring shared between callbacks and process */
537 static struct rte_ring *create_ring(void)
538 {
539         struct rte_ring *ring;
540         size_t size, log2;
541
542         /* Find next power of 2 >= size. */
543         size = ring_size;
544         log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
545         size = 1u << log2;
546
547         if (size != ring_size) {
548                 fprintf(stderr, "Ring size %u rounded up to %zu\n",
549                         ring_size, size);
550                 ring_size = size;
551         }
552
553         ring = rte_ring_lookup(RING_NAME);
554         if (ring == NULL) {
555                 ring = rte_ring_create(RING_NAME, ring_size,
556                                         rte_socket_id(), 0);
557                 if (ring == NULL)
558                         rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
559                                  rte_strerror(rte_errno));
560         }
561         return ring;
562 }
563
564 static struct rte_mempool *create_mempool(void)
565 {
566         static const char pool_name[] = "capture_mbufs";
567         size_t num_mbufs = 2 * ring_size;
568         struct rte_mempool *mp;
569
570         mp = rte_mempool_lookup(pool_name);
571         if (mp)
572                 return mp;
573
574         mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
575                                             MBUF_POOL_CACHE_SIZE, 0,
576                                             rte_pcapng_mbuf_size(snaplen),
577                                             rte_socket_id(), "ring_mp_sc");
578         if (mp == NULL)
579                 rte_exit(EXIT_FAILURE,
580                          "Mempool (%s) creation failed: %s\n", pool_name,
581                          rte_strerror(rte_errno));
582
583         return mp;
584 }
585
586 /*
587  * Get Operating System information.
588  * Returns an string allocated via malloc().
589  */
590 static char *get_os_info(void)
591 {
592         struct utsname uts;
593         char *osname = NULL;
594
595         if (uname(&uts) < 0)
596                 return NULL;
597
598         if (asprintf(&osname, "%s %s",
599                      uts.sysname, uts.release) == -1)
600                 return NULL;
601
602         return osname;
603 }
604
605 static dumpcap_out_t create_output(void)
606 {
607         dumpcap_out_t ret;
608         static char tmp_path[PATH_MAX];
609         int fd;
610
611         /* If no filename specified make a tempfile name */
612         if (output_name == NULL) {
613                 struct interface *intf;
614                 struct tm *tm;
615                 time_t now;
616                 char ts[32];
617
618                 intf = TAILQ_FIRST(&interfaces);
619                 now = time(NULL);
620                 tm = localtime(&now);
621                 if (!tm)
622                         rte_panic("localtime failed\n");
623
624                 strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
625
626                 snprintf(tmp_path, sizeof(tmp_path),
627                          "/tmp/%s_%u_%s_%s.%s",
628                          progname, intf->port, intf->name, ts,
629                          use_pcapng ? "pcapng" : "pcap");
630                 output_name = tmp_path;
631         }
632
633         if (strcmp(output_name, "-") == 0)
634                 fd = STDOUT_FILENO;
635         else {
636                 mode_t mode = group_read ? 0640 : 0600;
637
638                 fd = open(output_name, O_WRONLY | O_CREAT, mode);
639                 if (fd < 0)
640                         rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
641                                  output_name, strerror(errno));
642         }
643
644         if (use_pcapng) {
645                 char *os = get_os_info();
646
647                 ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
648                                            version(), capture_comment);
649                 if (ret.pcapng == NULL)
650                         rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
651                                  strerror(rte_errno));
652                 free(os);
653         } else {
654                 pcap_t *pcap;
655
656                 pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, snaplen,
657                                                             PCAP_TSTAMP_PRECISION_NANO);
658                 if (pcap == NULL)
659                         rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
660
661                 ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
662                 if (ret.dumper == NULL)
663                         rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
664                                  pcap_geterr(pcap));
665         }
666
667         return ret;
668 }
669
670 static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
671 {
672         struct interface *intf;
673         uint32_t flags;
674         int ret;
675
676         flags = RTE_PDUMP_FLAG_RXTX;
677         if (use_pcapng)
678                 flags |= RTE_PDUMP_FLAG_PCAPNG;
679
680         TAILQ_FOREACH(intf, &interfaces, next) {
681                 if (promiscuous_mode)
682                         rte_eth_promiscuous_enable(intf->port);
683
684                 ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
685                                            flags, snaplen,
686                                            r, mp, bpf_prm);
687                 if (ret < 0)
688                         rte_exit(EXIT_FAILURE,
689                                  "Packet dump enable failed: %s\n",
690                                  rte_strerror(-ret));
691         }
692 }
693
694 /*
695  * Show current count of captured packets
696  * with backspaces to overwrite last value.
697  */
698 static void show_count(uint64_t count)
699 {
700         unsigned int i;
701         static unsigned int bt;
702
703         for (i = 0; i < bt; i++)
704                 fputc('\b', stderr);
705
706         bt = fprintf(stderr, "%"PRIu64" ", count);
707 }
708
709 /* Write multiple packets in older pcap format */
710 static ssize_t
711 pcap_write_packets(pcap_dumper_t *dumper,
712                    struct rte_mbuf *pkts[], uint16_t n)
713 {
714         uint8_t temp_data[snaplen];
715         struct pcap_pkthdr header;
716         uint16_t i;
717         size_t total = 0;
718
719         gettimeofday(&header.ts, NULL);
720
721         for (i = 0; i < n; i++) {
722                 struct rte_mbuf *m = pkts[i];
723
724                 header.len = rte_pktmbuf_pkt_len(m);
725                 header.caplen = RTE_MIN(header.len, snaplen);
726
727                 pcap_dump((u_char *)dumper, &header,
728                           rte_pktmbuf_read(m, 0, header.caplen, temp_data));
729
730                 total += sizeof(header) + header.len;
731         }
732
733         return total;
734 }
735
736 /* Process all packets in ring and dump to capture file */
737 static int process_ring(dumpcap_out_t out, struct rte_ring *r)
738 {
739         struct rte_mbuf *pkts[BURST_SIZE];
740         unsigned int avail, n;
741         static unsigned int empty_count;
742         ssize_t written;
743
744         n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
745                                       &avail);
746         if (n == 0) {
747                 /* don't consume endless amounts of cpu if idle */
748                 if (empty_count < SLEEP_THRESHOLD)
749                         ++empty_count;
750                 else
751                         usleep(10);
752                 return 0;
753         }
754
755         empty_count = (avail == 0);
756
757         if (use_pcapng)
758                 written = rte_pcapng_write_packets(out.pcapng, pkts, n);
759         else
760                 written = pcap_write_packets(out.dumper, pkts, n);
761
762         rte_pktmbuf_free_bulk(pkts, n);
763
764         if (written < 0)
765                 return -1;
766
767         file_size += written;
768         packets_received += n;
769         if (!quiet)
770                 show_count(packets_received);
771
772         return 0;
773 }
774
775 int main(int argc, char **argv)
776 {
777         struct rte_ring *r;
778         struct rte_mempool *mp;
779         dumpcap_out_t out;
780
781         progname = argv[0];
782
783         dpdk_init();
784         parse_opts(argc, argv);
785
786         if (filter_str)
787                 compile_filter();
788
789         if (TAILQ_EMPTY(&interfaces))
790                 set_default_interface();
791
792         r = create_ring();
793         mp = create_mempool();
794         out = create_output();
795
796         start_time = create_timestamp();
797         enable_pdump(r, mp);
798
799         signal(SIGINT, signal_handler);
800         signal(SIGPIPE, SIG_IGN);
801
802         enable_primary_monitor();
803
804         if (!quiet) {
805                 fprintf(stderr, "Packets captured: ");
806                 show_count(0);
807         }
808
809         while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {
810                 if (process_ring(out, r) < 0) {
811                         fprintf(stderr, "pcapng file write failed; %s\n",
812                                 strerror(errno));
813                         break;
814                 }
815
816                 if (stop.size && file_size >= stop.size)
817                         break;
818
819                 if (stop.packets && packets_received >= stop.packets)
820                         break;
821
822                 if (stop.duration != 0 &&
823                     create_timestamp() - start_time > stop.duration)
824                         break;
825         }
826
827         end_time = create_timestamp();
828         disable_primary_monitor();
829
830         if (rte_eal_primary_proc_alive(NULL))
831                 report_packet_stats(out);
832
833         if (use_pcapng)
834                 rte_pcapng_close(out.pcapng);
835         else
836                 pcap_dump_close(out.dumper);
837
838         cleanup_pdump_resources();
839         rte_free(bpf_filter);
840         rte_ring_free(r);
841         rte_mempool_free(mp);
842
843         return rte_eal_cleanup() ? EXIT_FAILURE : 0;
844 }