xref: /dpdk/app/dumpcap/main.c (revision 9bbd44d63846cf0771ec0f1c7e1b5a63ec5e9603)
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_bitops.h>
28 #include <rte_bpf.h>
29 #include <rte_config.h>
30 #include <rte_debug.h>
31 #include <rte_eal.h>
32 #include <rte_errno.h>
33 #include <rte_ethdev.h>
34 #include <rte_lcore.h>
35 #include <rte_malloc.h>
36 #include <rte_mbuf.h>
37 #include <rte_mempool.h>
38 #include <rte_pcapng.h>
39 #include <rte_pdump.h>
40 #include <rte_ring.h>
41 #include <rte_string_fns.h>
42 #include <rte_thread.h>
43 #include <rte_time.h>
44 #include <rte_version.h>
45 
46 #include <pcap/pcap.h>
47 #include <pcap/bpf.h>
48 
49 #define MONITOR_INTERVAL  (500 * 1000)
50 #define MBUF_POOL_CACHE_SIZE 32
51 #define BURST_SIZE 32
52 #define SLEEP_THRESHOLD 1000
53 
54 /* command line flags */
55 static const char *progname;
56 static RTE_ATOMIC(bool) quit_signal;
57 static bool group_read;
58 static bool quiet;
59 static bool use_pcapng = true;
60 static char *output_name;
61 static const char *tmp_dir = "/tmp";
62 static unsigned int ring_size = 2048;
63 static const char *capture_comment;
64 static const char *file_prefix;
65 static const char *lcore_arg;
66 static bool dump_bpf;
67 static bool show_interfaces;
68 static bool print_stats;
69 
70 /* capture limit options */
71 static struct {
72 	time_t  duration;	/* seconds */
73 	unsigned long packets;  /* number of packets in file */
74 	size_t size;		/* file size (bytes) */
75 } stop;
76 
77 /* Running state */
78 static time_t start_time;
79 static uint64_t packets_received;
80 static size_t file_size;
81 
82 /* capture options */
83 struct capture_options {
84 	const char *filter;
85 	uint32_t snap_len;
86 	bool promisc_mode;
87 } capture = {
88 	.snap_len = RTE_MBUF_DEFAULT_BUF_SIZE,
89 	.promisc_mode = true,
90 };
91 
92 struct interface {
93 	TAILQ_ENTRY(interface) next;
94 	uint16_t port;
95 	struct capture_options opts;
96 	struct rte_bpf_prm *bpf_prm;
97 	char name[RTE_ETH_NAME_MAX_LEN];
98 
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 - rte_clz64(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 			if (rte_pcapng_add_interface(ret.pcapng, intf->port, intf->ifname,
804 						     intf->ifdescr, intf->opts.filter) < 0)
805 				rte_exit(EXIT_FAILURE, "rte_pcapng_add_interface %u failed\n",
806 					intf->port);
807 		}
808 	} else {
809 		pcap_t *pcap;
810 
811 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
812 							    capture.snap_len,
813 							    PCAP_TSTAMP_PRECISION_NANO);
814 		if (pcap == NULL)
815 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
816 
817 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
818 		if (ret.dumper == NULL)
819 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
820 				 pcap_geterr(pcap));
821 	}
822 
823 	return ret;
824 }
825 
826 static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
827 {
828 	struct interface *intf;
829 	unsigned int count = 0;
830 	uint32_t flags;
831 	int ret;
832 
833 	flags = RTE_PDUMP_FLAG_RXTX;
834 	if (use_pcapng)
835 		flags |= RTE_PDUMP_FLAG_PCAPNG;
836 
837 	TAILQ_FOREACH(intf, &interfaces, next) {
838 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
839 					   flags, intf->opts.snap_len,
840 					   r, mp, intf->bpf_prm);
841 		if (ret < 0) {
842 			const struct interface *intf2;
843 
844 			/* unwind any previous enables */
845 			TAILQ_FOREACH(intf2, &interfaces, next) {
846 				if (intf == intf2)
847 					break;
848 				rte_pdump_disable(intf2->port,
849 						  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
850 				if (intf2->opts.promisc_mode)
851 					rte_eth_promiscuous_disable(intf2->port);
852 			}
853 			rte_exit(EXIT_FAILURE,
854 				"Packet dump enable on %u:%s failed %s\n",
855 				intf->port, intf->name,
856 				rte_strerror(rte_errno));
857 		}
858 
859 		if (intf->opts.promisc_mode) {
860 			if (rte_eth_promiscuous_get(intf->port) == 1) {
861 				/* promiscuous already enabled */
862 				intf->opts.promisc_mode = false;
863 			} else if (rte_eth_promiscuous_enable(intf->port) < 0) {
864 				fprintf(stderr, "port %u:%s set promiscuous failed\n",
865 					intf->port, intf->name);
866 				intf->opts.promisc_mode = false;
867 			}
868 		}
869 		++count;
870 	}
871 
872 	fputs("Capturing on ", stdout);
873 	TAILQ_FOREACH(intf, &interfaces, next) {
874 		if (intf != TAILQ_FIRST(&interfaces)) {
875 			if (count > 2)
876 				putchar(',');
877 			putchar(' ');
878 			if (TAILQ_NEXT(intf, next) == NULL)
879 				fputs("and ", stdout);
880 		}
881 		printf("'%s'", intf->name);
882 	}
883 	putchar('\n');
884 }
885 
886 /*
887  * Show current count of captured packets
888  * with backspaces to overwrite last value.
889  */
890 static void show_count(uint64_t count)
891 {
892 	unsigned int i;
893 	static unsigned int bt;
894 
895 	for (i = 0; i < bt; i++)
896 		fputc('\b', stderr);
897 
898 	bt = fprintf(stderr, "%"PRIu64" ", count);
899 }
900 
901 /* Write multiple packets in older pcap format */
902 static ssize_t
903 pcap_write_packets(pcap_dumper_t *dumper,
904 		   struct rte_mbuf *pkts[], uint16_t n)
905 {
906 	uint8_t temp_data[RTE_ETHER_MAX_JUMBO_FRAME_LEN];
907 	struct pcap_pkthdr header;
908 	uint16_t i;
909 	size_t total = 0;
910 
911 	gettimeofday(&header.ts, NULL);
912 
913 	for (i = 0; i < n; i++) {
914 		struct rte_mbuf *m = pkts[i];
915 		size_t len, caplen;
916 
917 		len = caplen = rte_pktmbuf_pkt_len(m);
918 		if (unlikely(!rte_pktmbuf_is_contiguous(m) && len > sizeof(temp_data)))
919 			caplen = sizeof(temp_data);
920 
921 		header.len = len;
922 		header.caplen = caplen;
923 
924 		pcap_dump((u_char *)dumper, &header,
925 			  rte_pktmbuf_read(m, 0, caplen, temp_data));
926 
927 		total += sizeof(header) + caplen;
928 	}
929 
930 	return total;
931 }
932 
933 /* Process all packets in ring and dump to capture file */
934 static int process_ring(dumpcap_out_t out, struct rte_ring *r)
935 {
936 	struct rte_mbuf *pkts[BURST_SIZE];
937 	unsigned int avail, n;
938 	static unsigned int empty_count;
939 	ssize_t written;
940 
941 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
942 				      &avail);
943 	if (n == 0) {
944 		/* don't consume endless amounts of cpu if idle */
945 		if (empty_count < SLEEP_THRESHOLD)
946 			++empty_count;
947 		else
948 			usleep(10);
949 		return 0;
950 	}
951 
952 	empty_count = (avail == 0);
953 
954 	if (use_pcapng)
955 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
956 	else
957 		written = pcap_write_packets(out.dumper, pkts, n);
958 
959 	rte_pktmbuf_free_bulk(pkts, n);
960 
961 	if (written < 0)
962 		return -1;
963 
964 	file_size += written;
965 	packets_received += n;
966 	if (!quiet)
967 		show_count(packets_received);
968 
969 	return 0;
970 }
971 
972 int main(int argc, char **argv)
973 {
974 	struct rte_ring *r;
975 	struct rte_mempool *mp;
976 	struct sigaction action = {
977 		.sa_flags = SA_RESTART,
978 		.sa_handler = signal_handler,
979 	};
980 	struct sigaction origaction;
981 	dumpcap_out_t out;
982 	char *p;
983 
984 	p = strrchr(argv[0], '/');
985 	if (p == NULL)
986 		progname = argv[0];
987 	else
988 		progname = p + 1;
989 
990 	parse_opts(argc, argv);
991 	dpdk_init();
992 
993 	if (show_interfaces)
994 		dump_interfaces();
995 
996 	if (rte_eth_dev_count_avail() == 0)
997 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
998 
999 	if (TAILQ_EMPTY(&interfaces))
1000 		set_default_interface();
1001 	else
1002 		find_interfaces();
1003 
1004 	compile_filters();
1005 
1006 	sigemptyset(&action.sa_mask);
1007 	sigaction(SIGTERM, &action, NULL);
1008 	sigaction(SIGINT, &action, NULL);
1009 	sigaction(SIGPIPE, &action, NULL);
1010 	sigaction(SIGHUP, NULL, &origaction);
1011 	if (origaction.sa_handler == SIG_DFL)
1012 		sigaction(SIGHUP, &action, NULL);
1013 
1014 	enable_primary_monitor();
1015 
1016 	if (print_stats) {
1017 		statistics_loop();
1018 		exit(0);
1019 	}
1020 
1021 	r = create_ring();
1022 	mp = create_mempool();
1023 	out = create_output();
1024 
1025 	start_time = time(NULL);
1026 	enable_pdump(r, mp);
1027 
1028 	if (!quiet) {
1029 		fprintf(stderr, "Packets captured: ");
1030 		show_count(0);
1031 	}
1032 
1033 	while (!rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed)) {
1034 		if (process_ring(out, r) < 0) {
1035 			fprintf(stderr, "pcapng file write failed; %s\n",
1036 				strerror(errno));
1037 			break;
1038 		}
1039 
1040 		if (stop.size && file_size >= stop.size)
1041 			break;
1042 
1043 		if (stop.packets && packets_received >= stop.packets)
1044 			break;
1045 
1046 		if (stop.duration != 0 &&
1047 		    time(NULL) - start_time > stop.duration)
1048 			break;
1049 	}
1050 
1051 	disable_primary_monitor();
1052 
1053 	if (rte_eal_primary_proc_alive(NULL))
1054 		report_packet_stats(out);
1055 
1056 	if (use_pcapng)
1057 		rte_pcapng_close(out.pcapng);
1058 	else
1059 		pcap_dump_close(out.dumper);
1060 
1061 	cleanup_pdump_resources();
1062 
1063 	rte_ring_free(r);
1064 	rte_mempool_free(mp);
1065 
1066 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
1067 }
1068