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