xref: /dpdk/app/dumpcap/main.c (revision f8dbaebbf1c9efcbb2e2354b341ed62175466a57)
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: %s(%d)\n",
289 			 rte_strerror(rte_errno), rte_errno);
290 
291 	if (dump_bpf) {
292 		printf("cBPF program (%u insns)\n", bf.bf_len);
293 		bpf_dump(&bf, 1);
294 		printf("\neBPF program (%u insns)\n", bpf_prm->nb_ins);
295 		rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
296 		exit(0);
297 	}
298 
299 	/* Don't care about original program any more */
300 	pcap_freecode(&bf);
301 	pcap_close(pcap);
302 }
303 
304 /*
305  * Parse command line options.
306  * These are chosen to be similar to dumpcap command.
307  */
308 static void parse_opts(int argc, char **argv)
309 {
310 	static const struct option long_options[] = {
311 		{ "autostop",        required_argument, NULL, 'a' },
312 		{ "capture-comment", required_argument, NULL, 0 },
313 		{ "help",            no_argument,       NULL, 'h' },
314 		{ "interface",       required_argument, NULL, 'i' },
315 		{ "list-interfaces", no_argument,       NULL, 'D' },
316 		{ "no-promiscuous-mode", no_argument,   NULL, 'p' },
317 		{ "output-file",     required_argument, NULL, 'w' },
318 		{ "ring-buffer",     required_argument, NULL, 'b' },
319 		{ "snapshot-length", required_argument, NULL, 's' },
320 		{ "version",         no_argument,       NULL, 'v' },
321 		{ NULL },
322 	};
323 	int option_index, c;
324 
325 	for (;;) {
326 		c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqs:vw:",
327 				long_options, &option_index);
328 		if (c == -1)
329 			break;
330 
331 		switch (c) {
332 		case 0:
333 			switch (option_index) {
334 			case 0:
335 				capture_comment = optarg;
336 				break;
337 			default:
338 				usage();
339 				exit(1);
340 			}
341 			break;
342 		case 'a':
343 			auto_stop(optarg);
344 			break;
345 		case 'b':
346 			rte_exit(EXIT_FAILURE,
347 				 "multiple files not implemented\n");
348 			break;
349 		case 'c':
350 			stop.packets = get_uint(optarg, "packet_count", 0);
351 			break;
352 		case 'd':
353 			dump_bpf = true;
354 			break;
355 		case 'D':
356 			show_interfaces();
357 			exit(0);
358 		case 'f':
359 			filter_str = optarg;
360 			break;
361 		case 'g':
362 			group_read = true;
363 			break;
364 		case 'h':
365 			printf("%s\n\n", version());
366 			usage();
367 			exit(0);
368 		case 'i':
369 			select_interface(optarg);
370 			break;
371 		case 'n':
372 			use_pcapng = true;
373 			break;
374 		case 'N':
375 			ring_size = get_uint(optarg, "packet_limit", 0);
376 			break;
377 		case 'p':
378 			promiscuous_mode = false;
379 			break;
380 		case 'P':
381 			use_pcapng = false;
382 			break;
383 		case 'q':
384 			quiet = true;
385 			break;
386 		case 's':
387 			snaplen = get_uint(optarg, "snap_len", 0);
388 			break;
389 		case 'w':
390 			output_name = optarg;
391 			break;
392 		case 'v':
393 			printf("%s\n", version());
394 			exit(0);
395 		default:
396 			fprintf(stderr, "Invalid option: %s\n",
397 				argv[optind - 1]);
398 			usage();
399 			exit(1);
400 		}
401 	}
402 }
403 
404 static void
405 signal_handler(int sig_num __rte_unused)
406 {
407 	__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
408 }
409 
410 /* Return the time since 1/1/1970 in nanoseconds */
411 static uint64_t create_timestamp(void)
412 {
413 	struct timespec now;
414 
415 	clock_gettime(CLOCK_MONOTONIC, &now);
416 	return rte_timespec_to_ns(&now);
417 }
418 
419 static void
420 cleanup_pdump_resources(void)
421 {
422 	struct interface *intf;
423 
424 	TAILQ_FOREACH(intf, &interfaces, next) {
425 		rte_pdump_disable(intf->port,
426 				  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
427 		if (promiscuous_mode)
428 			rte_eth_promiscuous_disable(intf->port);
429 	}
430 }
431 
432 /* Alarm signal handler, used to check that primary process */
433 static void
434 monitor_primary(void *arg __rte_unused)
435 {
436 	if (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED))
437 		return;
438 
439 	if (rte_eal_primary_proc_alive(NULL)) {
440 		rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
441 	} else {
442 		fprintf(stderr,
443 			"Primary process is no longer active, exiting...\n");
444 		__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
445 	}
446 }
447 
448 /* Setup handler to check when primary exits. */
449 static void
450 enable_primary_monitor(void)
451 {
452 	int ret;
453 
454 	/* Once primary exits, so will pdump. */
455 	ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
456 	if (ret < 0)
457 		fprintf(stderr, "Fail to enable monitor:%d\n", ret);
458 }
459 
460 static void
461 disable_primary_monitor(void)
462 {
463 	int ret;
464 
465 	ret = rte_eal_alarm_cancel(monitor_primary, NULL);
466 	if (ret < 0)
467 		fprintf(stderr, "Fail to disable monitor:%d\n", ret);
468 }
469 
470 static void
471 report_packet_stats(dumpcap_out_t out)
472 {
473 	struct rte_pdump_stats pdump_stats;
474 	struct interface *intf;
475 	uint64_t ifrecv, ifdrop;
476 	double percent;
477 
478 	fputc('\n', stderr);
479 	TAILQ_FOREACH(intf, &interfaces, next) {
480 		if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
481 			continue;
482 
483 		/* do what Wiretap does */
484 		ifrecv = pdump_stats.accepted + pdump_stats.filtered;
485 		ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
486 
487 		if (use_pcapng)
488 			rte_pcapng_write_stats(out.pcapng, intf->port, NULL,
489 					       start_time, end_time,
490 					       ifrecv, ifdrop);
491 
492 		if (ifrecv == 0)
493 			percent = 0;
494 		else
495 			percent = 100. * ifrecv / (ifrecv + ifdrop);
496 
497 		fprintf(stderr,
498 			"Packets received/dropped on interface '%s': "
499 			"%"PRIu64 "/%" PRIu64 " (%.1f)\n",
500 			intf->name, ifrecv, ifdrop, percent);
501 	}
502 }
503 
504 /*
505  * Start DPDK EAL with arguments.
506  * Unlike most DPDK programs, this application does not use the
507  * typical EAL command line arguments.
508  * We don't want to expose all the DPDK internals to the user.
509  */
510 static void dpdk_init(void)
511 {
512 	static const char * const args[] = {
513 		"dumpcap", "--proc-type", "secondary",
514 		"--log-level", "notice"
515 
516 	};
517 	const int eal_argc = RTE_DIM(args);
518 	char **eal_argv;
519 	unsigned int i;
520 
521 	/* DPDK API requires mutable versions of command line arguments. */
522 	eal_argv = calloc(eal_argc + 1, sizeof(char *));
523 	if (eal_argv == NULL)
524 		rte_panic("No memory\n");
525 
526 	eal_argv[0] = strdup(progname);
527 	for (i = 1; i < RTE_DIM(args); i++)
528 		eal_argv[i] = strdup(args[i]);
529 
530 	if (rte_eal_init(eal_argc, eal_argv) < 0)
531 		rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
532 
533 	if (rte_eth_dev_count_avail() == 0)
534 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
535 }
536 
537 /* Create packet ring shared between callbacks and process */
538 static struct rte_ring *create_ring(void)
539 {
540 	struct rte_ring *ring;
541 	size_t size, log2;
542 
543 	/* Find next power of 2 >= size. */
544 	size = ring_size;
545 	log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
546 	size = 1u << log2;
547 
548 	if (size != ring_size) {
549 		fprintf(stderr, "Ring size %u rounded up to %zu\n",
550 			ring_size, size);
551 		ring_size = size;
552 	}
553 
554 	ring = rte_ring_lookup(RING_NAME);
555 	if (ring == NULL) {
556 		ring = rte_ring_create(RING_NAME, ring_size,
557 					rte_socket_id(), 0);
558 		if (ring == NULL)
559 			rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
560 				 rte_strerror(rte_errno));
561 	}
562 	return ring;
563 }
564 
565 static struct rte_mempool *create_mempool(void)
566 {
567 	static const char pool_name[] = "capture_mbufs";
568 	size_t num_mbufs = 2 * ring_size;
569 	struct rte_mempool *mp;
570 
571 	mp = rte_mempool_lookup(pool_name);
572 	if (mp)
573 		return mp;
574 
575 	mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
576 					    MBUF_POOL_CACHE_SIZE, 0,
577 					    rte_pcapng_mbuf_size(snaplen),
578 					    rte_socket_id(), "ring_mp_sc");
579 	if (mp == NULL)
580 		rte_exit(EXIT_FAILURE,
581 			 "Mempool (%s) creation failed: %s\n", pool_name,
582 			 rte_strerror(rte_errno));
583 
584 	return mp;
585 }
586 
587 /*
588  * Get Operating System information.
589  * Returns an string allocated via malloc().
590  */
591 static char *get_os_info(void)
592 {
593 	struct utsname uts;
594 	char *osname = NULL;
595 
596 	if (uname(&uts) < 0)
597 		return NULL;
598 
599 	if (asprintf(&osname, "%s %s",
600 		     uts.sysname, uts.release) == -1)
601 		return NULL;
602 
603 	return osname;
604 }
605 
606 static dumpcap_out_t create_output(void)
607 {
608 	dumpcap_out_t ret;
609 	static char tmp_path[PATH_MAX];
610 	int fd;
611 
612 	/* If no filename specified make a tempfile name */
613 	if (output_name == NULL) {
614 		struct interface *intf;
615 		struct tm *tm;
616 		time_t now;
617 		char ts[32];
618 
619 		intf = TAILQ_FIRST(&interfaces);
620 		now = time(NULL);
621 		tm = localtime(&now);
622 		if (!tm)
623 			rte_panic("localtime failed\n");
624 
625 		strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
626 
627 		snprintf(tmp_path, sizeof(tmp_path),
628 			 "/tmp/%s_%u_%s_%s.%s",
629 			 progname, intf->port, intf->name, ts,
630 			 use_pcapng ? "pcapng" : "pcap");
631 		output_name = tmp_path;
632 	}
633 
634 	if (strcmp(output_name, "-") == 0)
635 		fd = STDOUT_FILENO;
636 	else {
637 		mode_t mode = group_read ? 0640 : 0600;
638 
639 		fd = open(output_name, O_WRONLY | O_CREAT, mode);
640 		if (fd < 0)
641 			rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
642 				 output_name, strerror(errno));
643 	}
644 
645 	if (use_pcapng) {
646 		char *os = get_os_info();
647 
648 		ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
649 					   version(), capture_comment);
650 		if (ret.pcapng == NULL)
651 			rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
652 				 strerror(rte_errno));
653 		free(os);
654 	} else {
655 		pcap_t *pcap;
656 
657 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, snaplen,
658 							    PCAP_TSTAMP_PRECISION_NANO);
659 		if (pcap == NULL)
660 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
661 
662 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
663 		if (ret.dumper == NULL)
664 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
665 				 pcap_geterr(pcap));
666 	}
667 
668 	return ret;
669 }
670 
671 static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
672 {
673 	struct interface *intf;
674 	uint32_t flags;
675 	int ret;
676 
677 	flags = RTE_PDUMP_FLAG_RXTX;
678 	if (use_pcapng)
679 		flags |= RTE_PDUMP_FLAG_PCAPNG;
680 
681 	TAILQ_FOREACH(intf, &interfaces, next) {
682 		if (promiscuous_mode)
683 			rte_eth_promiscuous_enable(intf->port);
684 
685 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
686 					   flags, snaplen,
687 					   r, mp, bpf_prm);
688 		if (ret < 0)
689 			rte_exit(EXIT_FAILURE,
690 				 "Packet dump enable failed: %s\n",
691 				 rte_strerror(-ret));
692 	}
693 }
694 
695 /*
696  * Show current count of captured packets
697  * with backspaces to overwrite last value.
698  */
699 static void show_count(uint64_t count)
700 {
701 	unsigned int i;
702 	static unsigned int bt;
703 
704 	for (i = 0; i < bt; i++)
705 		fputc('\b', stderr);
706 
707 	bt = fprintf(stderr, "%"PRIu64" ", count);
708 }
709 
710 /* Write multiple packets in older pcap format */
711 static ssize_t
712 pcap_write_packets(pcap_dumper_t *dumper,
713 		   struct rte_mbuf *pkts[], uint16_t n)
714 {
715 	uint8_t temp_data[snaplen];
716 	struct pcap_pkthdr header;
717 	uint16_t i;
718 	size_t total = 0;
719 
720 	gettimeofday(&header.ts, NULL);
721 
722 	for (i = 0; i < n; i++) {
723 		struct rte_mbuf *m = pkts[i];
724 
725 		header.len = rte_pktmbuf_pkt_len(m);
726 		header.caplen = RTE_MIN(header.len, snaplen);
727 
728 		pcap_dump((u_char *)dumper, &header,
729 			  rte_pktmbuf_read(m, 0, header.caplen, temp_data));
730 
731 		total += sizeof(header) + header.len;
732 	}
733 
734 	return total;
735 }
736 
737 /* Process all packets in ring and dump to capture file */
738 static int process_ring(dumpcap_out_t out, struct rte_ring *r)
739 {
740 	struct rte_mbuf *pkts[BURST_SIZE];
741 	unsigned int avail, n;
742 	static unsigned int empty_count;
743 	ssize_t written;
744 
745 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
746 				      &avail);
747 	if (n == 0) {
748 		/* don't consume endless amounts of cpu if idle */
749 		if (empty_count < SLEEP_THRESHOLD)
750 			++empty_count;
751 		else
752 			usleep(10);
753 		return 0;
754 	}
755 
756 	empty_count = (avail == 0);
757 
758 	if (use_pcapng)
759 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
760 	else
761 		written = pcap_write_packets(out.dumper, pkts, n);
762 
763 	rte_pktmbuf_free_bulk(pkts, n);
764 
765 	if (written < 0)
766 		return -1;
767 
768 	file_size += written;
769 	packets_received += n;
770 	if (!quiet)
771 		show_count(packets_received);
772 
773 	return 0;
774 }
775 
776 int main(int argc, char **argv)
777 {
778 	struct rte_ring *r;
779 	struct rte_mempool *mp;
780 	dumpcap_out_t out;
781 
782 	progname = argv[0];
783 
784 	dpdk_init();
785 	parse_opts(argc, argv);
786 
787 	if (filter_str)
788 		compile_filter();
789 
790 	if (TAILQ_EMPTY(&interfaces))
791 		set_default_interface();
792 
793 	r = create_ring();
794 	mp = create_mempool();
795 	out = create_output();
796 
797 	start_time = create_timestamp();
798 	enable_pdump(r, mp);
799 
800 	signal(SIGINT, signal_handler);
801 	signal(SIGPIPE, SIG_IGN);
802 
803 	enable_primary_monitor();
804 
805 	if (!quiet) {
806 		fprintf(stderr, "Packets captured: ");
807 		show_count(0);
808 	}
809 
810 	while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {
811 		if (process_ring(out, r) < 0) {
812 			fprintf(stderr, "pcapng file write failed; %s\n",
813 				strerror(errno));
814 			break;
815 		}
816 
817 		if (stop.size && file_size >= stop.size)
818 			break;
819 
820 		if (stop.packets && packets_received >= stop.packets)
821 			break;
822 
823 		if (stop.duration != 0 &&
824 		    create_timestamp() - start_time > stop.duration)
825 			break;
826 	}
827 
828 	end_time = create_timestamp();
829 	disable_primary_monitor();
830 
831 	if (rte_eal_primary_proc_alive(NULL))
832 		report_packet_stats(out);
833 
834 	if (use_pcapng)
835 		rte_pcapng_close(out.pcapng);
836 	else
837 		pcap_dump_close(out.dumper);
838 
839 	cleanup_pdump_resources();
840 	rte_free(bpf_filter);
841 	rte_ring_free(r);
842 	rte_mempool_free(mp);
843 
844 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
845 }
846