xref: /dpdk/app/dumpcap/main.c (revision 7917b0d38e92e8b9ec5a870415b791420e10f11a)
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_thread.h>
42 #include <rte_time.h>
43 #include <rte_version.h>
44 
45 #include <pcap/pcap.h>
46 #include <pcap/bpf.h>
47 
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 RTE_ATOMIC(bool) quit_signal;
56 static bool group_read;
57 static bool quiet;
58 static bool use_pcapng = true;
59 static char *output_name;
60 static const char *tmp_dir = "/tmp";
61 static unsigned int ring_size = 2048;
62 static const char *capture_comment;
63 static const char *file_prefix;
64 static const char *lcore_arg;
65 static bool dump_bpf;
66 static bool show_interfaces;
67 static bool print_stats;
68 
69 /* capture limit options */
70 static struct {
71 	time_t  duration;	/* seconds */
72 	unsigned long packets;  /* number of packets in file */
73 	size_t size;		/* file size (bytes) */
74 } stop;
75 
76 /* Running state */
77 static time_t start_time;
78 static uint64_t packets_received;
79 static size_t file_size;
80 
81 /* capture options */
82 struct capture_options {
83 	const char *filter;
84 	uint32_t snap_len;
85 	bool promisc_mode;
86 } capture = {
87 	.snap_len = RTE_MBUF_DEFAULT_BUF_SIZE,
88 	.promisc_mode = true,
89 };
90 
91 struct interface {
92 	TAILQ_ENTRY(interface) next;
93 	uint16_t port;
94 	struct capture_options opts;
95 	struct rte_bpf_prm *bpf_prm;
96 	char name[RTE_ETH_NAME_MAX_LEN];
97 
98 	struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];
99 	const char *ifname;
100 	const char *ifdescr;
101 };
102 
103 TAILQ_HEAD(interface_list, interface);
104 static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
105 
106 /* Can do either pcap or pcapng format output */
107 typedef union {
108 	rte_pcapng_t  *pcapng;
109 	pcap_dumper_t *dumper;
110 } dumpcap_out_t;
111 
112 static void usage(void)
113 {
114 	printf("Usage: %s [options] ...\n\n", progname);
115 	printf("Capture Interface:\n"
116 	       "  -i <interface>, --interface <interface>\n"
117 	       "                           name or port index of interface\n"
118 	       "  -f <capture filter>      packet filter in libpcap filter syntax\n");
119 	printf("  --ifname <name>          name to use in the capture file\n");
120 	printf("  --ifdescr <description>\n");
121 	printf("                           description to use in the capture file\n");
122 	printf("  -s <snaplen>, --snapshot-length <snaplen>\n"
123 	       "                           packet snapshot length (def: %u)\n",
124 	       RTE_MBUF_DEFAULT_BUF_SIZE);
125 	printf("  -p, --no-promiscuous-mode\n"
126 	       "                           don't capture in promiscuous mode\n"
127 	       "  -D, --list-interfaces    print list of interfaces and exit\n"
128 	       "  -d                       print generated BPF code for capture filter\n"
129 	       "  -S                       print statistics for each interface once per second\n"
130 	       "\n"
131 	       "Stop conditions:\n"
132 	       "  -c <packet count>        stop after n packets (def: infinite)\n"
133 	       "  -a <autostop cond.> ..., --autostop <autostop cond.> ...\n"
134 	       "                           duration:NUM - stop after NUM seconds\n"
135 	       "                           filesize:NUM - stop this file after NUM kB\n"
136 	       "                            packets:NUM - stop after NUM packets\n"
137 	       "Output (files):\n"
138 	       "  -w <filename>            name of file to save (def: tempfile)\n"
139 	       "  -g                       enable group read access on the output file(s)\n"
140 	       "  -n                       use pcapng format instead of pcap (default)\n"
141 	       "  -P                       use libpcap format instead of pcapng\n"
142 	       "  --capture-comment <comment>\n"
143 	       "                           add a capture comment to the output file\n"
144 	       "  --temp-dir <directory>   write temporary files to this directory\n"
145 	       "                           (default: /tmp)\n"
146 	       "\n"
147 	       "Miscellaneous:\n"
148 	       "  --lcore=<core>           CPU core to run on (default: any)\n"
149 	       "  --file-prefix=<prefix>   prefix to use for multi-process\n"
150 	       "  -q                       don't report packet capture counts\n"
151 	       "  -v, --version            print version information and exit\n"
152 	       "  -h, --help               display this help and exit\n"
153 	       "\n"
154 	       "Use Ctrl-C to stop capturing at any time.\n");
155 }
156 
157 static const char *version(void)
158 {
159 	static char str[128];
160 
161 	snprintf(str, sizeof(str),
162 		 "%s 1.0 (%s)\n", progname, rte_version());
163 	return str;
164 }
165 
166 /* Parse numeric argument from command line */
167 static unsigned long get_uint(const char *arg, const char *name,
168 			     unsigned int limit)
169 {
170 	unsigned long u;
171 	char *endp;
172 
173 	u = strtoul(arg, &endp, 0);
174 	if (*arg == '\0' || *endp != '\0')
175 		rte_exit(EXIT_FAILURE,
176 			 "Specified %s \"%s\" is not a valid number\n",
177 			 name, arg);
178 	if (limit && u > limit)
179 		rte_exit(EXIT_FAILURE,
180 			 "Specified %s \"%s\" is too large (greater than %u)\n",
181 			 name, arg, limit);
182 
183 	return u;
184 }
185 
186 /* Set auto stop values */
187 static void auto_stop(char *opt)
188 {
189 	char *value, *endp;
190 
191 	value = strchr(opt, ':');
192 	if (value == NULL)
193 		rte_exit(EXIT_FAILURE,
194 			 "Missing colon in auto stop parameter\n");
195 
196 	*value++ = '\0';
197 	if (strcmp(opt, "duration") == 0) {
198 		double interval = strtod(value, &endp);
199 
200 		if (*value == '\0' || *endp != '\0' || interval <= 0)
201 			rte_exit(EXIT_FAILURE,
202 				 "Invalid duration \"%s\"\n", value);
203 		stop.duration = interval;
204 	} else if (strcmp(opt, "filesize") == 0) {
205 		stop.size = get_uint(value, "filesize", 0) * 1024;
206 	} else if (strcmp(opt, "packets") == 0) {
207 		stop.packets = get_uint(value, "packets", 0);
208 	} else {
209 		rte_exit(EXIT_FAILURE,
210 			 "Unknown autostop parameter \"%s\"\n", opt);
211 	}
212 }
213 
214 /* Add interface to list of interfaces to capture */
215 static struct interface *add_interface(const char *name)
216 {
217 	struct interface *intf;
218 
219 	if (strlen(name) >= RTE_ETH_NAME_MAX_LEN)
220 		rte_exit(EXIT_FAILURE, "invalid name for interface: '%s'\n", name);
221 
222 	intf = malloc(sizeof(*intf));
223 	if (!intf)
224 		rte_exit(EXIT_FAILURE, "no memory for interface\n");
225 
226 	memset(intf, 0, sizeof(*intf));
227 	rte_strscpy(intf->name, name, sizeof(intf->name));
228 	intf->opts = capture;
229 	intf->port = -1;	/* port set later after EAL init */
230 
231 	TAILQ_INSERT_TAIL(&interfaces, intf, next);
232 	return intf;
233 }
234 
235 /* Name has been set but need to lookup port after eal_init */
236 static void find_interfaces(void)
237 {
238 	struct interface *intf;
239 
240 	TAILQ_FOREACH(intf, &interfaces, next) {
241 		/* if name is valid then just record port */
242 		if (rte_eth_dev_get_port_by_name(intf->name, &intf->port) == 0)
243 			continue;
244 
245 		/* maybe got passed port number string as name */
246 		intf->port = get_uint(intf->name, "port_number", UINT16_MAX);
247 		if (rte_eth_dev_get_name_by_port(intf->port, intf->name) < 0)
248 			rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
249 				 intf->port);
250 	}
251 }
252 
253 /*
254  * Choose interface to capture if no -i option given.
255  * Select the first DPDK port, this matches what dumpcap does.
256  */
257 static void set_default_interface(void)
258 {
259 	struct interface *intf;
260 	char name[RTE_ETH_NAME_MAX_LEN];
261 	uint16_t p;
262 
263 	RTE_ETH_FOREACH_DEV(p) {
264 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
265 			continue;
266 
267 		intf = add_interface(name);
268 		intf->port = p;
269 		return;
270 	}
271 	rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
272 }
273 
274 /* Display list of possible interfaces that can be used. */
275 static void dump_interfaces(void)
276 {
277 	char name[RTE_ETH_NAME_MAX_LEN];
278 	uint16_t p;
279 
280 	RTE_ETH_FOREACH_DEV(p) {
281 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
282 			continue;
283 		printf("%u. %s\n", p, name);
284 	}
285 
286 	exit(0);
287 }
288 
289 static void compile_filters(void)
290 {
291 	struct interface *intf;
292 
293 	TAILQ_FOREACH(intf, &interfaces, next) {
294 		struct rte_bpf_prm *bpf_prm;
295 		struct bpf_program bf;
296 		pcap_t *pcap;
297 
298 		pcap = pcap_open_dead(DLT_EN10MB, intf->opts.snap_len);
299 		if (!pcap)
300 			rte_exit(EXIT_FAILURE, "can not open pcap\n");
301 
302 		if (pcap_compile(pcap, &bf, intf->opts.filter,
303 				 1, PCAP_NETMASK_UNKNOWN) != 0) {
304 			fprintf(stderr,
305 				"Invalid capture filter \"%s\": for interface '%s'\n",
306 				intf->opts.filter, intf->name);
307 			rte_exit(EXIT_FAILURE, "\n%s\n",
308 				 pcap_geterr(pcap));
309 		}
310 
311 		bpf_prm = rte_bpf_convert(&bf);
312 		if (bpf_prm == NULL)
313 			rte_exit(EXIT_FAILURE,
314 				 "BPF convert interface '%s'\n%s(%d)\n",
315 				 intf->name,
316 				 rte_strerror(rte_errno), rte_errno);
317 
318 		if (dump_bpf) {
319 			printf("cBPF program (%u insns)\n", bf.bf_len);
320 			bpf_dump(&bf, 1);
321 			printf("\neBPF program (%u insns)\n",
322 			       bpf_prm->nb_ins);
323 			rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
324 			exit(0);
325 		}
326 
327 		intf->bpf_prm = bpf_prm;
328 
329 		/* Don't care about original program any more */
330 		pcap_freecode(&bf);
331 		pcap_close(pcap);
332 	}
333 }
334 
335 /*
336  * Parse command line options.
337  * These are chosen to be similar to dumpcap command.
338  */
339 static void parse_opts(int argc, char **argv)
340 {
341 	static const struct option long_options[] = {
342 		{ "autostop",        required_argument, NULL, 'a' },
343 		{ "capture-comment", required_argument, NULL, 0 },
344 		{ "file-prefix",     required_argument, NULL, 0 },
345 		{ "help",            no_argument,       NULL, 'h' },
346 		{ "ifdescr",	     required_argument, NULL, 0 },
347 		{ "ifname",	     required_argument, NULL, 0 },
348 		{ "interface",       required_argument, NULL, 'i' },
349 		{ "lcore",           required_argument, NULL, 0 },
350 		{ "list-interfaces", no_argument,       NULL, 'D' },
351 		{ "no-promiscuous-mode", no_argument,   NULL, 'p' },
352 		{ "output-file",     required_argument, NULL, 'w' },
353 		{ "ring-buffer",     required_argument, NULL, 'b' },
354 		{ "snapshot-length", required_argument, NULL, 's' },
355 		{ "temp-dir",        required_argument, NULL, 0 },
356 		{ "version",         no_argument,       NULL, 'v' },
357 		{ NULL },
358 	};
359 	int option_index, c;
360 	struct interface *last_intf = NULL;
361 	uint32_t len;
362 
363 	for (;;) {
364 		c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqSs:vw:",
365 				long_options, &option_index);
366 		if (c == -1)
367 			break;
368 
369 		switch (c) {
370 		case 0: {
371 			const char *longopt
372 				= long_options[option_index].name;
373 
374 			if (!strcmp(longopt, "capture-comment")) {
375 				capture_comment = optarg;
376 			} else if (!strcmp(longopt, "lcore")) {
377 				lcore_arg = optarg;
378 			} else if (!strcmp(longopt, "file-prefix")) {
379 				file_prefix = optarg;
380 			} else if (!strcmp(longopt, "temp-dir")) {
381 				tmp_dir = optarg;
382 			} else if (!strcmp(longopt, "ifdescr")) {
383 				if (last_intf == NULL)
384 					rte_exit(EXIT_FAILURE,
385 						 "--ifdescr must be specified after a -i option\n");
386 				last_intf->ifdescr = optarg;
387 			} else if (!strcmp(longopt, "ifname")) {
388 				if (last_intf == NULL)
389 					rte_exit(EXIT_FAILURE,
390 						 "--ifname must be specified after a -i option\n");
391 				last_intf->ifname = optarg;
392 			} else {
393 				usage();
394 				exit(1);
395 			}
396 			break;
397 		}
398 		case 'a':
399 			auto_stop(optarg);
400 			break;
401 		case 'b':
402 			rte_exit(EXIT_FAILURE,
403 				 "multiple files not implemented\n");
404 			break;
405 		case 'c':
406 			stop.packets = get_uint(optarg, "packet_count", 0);
407 			break;
408 		case 'd':
409 			dump_bpf = true;
410 			break;
411 		case 'D':
412 			show_interfaces = true;
413 			break;
414 		case 'f':
415 			if (last_intf == NULL)
416 				capture.filter = optarg;
417 			else
418 				last_intf->opts.filter = optarg;
419 			break;
420 		case 'g':
421 			group_read = true;
422 			break;
423 		case 'h':
424 			printf("%s\n\n", version());
425 			usage();
426 			exit(0);
427 		case 'i':
428 			last_intf = add_interface(optarg);
429 			break;
430 		case 'n':
431 			use_pcapng = true;
432 			break;
433 		case 'N':
434 			ring_size = get_uint(optarg, "packet_limit", 0);
435 			break;
436 		case 'p':
437 			/* Like dumpcap this option can occur multiple times.
438 			 *
439 			 * If used before the first occurrence of the -i option,
440 			 * no interface will be put into the promiscuous mode.
441 			 * If used after an -i option, the interface specified
442 			 * by the last -i option occurring before this option
443 			 * will not be put into the promiscuous mode.
444 			 */
445 			if (last_intf == NULL)
446 				capture.promisc_mode = false;
447 			else
448 				last_intf->opts.promisc_mode = false;
449 			break;
450 		case 'P':
451 			use_pcapng = false;
452 			break;
453 		case 'q':
454 			quiet = true;
455 			break;
456 		case 's':
457 			len = get_uint(optarg, "snap_len", 0);
458 			if (last_intf == NULL)
459 				capture.snap_len = len;
460 			else
461 				last_intf->opts.snap_len = len;
462 			break;
463 		case 'S':
464 			print_stats = true;
465 			break;
466 		case 'w':
467 			output_name = optarg;
468 			break;
469 		case 'v':
470 			printf("%s\n", version());
471 			exit(0);
472 		default:
473 			fprintf(stderr, "Invalid option: %s\n",
474 				argv[optind - 1]);
475 			usage();
476 			exit(1);
477 		}
478 	}
479 }
480 
481 static void
482 signal_handler(int sig_num __rte_unused)
483 {
484 	rte_atomic_store_explicit(&quit_signal, true, rte_memory_order_relaxed);
485 }
486 
487 
488 /* Instead of capturing, it tracks interface statistics */
489 static void statistics_loop(void)
490 {
491 	struct rte_eth_stats stats;
492 	char name[RTE_ETH_NAME_MAX_LEN];
493 	uint16_t p;
494 	int r;
495 
496 	printf("%-15s  %10s  %10s\n",
497 	       "Interface", "Received", "Dropped");
498 
499 	while (!rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed)) {
500 		RTE_ETH_FOREACH_DEV(p) {
501 			if (rte_eth_dev_get_name_by_port(p, name) < 0)
502 				continue;
503 
504 			r = rte_eth_stats_get(p, &stats);
505 			if (r < 0) {
506 				fprintf(stderr,
507 					"stats_get for port %u failed: %d (%s)\n",
508 					p, r, strerror(-r));
509 				return;
510 			}
511 
512 			printf("%-15s  %10"PRIu64"  %10"PRIu64"\n",
513 			       name, stats.ipackets,
514 			       stats.imissed + stats.ierrors + stats.rx_nombuf);
515 		}
516 		sleep(1);
517 	}
518 }
519 
520 static void
521 cleanup_pdump_resources(void)
522 {
523 	struct interface *intf;
524 
525 	TAILQ_FOREACH(intf, &interfaces, next) {
526 		rte_pdump_disable(intf->port,
527 				  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
528 		if (intf->opts.promisc_mode)
529 			rte_eth_promiscuous_disable(intf->port);
530 	}
531 }
532 
533 /* Alarm signal handler, used to check that primary process */
534 static void
535 monitor_primary(void *arg __rte_unused)
536 {
537 	if (rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed))
538 		return;
539 
540 	if (rte_eal_primary_proc_alive(NULL)) {
541 		rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
542 	} else {
543 		fprintf(stderr,
544 			"Primary process is no longer active, exiting...\n");
545 		rte_atomic_store_explicit(&quit_signal, true, rte_memory_order_relaxed);
546 	}
547 }
548 
549 /* Setup handler to check when primary exits. */
550 static void
551 enable_primary_monitor(void)
552 {
553 	int ret;
554 
555 	/* Once primary exits, so will pdump. */
556 	ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
557 	if (ret < 0)
558 		fprintf(stderr, "Fail to enable monitor:%d\n", ret);
559 }
560 
561 static void
562 disable_primary_monitor(void)
563 {
564 	int ret;
565 
566 	ret = rte_eal_alarm_cancel(monitor_primary, NULL);
567 	if (ret < 0)
568 		fprintf(stderr, "Fail to disable monitor:%d\n", ret);
569 }
570 
571 static void
572 report_packet_stats(dumpcap_out_t out)
573 {
574 	struct rte_pdump_stats pdump_stats;
575 	struct interface *intf;
576 	uint64_t ifrecv, ifdrop;
577 	double percent;
578 
579 	fputc('\n', stderr);
580 	TAILQ_FOREACH(intf, &interfaces, next) {
581 		if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
582 			continue;
583 
584 		/* do what Wiretap does */
585 		ifrecv = pdump_stats.accepted + pdump_stats.filtered;
586 		ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
587 
588 		if (use_pcapng)
589 			rte_pcapng_write_stats(out.pcapng, intf->port,
590 					       ifrecv, ifdrop, NULL);
591 
592 		if (ifrecv == 0)
593 			percent = 0;
594 		else
595 			percent = 100. * ifrecv / (ifrecv + ifdrop);
596 
597 		fprintf(stderr,
598 			"Packets received/dropped on interface '%s': "
599 			"%"PRIu64 "/%" PRIu64 " (%.1f)\n",
600 			intf->name, ifrecv, ifdrop, percent);
601 	}
602 }
603 
604 /*
605  * Start DPDK EAL with arguments.
606  * Unlike most DPDK programs, this application does not use the
607  * typical EAL command line arguments.
608  * We don't want to expose all the DPDK internals to the user.
609  */
610 static void dpdk_init(void)
611 {
612 	static const char * const args[] = {
613 		"dumpcap", "--proc-type", "secondary",
614 		"--log-level", "notice"
615 	};
616 	int eal_argc = RTE_DIM(args);
617 	rte_cpuset_t cpuset = { };
618 	char **eal_argv;
619 	unsigned int i;
620 
621 	if (file_prefix != NULL)
622 		eal_argc += 2;
623 
624 	if (lcore_arg != NULL)
625 		eal_argc += 2;
626 
627 	/* DPDK API requires mutable versions of command line arguments. */
628 	eal_argv = calloc(eal_argc + 1, sizeof(char *));
629 	if (eal_argv == NULL)
630 		rte_panic("No memory\n");
631 
632 	eal_argv[0] = strdup(progname);
633 	for (i = 1; i < RTE_DIM(args); i++)
634 		eal_argv[i] = strdup(args[i]);
635 
636 	if (lcore_arg != NULL) {
637 		eal_argv[i++] = strdup("--lcores");
638 		eal_argv[i++] = strdup(lcore_arg);
639 	}
640 
641 	if (file_prefix != NULL) {
642 		eal_argv[i++] = strdup("--file-prefix");
643 		eal_argv[i++] = strdup(file_prefix);
644 	}
645 
646 	for (i = 0; i < (unsigned int)eal_argc; i++) {
647 		if (eal_argv[i] == NULL)
648 			rte_panic("No memory\n");
649 	}
650 
651 	/*
652 	 * Need to get the original cpuset, before EAL init changes
653 	 * the affinity of this thread (main lcore).
654 	 */
655 	if (lcore_arg == NULL &&
656 	    rte_thread_get_affinity_by_id(rte_thread_self(), &cpuset) != 0)
657 		rte_panic("rte_thread_getaffinity failed\n");
658 
659 	if (rte_eal_init(eal_argc, eal_argv) < 0)
660 		rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
661 
662 	/*
663 	 * If no lcore argument was specified, then run this program as a normal process
664 	 * which can be scheduled on any non-isolated CPU.
665 	 */
666 	if (lcore_arg == NULL &&
667 	    rte_thread_set_affinity_by_id(rte_thread_self(), &cpuset) != 0)
668 		rte_exit(EXIT_FAILURE, "Can not restore original CPU affinity\n");
669 }
670 
671 /* Create packet ring shared between callbacks and process */
672 static struct rte_ring *create_ring(void)
673 {
674 	struct rte_ring *ring;
675 	char ring_name[RTE_RING_NAMESIZE];
676 	size_t size, log2;
677 
678 	/* Find next power of 2 >= size. */
679 	size = ring_size;
680 	log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
681 	size = 1u << log2;
682 
683 	if (size != ring_size) {
684 		fprintf(stderr, "Ring size %u rounded up to %zu\n",
685 			ring_size, size);
686 		ring_size = size;
687 	}
688 
689 	/* Want one ring per invocation of program */
690 	snprintf(ring_name, sizeof(ring_name),
691 		 "dumpcap-%d", getpid());
692 
693 	ring = rte_ring_create(ring_name, ring_size,
694 			       rte_socket_id(), 0);
695 	if (ring == NULL)
696 		rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
697 			 rte_strerror(rte_errno));
698 
699 	return ring;
700 }
701 
702 static struct rte_mempool *create_mempool(void)
703 {
704 	const struct interface *intf;
705 	char pool_name[RTE_MEMPOOL_NAMESIZE];
706 	size_t num_mbufs = 2 * ring_size;
707 	struct rte_mempool *mp;
708 	uint32_t data_size = 128;
709 
710 	snprintf(pool_name, sizeof(pool_name), "capture_%d", getpid());
711 
712 	/* Common pool so size mbuf for biggest snap length */
713 	TAILQ_FOREACH(intf, &interfaces, next) {
714 		uint32_t mbuf_size = rte_pcapng_mbuf_size(intf->opts.snap_len);
715 
716 		if (mbuf_size > data_size)
717 			data_size = mbuf_size;
718 	}
719 
720 	mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
721 					    MBUF_POOL_CACHE_SIZE, 0,
722 					    data_size,
723 					    rte_socket_id(), "ring_mp_mc");
724 	if (mp == NULL)
725 		rte_exit(EXIT_FAILURE,
726 			 "Mempool (%s) creation failed: %s\n", pool_name,
727 			 rte_strerror(rte_errno));
728 
729 	return mp;
730 }
731 
732 /*
733  * Get Operating System information.
734  * Returns an string allocated via malloc().
735  */
736 static char *get_os_info(void)
737 {
738 	struct utsname uts;
739 	char *osname = NULL;
740 
741 	if (uname(&uts) < 0)
742 		return NULL;
743 
744 	if (asprintf(&osname, "%s %s",
745 		     uts.sysname, uts.release) == -1)
746 		return NULL;
747 
748 	return osname;
749 }
750 
751 static dumpcap_out_t create_output(void)
752 {
753 	dumpcap_out_t ret;
754 	static char tmp_path[PATH_MAX];
755 	int fd;
756 
757 	/* If no filename specified make a tempfile name */
758 	if (output_name == NULL) {
759 		struct interface *intf;
760 		struct tm *tm;
761 		time_t now;
762 		char ts[32];
763 
764 		intf = TAILQ_FIRST(&interfaces);
765 		now = time(NULL);
766 		tm = localtime(&now);
767 		if (!tm)
768 			rte_panic("localtime failed\n");
769 
770 		strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
771 
772 		snprintf(tmp_path, sizeof(tmp_path),
773 			 "%s/%s_%u_%s_%s.%s", tmp_dir,
774 			 progname, intf->port, intf->name, ts,
775 			 use_pcapng ? "pcapng" : "pcap");
776 		output_name = tmp_path;
777 	}
778 
779 	if (strcmp(output_name, "-") == 0)
780 		fd = STDOUT_FILENO;
781 	else {
782 		mode_t mode = group_read ? 0640 : 0600;
783 
784 		fprintf(stderr, "File: %s\n", output_name);
785 		fd = open(output_name, O_WRONLY | O_CREAT, mode);
786 		if (fd < 0)
787 			rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
788 				 output_name, strerror(errno));
789 	}
790 
791 	if (use_pcapng) {
792 		struct interface *intf;
793 		char *os = get_os_info();
794 
795 		ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
796 					   version(), capture_comment);
797 		if (ret.pcapng == NULL)
798 			rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
799 				 strerror(rte_errno));
800 		free(os);
801 
802 		TAILQ_FOREACH(intf, &interfaces, next) {
803 			rte_pcapng_add_interface(ret.pcapng, intf->port,
804 						 intf->ifname, intf->ifdescr,
805 						 intf->opts.filter);
806 		}
807 	} else {
808 		pcap_t *pcap;
809 
810 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
811 							    capture.snap_len,
812 							    PCAP_TSTAMP_PRECISION_NANO);
813 		if (pcap == NULL)
814 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
815 
816 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
817 		if (ret.dumper == NULL)
818 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
819 				 pcap_geterr(pcap));
820 	}
821 
822 	return ret;
823 }
824 
825 static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
826 {
827 	struct interface *intf;
828 	unsigned int count = 0;
829 	uint32_t flags;
830 	int ret;
831 
832 	flags = RTE_PDUMP_FLAG_RXTX;
833 	if (use_pcapng)
834 		flags |= RTE_PDUMP_FLAG_PCAPNG;
835 
836 	TAILQ_FOREACH(intf, &interfaces, next) {
837 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
838 					   flags, intf->opts.snap_len,
839 					   r, mp, intf->bpf_prm);
840 		if (ret < 0) {
841 			const struct interface *intf2;
842 
843 			/* unwind any previous enables */
844 			TAILQ_FOREACH(intf2, &interfaces, next) {
845 				if (intf == intf2)
846 					break;
847 				rte_pdump_disable(intf2->port,
848 						  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
849 				if (intf2->opts.promisc_mode)
850 					rte_eth_promiscuous_disable(intf2->port);
851 			}
852 			rte_exit(EXIT_FAILURE,
853 				"Packet dump enable on %u:%s failed %s\n",
854 				intf->port, intf->name,
855 				rte_strerror(rte_errno));
856 		}
857 
858 		if (intf->opts.promisc_mode) {
859 			if (rte_eth_promiscuous_get(intf->port) == 1) {
860 				/* promiscuous already enabled */
861 				intf->opts.promisc_mode = false;
862 			} else if (rte_eth_promiscuous_enable(intf->port) < 0) {
863 				fprintf(stderr, "port %u:%s set promiscuous failed\n",
864 					intf->port, intf->name);
865 				intf->opts.promisc_mode = false;
866 			}
867 		}
868 		++count;
869 	}
870 
871 	fputs("Capturing on ", stdout);
872 	TAILQ_FOREACH(intf, &interfaces, next) {
873 		if (intf != TAILQ_FIRST(&interfaces)) {
874 			if (count > 2)
875 				putchar(',');
876 			putchar(' ');
877 			if (TAILQ_NEXT(intf, next) == NULL)
878 				fputs("and ", stdout);
879 		}
880 		printf("'%s'", intf->name);
881 	}
882 	putchar('\n');
883 }
884 
885 /*
886  * Show current count of captured packets
887  * with backspaces to overwrite last value.
888  */
889 static void show_count(uint64_t count)
890 {
891 	unsigned int i;
892 	static unsigned int bt;
893 
894 	for (i = 0; i < bt; i++)
895 		fputc('\b', stderr);
896 
897 	bt = fprintf(stderr, "%"PRIu64" ", count);
898 }
899 
900 /* Write multiple packets in older pcap format */
901 static ssize_t
902 pcap_write_packets(pcap_dumper_t *dumper,
903 		   struct rte_mbuf *pkts[], uint16_t n)
904 {
905 	uint8_t temp_data[RTE_ETHER_MAX_JUMBO_FRAME_LEN];
906 	struct pcap_pkthdr header;
907 	uint16_t i;
908 	size_t total = 0;
909 
910 	gettimeofday(&header.ts, NULL);
911 
912 	for (i = 0; i < n; i++) {
913 		struct rte_mbuf *m = pkts[i];
914 		size_t len, caplen;
915 
916 		len = caplen = rte_pktmbuf_pkt_len(m);
917 		if (unlikely(!rte_pktmbuf_is_contiguous(m) && len > sizeof(temp_data)))
918 			caplen = sizeof(temp_data);
919 
920 		header.len = len;
921 		header.caplen = caplen;
922 
923 		pcap_dump((u_char *)dumper, &header,
924 			  rte_pktmbuf_read(m, 0, caplen, temp_data));
925 
926 		total += sizeof(header) + caplen;
927 	}
928 
929 	return total;
930 }
931 
932 /* Process all packets in ring and dump to capture file */
933 static int process_ring(dumpcap_out_t out, struct rte_ring *r)
934 {
935 	struct rte_mbuf *pkts[BURST_SIZE];
936 	unsigned int avail, n;
937 	static unsigned int empty_count;
938 	ssize_t written;
939 
940 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
941 				      &avail);
942 	if (n == 0) {
943 		/* don't consume endless amounts of cpu if idle */
944 		if (empty_count < SLEEP_THRESHOLD)
945 			++empty_count;
946 		else
947 			usleep(10);
948 		return 0;
949 	}
950 
951 	empty_count = (avail == 0);
952 
953 	if (use_pcapng)
954 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
955 	else
956 		written = pcap_write_packets(out.dumper, pkts, n);
957 
958 	rte_pktmbuf_free_bulk(pkts, n);
959 
960 	if (written < 0)
961 		return -1;
962 
963 	file_size += written;
964 	packets_received += n;
965 	if (!quiet)
966 		show_count(packets_received);
967 
968 	return 0;
969 }
970 
971 int main(int argc, char **argv)
972 {
973 	struct rte_ring *r;
974 	struct rte_mempool *mp;
975 	struct sigaction action = {
976 		.sa_flags = SA_RESTART,
977 		.sa_handler = signal_handler,
978 	};
979 	struct sigaction origaction;
980 	dumpcap_out_t out;
981 	char *p;
982 
983 	p = strrchr(argv[0], '/');
984 	if (p == NULL)
985 		progname = argv[0];
986 	else
987 		progname = p + 1;
988 
989 	parse_opts(argc, argv);
990 	dpdk_init();
991 
992 	if (show_interfaces)
993 		dump_interfaces();
994 
995 	if (rte_eth_dev_count_avail() == 0)
996 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
997 
998 	if (TAILQ_EMPTY(&interfaces))
999 		set_default_interface();
1000 	else
1001 		find_interfaces();
1002 
1003 	compile_filters();
1004 
1005 	sigemptyset(&action.sa_mask);
1006 	sigaction(SIGTERM, &action, NULL);
1007 	sigaction(SIGINT, &action, NULL);
1008 	sigaction(SIGPIPE, &action, NULL);
1009 	sigaction(SIGHUP, NULL, &origaction);
1010 	if (origaction.sa_handler == SIG_DFL)
1011 		sigaction(SIGHUP, &action, NULL);
1012 
1013 	enable_primary_monitor();
1014 
1015 	if (print_stats) {
1016 		statistics_loop();
1017 		exit(0);
1018 	}
1019 
1020 	r = create_ring();
1021 	mp = create_mempool();
1022 	out = create_output();
1023 
1024 	start_time = time(NULL);
1025 	enable_pdump(r, mp);
1026 
1027 	if (!quiet) {
1028 		fprintf(stderr, "Packets captured: ");
1029 		show_count(0);
1030 	}
1031 
1032 	while (!rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed)) {
1033 		if (process_ring(out, r) < 0) {
1034 			fprintf(stderr, "pcapng file write failed; %s\n",
1035 				strerror(errno));
1036 			break;
1037 		}
1038 
1039 		if (stop.size && file_size >= stop.size)
1040 			break;
1041 
1042 		if (stop.packets && packets_received >= stop.packets)
1043 			break;
1044 
1045 		if (stop.duration != 0 &&
1046 		    time(NULL) - start_time > stop.duration)
1047 			break;
1048 	}
1049 
1050 	disable_primary_monitor();
1051 
1052 	if (rte_eal_primary_proc_alive(NULL))
1053 		report_packet_stats(out);
1054 
1055 	if (use_pcapng)
1056 		rte_pcapng_close(out.pcapng);
1057 	else
1058 		pcap_dump_close(out.dumper);
1059 
1060 	cleanup_pdump_resources();
1061 
1062 	rte_ring_free(r);
1063 	rte_mempool_free(mp);
1064 
1065 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
1066 }
1067