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