xref: /dpdk/app/dumpcap/main.c (revision 9bbd44d63846cf0771ec0f1c7e1b5a63ec5e9603)
1cbb44143SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2cbb44143SStephen Hemminger  * Copyright(c) 2019-2020 Microsoft Corporation
3cbb44143SStephen Hemminger  *
4cbb44143SStephen Hemminger  * DPDK application to dump network traffic
5cbb44143SStephen Hemminger  * This is designed to look and act like the Wireshark
6cbb44143SStephen Hemminger  * dumpcap program.
7cbb44143SStephen Hemminger  */
8cbb44143SStephen Hemminger 
9cbb44143SStephen Hemminger #include <errno.h>
10cbb44143SStephen Hemminger #include <fcntl.h>
11cbb44143SStephen Hemminger #include <getopt.h>
12cbb44143SStephen Hemminger #include <inttypes.h>
13cbb44143SStephen Hemminger #include <limits.h>
14cbb44143SStephen Hemminger #include <signal.h>
15cbb44143SStephen Hemminger #include <stdbool.h>
16cbb44143SStephen Hemminger #include <stdint.h>
17cbb44143SStephen Hemminger #include <stdio.h>
18cbb44143SStephen Hemminger #include <stdlib.h>
19cbb44143SStephen Hemminger #include <string.h>
20cbb44143SStephen Hemminger #include <sys/queue.h>
21cbb44143SStephen Hemminger #include <sys/types.h>
22cbb44143SStephen Hemminger #include <sys/utsname.h>
23cbb44143SStephen Hemminger #include <time.h>
24cbb44143SStephen Hemminger #include <unistd.h>
25cbb44143SStephen Hemminger 
26cbb44143SStephen Hemminger #include <rte_alarm.h>
272a682d65SStephen Hemminger #include <rte_bitops.h>
28cbb44143SStephen Hemminger #include <rte_bpf.h>
29cbb44143SStephen Hemminger #include <rte_config.h>
30cbb44143SStephen Hemminger #include <rte_debug.h>
31cbb44143SStephen Hemminger #include <rte_eal.h>
32cbb44143SStephen Hemminger #include <rte_errno.h>
33cbb44143SStephen Hemminger #include <rte_ethdev.h>
34cbb44143SStephen Hemminger #include <rte_lcore.h>
35cbb44143SStephen Hemminger #include <rte_malloc.h>
36cbb44143SStephen Hemminger #include <rte_mbuf.h>
37cbb44143SStephen Hemminger #include <rte_mempool.h>
38cbb44143SStephen Hemminger #include <rte_pcapng.h>
39cbb44143SStephen Hemminger #include <rte_pdump.h>
40cbb44143SStephen Hemminger #include <rte_ring.h>
41cbb44143SStephen Hemminger #include <rte_string_fns.h>
42311137f1SStephen Hemminger #include <rte_thread.h>
43cbb44143SStephen Hemminger #include <rte_time.h>
44cbb44143SStephen Hemminger #include <rte_version.h>
45cbb44143SStephen Hemminger 
46cbb44143SStephen Hemminger #include <pcap/pcap.h>
47cbb44143SStephen Hemminger #include <pcap/bpf.h>
48cbb44143SStephen Hemminger 
49cbb44143SStephen Hemminger #define MONITOR_INTERVAL  (500 * 1000)
50cbb44143SStephen Hemminger #define MBUF_POOL_CACHE_SIZE 32
51cbb44143SStephen Hemminger #define BURST_SIZE 32
52cbb44143SStephen Hemminger #define SLEEP_THRESHOLD 1000
53cbb44143SStephen Hemminger 
54cbb44143SStephen Hemminger /* command line flags */
55cbb44143SStephen Hemminger static const char *progname;
56b6a7e685STyler Retzlaff static RTE_ATOMIC(bool) quit_signal;
57cbb44143SStephen Hemminger static bool group_read;
58cbb44143SStephen Hemminger static bool quiet;
59cbb44143SStephen Hemminger static bool use_pcapng = true;
60cbb44143SStephen Hemminger static char *output_name;
61b39d52a5SStephen Hemminger static const char *tmp_dir = "/tmp";
62cbb44143SStephen Hemminger static unsigned int ring_size = 2048;
63cbb44143SStephen Hemminger static const char *capture_comment;
64eeb6cad4SStephen Hemminger static const char *file_prefix;
65311137f1SStephen Hemminger static const char *lcore_arg;
66cbb44143SStephen Hemminger static bool dump_bpf;
67d59fb4d1SStephen Hemminger static bool show_interfaces;
688744f84bSStephen Hemminger static bool print_stats;
69d59fb4d1SStephen Hemminger 
706026bfaeSStephen Hemminger /* capture limit options */
71cbb44143SStephen Hemminger static struct {
7216659193SStephen Hemminger 	time_t  duration;	/* seconds */
73cbb44143SStephen Hemminger 	unsigned long packets;  /* number of packets in file */
74cbb44143SStephen Hemminger 	size_t size;		/* file size (bytes) */
75cbb44143SStephen Hemminger } stop;
76cbb44143SStephen Hemminger 
77cbb44143SStephen Hemminger /* Running state */
7816659193SStephen Hemminger static time_t start_time;
79cbb44143SStephen Hemminger static uint64_t packets_received;
80cbb44143SStephen Hemminger static size_t file_size;
81cbb44143SStephen Hemminger 
826026bfaeSStephen Hemminger /* capture options */
836026bfaeSStephen Hemminger struct capture_options {
846026bfaeSStephen Hemminger 	const char *filter;
856026bfaeSStephen Hemminger 	uint32_t snap_len;
866026bfaeSStephen Hemminger 	bool promisc_mode;
876026bfaeSStephen Hemminger } capture = {
886026bfaeSStephen Hemminger 	.snap_len = RTE_MBUF_DEFAULT_BUF_SIZE,
896026bfaeSStephen Hemminger 	.promisc_mode = true,
906026bfaeSStephen Hemminger };
916026bfaeSStephen Hemminger 
92cbb44143SStephen Hemminger struct interface {
93cbb44143SStephen Hemminger 	TAILQ_ENTRY(interface) next;
94cbb44143SStephen Hemminger 	uint16_t port;
956026bfaeSStephen Hemminger 	struct capture_options opts;
966026bfaeSStephen Hemminger 	struct rte_bpf_prm *bpf_prm;
97cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
98cbb44143SStephen Hemminger 
99d1920ed6SStephen Hemminger 	const char *ifname;
100d1920ed6SStephen Hemminger 	const char *ifdescr;
101cbb44143SStephen Hemminger };
102cbb44143SStephen Hemminger 
103cbb44143SStephen Hemminger TAILQ_HEAD(interface_list, interface);
104cbb44143SStephen Hemminger static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
105cbb44143SStephen Hemminger 
106cbb44143SStephen Hemminger /* Can do either pcap or pcapng format output */
107cbb44143SStephen Hemminger typedef union {
108cbb44143SStephen Hemminger 	rte_pcapng_t  *pcapng;
109cbb44143SStephen Hemminger 	pcap_dumper_t *dumper;
110cbb44143SStephen Hemminger } dumpcap_out_t;
111cbb44143SStephen Hemminger 
112cbb44143SStephen Hemminger static void usage(void)
113cbb44143SStephen Hemminger {
114cbb44143SStephen Hemminger 	printf("Usage: %s [options] ...\n\n", progname);
115cbb44143SStephen Hemminger 	printf("Capture Interface:\n"
116137df50eSStephen Hemminger 	       "  -i <interface>, --interface <interface>\n"
117137df50eSStephen Hemminger 	       "                           name or port index of interface\n"
118cbb44143SStephen Hemminger 	       "  -f <capture filter>      packet filter in libpcap filter syntax\n");
119d1920ed6SStephen Hemminger 	printf("  --ifname <name>          name to use in the capture file\n");
120d1920ed6SStephen Hemminger 	printf("  --ifdescr <description>\n");
121d1920ed6SStephen Hemminger 	printf("                           description to use in the capture file\n");
122cbb44143SStephen Hemminger 	printf("  -s <snaplen>, --snapshot-length <snaplen>\n"
123cbb44143SStephen Hemminger 	       "                           packet snapshot length (def: %u)\n",
124cbb44143SStephen Hemminger 	       RTE_MBUF_DEFAULT_BUF_SIZE);
125cbb44143SStephen Hemminger 	printf("  -p, --no-promiscuous-mode\n"
126cbb44143SStephen Hemminger 	       "                           don't capture in promiscuous mode\n"
127cbb44143SStephen Hemminger 	       "  -D, --list-interfaces    print list of interfaces and exit\n"
128cbb44143SStephen Hemminger 	       "  -d                       print generated BPF code for capture filter\n"
1298744f84bSStephen Hemminger 	       "  -S                       print statistics for each interface once per second\n"
130cbb44143SStephen Hemminger 	       "\n"
131cbb44143SStephen Hemminger 	       "Stop conditions:\n"
132cbb44143SStephen Hemminger 	       "  -c <packet count>        stop after n packets (def: infinite)\n"
133cbb44143SStephen Hemminger 	       "  -a <autostop cond.> ..., --autostop <autostop cond.> ...\n"
134cbb44143SStephen Hemminger 	       "                           duration:NUM - stop after NUM seconds\n"
135cbb44143SStephen Hemminger 	       "                           filesize:NUM - stop this file after NUM kB\n"
136cbb44143SStephen Hemminger 	       "                            packets:NUM - stop after NUM packets\n"
137cbb44143SStephen Hemminger 	       "Output (files):\n"
138cbb44143SStephen Hemminger 	       "  -w <filename>            name of file to save (def: tempfile)\n"
139cbb44143SStephen Hemminger 	       "  -g                       enable group read access on the output file(s)\n"
140cbb44143SStephen Hemminger 	       "  -n                       use pcapng format instead of pcap (default)\n"
141cbb44143SStephen Hemminger 	       "  -P                       use libpcap format instead of pcapng\n"
142cbb44143SStephen Hemminger 	       "  --capture-comment <comment>\n"
143cbb44143SStephen Hemminger 	       "                           add a capture comment to the output file\n"
144b39d52a5SStephen Hemminger 	       "  --temp-dir <directory>   write temporary files to this directory\n"
145b39d52a5SStephen Hemminger 	       "                           (default: /tmp)\n"
146cbb44143SStephen Hemminger 	       "\n"
147cbb44143SStephen Hemminger 	       "Miscellaneous:\n"
148311137f1SStephen Hemminger 	       "  --lcore=<core>           CPU core to run on (default: any)\n"
149eeb6cad4SStephen Hemminger 	       "  --file-prefix=<prefix>   prefix to use for multi-process\n"
150cbb44143SStephen Hemminger 	       "  -q                       don't report packet capture counts\n"
151cbb44143SStephen Hemminger 	       "  -v, --version            print version information and exit\n"
152cbb44143SStephen Hemminger 	       "  -h, --help               display this help and exit\n"
153cbb44143SStephen Hemminger 	       "\n"
154cbb44143SStephen Hemminger 	       "Use Ctrl-C to stop capturing at any time.\n");
155cbb44143SStephen Hemminger }
156cbb44143SStephen Hemminger 
157cbb44143SStephen Hemminger static const char *version(void)
158cbb44143SStephen Hemminger {
159cbb44143SStephen Hemminger 	static char str[128];
160cbb44143SStephen Hemminger 
161cbb44143SStephen Hemminger 	snprintf(str, sizeof(str),
162cbb44143SStephen Hemminger 		 "%s 1.0 (%s)\n", progname, rte_version());
163cbb44143SStephen Hemminger 	return str;
164cbb44143SStephen Hemminger }
165cbb44143SStephen Hemminger 
166cbb44143SStephen Hemminger /* Parse numeric argument from command line */
167cbb44143SStephen Hemminger static unsigned long get_uint(const char *arg, const char *name,
168cbb44143SStephen Hemminger 			     unsigned int limit)
169cbb44143SStephen Hemminger {
170cbb44143SStephen Hemminger 	unsigned long u;
171cbb44143SStephen Hemminger 	char *endp;
172cbb44143SStephen Hemminger 
173cbb44143SStephen Hemminger 	u = strtoul(arg, &endp, 0);
174cbb44143SStephen Hemminger 	if (*arg == '\0' || *endp != '\0')
175cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
176cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is not a valid number\n",
177cbb44143SStephen Hemminger 			 name, arg);
178cbb44143SStephen Hemminger 	if (limit && u > limit)
179cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
180cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is too large (greater than %u)\n",
181cbb44143SStephen Hemminger 			 name, arg, limit);
182cbb44143SStephen Hemminger 
183cbb44143SStephen Hemminger 	return u;
184cbb44143SStephen Hemminger }
185cbb44143SStephen Hemminger 
186cbb44143SStephen Hemminger /* Set auto stop values */
187cbb44143SStephen Hemminger static void auto_stop(char *opt)
188cbb44143SStephen Hemminger {
189cbb44143SStephen Hemminger 	char *value, *endp;
190cbb44143SStephen Hemminger 
191cbb44143SStephen Hemminger 	value = strchr(opt, ':');
192cbb44143SStephen Hemminger 	if (value == NULL)
193cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
194cbb44143SStephen Hemminger 			 "Missing colon in auto stop parameter\n");
195cbb44143SStephen Hemminger 
196cbb44143SStephen Hemminger 	*value++ = '\0';
197cbb44143SStephen Hemminger 	if (strcmp(opt, "duration") == 0) {
198cbb44143SStephen Hemminger 		double interval = strtod(value, &endp);
199cbb44143SStephen Hemminger 
200cbb44143SStephen Hemminger 		if (*value == '\0' || *endp != '\0' || interval <= 0)
201cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
202cbb44143SStephen Hemminger 				 "Invalid duration \"%s\"\n", value);
20316659193SStephen Hemminger 		stop.duration = interval;
204cbb44143SStephen Hemminger 	} else if (strcmp(opt, "filesize") == 0) {
205cbb44143SStephen Hemminger 		stop.size = get_uint(value, "filesize", 0) * 1024;
206cbb44143SStephen Hemminger 	} else if (strcmp(opt, "packets") == 0) {
207cbb44143SStephen Hemminger 		stop.packets = get_uint(value, "packets", 0);
208cbb44143SStephen Hemminger 	} else {
209cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
210cbb44143SStephen Hemminger 			 "Unknown autostop parameter \"%s\"\n", opt);
211cbb44143SStephen Hemminger 	}
212cbb44143SStephen Hemminger }
213cbb44143SStephen Hemminger 
214cbb44143SStephen Hemminger /* Add interface to list of interfaces to capture */
2156026bfaeSStephen Hemminger static struct interface *add_interface(const char *name)
216cbb44143SStephen Hemminger {
217cbb44143SStephen Hemminger 	struct interface *intf;
218cbb44143SStephen Hemminger 
219742be6a4SStephen Hemminger 	if (strlen(name) >= RTE_ETH_NAME_MAX_LEN)
220742be6a4SStephen Hemminger 		rte_exit(EXIT_FAILURE, "invalid name for interface: '%s'\n", name);
221742be6a4SStephen Hemminger 
222cbb44143SStephen Hemminger 	intf = malloc(sizeof(*intf));
223cbb44143SStephen Hemminger 	if (!intf)
224cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "no memory for interface\n");
225cbb44143SStephen Hemminger 
226cbb44143SStephen Hemminger 	memset(intf, 0, sizeof(*intf));
227cbb44143SStephen Hemminger 	rte_strscpy(intf->name, name, sizeof(intf->name));
2286026bfaeSStephen Hemminger 	intf->opts = capture;
2296026bfaeSStephen Hemminger 	intf->port = -1;	/* port set later after EAL init */
230cbb44143SStephen Hemminger 
231cbb44143SStephen Hemminger 	TAILQ_INSERT_TAIL(&interfaces, intf, next);
2326026bfaeSStephen Hemminger 	return intf;
233cbb44143SStephen Hemminger }
234cbb44143SStephen Hemminger 
2356026bfaeSStephen Hemminger /* Name has been set but need to lookup port after eal_init */
2366026bfaeSStephen Hemminger static void find_interfaces(void)
237cbb44143SStephen Hemminger {
2386026bfaeSStephen Hemminger 	struct interface *intf;
239cbb44143SStephen Hemminger 
2406026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
2416026bfaeSStephen Hemminger 		/* if name is valid then just record port */
2426026bfaeSStephen Hemminger 		if (rte_eth_dev_get_port_by_name(intf->name, &intf->port) == 0)
243cbb44143SStephen Hemminger 			continue;
2446026bfaeSStephen Hemminger 
2456026bfaeSStephen Hemminger 		/* maybe got passed port number string as name */
2466026bfaeSStephen Hemminger 		intf->port = get_uint(intf->name, "port_number", UINT16_MAX);
2476026bfaeSStephen Hemminger 		if (rte_eth_dev_get_name_by_port(intf->port, intf->name) < 0)
2486026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
2496026bfaeSStephen Hemminger 				 intf->port);
250cbb44143SStephen Hemminger 	}
251cbb44143SStephen Hemminger }
252cbb44143SStephen Hemminger 
253cbb44143SStephen Hemminger /*
254cbb44143SStephen Hemminger  * Choose interface to capture if no -i option given.
255cbb44143SStephen Hemminger  * Select the first DPDK port, this matches what dumpcap does.
256cbb44143SStephen Hemminger  */
257cbb44143SStephen Hemminger static void set_default_interface(void)
258cbb44143SStephen Hemminger {
2596026bfaeSStephen Hemminger 	struct interface *intf;
260cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
261cbb44143SStephen Hemminger 	uint16_t p;
262cbb44143SStephen Hemminger 
263cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
264cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
265cbb44143SStephen Hemminger 			continue;
2666026bfaeSStephen Hemminger 
2676026bfaeSStephen Hemminger 		intf = add_interface(name);
2686026bfaeSStephen Hemminger 		intf->port = p;
269cbb44143SStephen Hemminger 		return;
270cbb44143SStephen Hemminger 	}
271cbb44143SStephen Hemminger 	rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
272cbb44143SStephen Hemminger }
273cbb44143SStephen Hemminger 
274cbb44143SStephen Hemminger /* Display list of possible interfaces that can be used. */
275d59fb4d1SStephen Hemminger static void dump_interfaces(void)
276cbb44143SStephen Hemminger {
277cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
278cbb44143SStephen Hemminger 	uint16_t p;
279cbb44143SStephen Hemminger 
280cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
281cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
282cbb44143SStephen Hemminger 			continue;
283cbb44143SStephen Hemminger 		printf("%u. %s\n", p, name);
284cbb44143SStephen Hemminger 	}
285d59fb4d1SStephen Hemminger 
286d59fb4d1SStephen Hemminger 	exit(0);
287cbb44143SStephen Hemminger }
288cbb44143SStephen Hemminger 
2896026bfaeSStephen Hemminger static void compile_filters(void)
290cbb44143SStephen Hemminger {
2916026bfaeSStephen Hemminger 	struct interface *intf;
2926026bfaeSStephen Hemminger 
2936026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
2946026bfaeSStephen Hemminger 		struct rte_bpf_prm *bpf_prm;
295cbb44143SStephen Hemminger 		struct bpf_program bf;
296cbb44143SStephen Hemminger 		pcap_t *pcap;
297cbb44143SStephen Hemminger 
2986026bfaeSStephen Hemminger 		pcap = pcap_open_dead(DLT_EN10MB, intf->opts.snap_len);
299cbb44143SStephen Hemminger 		if (!pcap)
300cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "can not open pcap\n");
301cbb44143SStephen Hemminger 
3026026bfaeSStephen Hemminger 		if (pcap_compile(pcap, &bf, intf->opts.filter,
3036026bfaeSStephen Hemminger 				 1, PCAP_NETMASK_UNKNOWN) != 0) {
3046026bfaeSStephen Hemminger 			fprintf(stderr,
3056026bfaeSStephen Hemminger 				"Invalid capture filter \"%s\": for interface '%s'\n",
3066026bfaeSStephen Hemminger 				intf->opts.filter, intf->name);
3076026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE, "\n%s\n",
308cbb44143SStephen Hemminger 				 pcap_geterr(pcap));
3096026bfaeSStephen Hemminger 		}
310cbb44143SStephen Hemminger 
311cbb44143SStephen Hemminger 		bpf_prm = rte_bpf_convert(&bf);
312cbb44143SStephen Hemminger 		if (bpf_prm == NULL)
313cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
3146026bfaeSStephen Hemminger 				 "BPF convert interface '%s'\n%s(%d)\n",
3156026bfaeSStephen Hemminger 				 intf->name,
31665d9b7c6SKonstantin Ananyev 				 rte_strerror(rte_errno), rte_errno);
317cbb44143SStephen Hemminger 
318cbb44143SStephen Hemminger 		if (dump_bpf) {
319cbb44143SStephen Hemminger 			printf("cBPF program (%u insns)\n", bf.bf_len);
320cbb44143SStephen Hemminger 			bpf_dump(&bf, 1);
3216026bfaeSStephen Hemminger 			printf("\neBPF program (%u insns)\n",
3226026bfaeSStephen Hemminger 			       bpf_prm->nb_ins);
323cbb44143SStephen Hemminger 			rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
324cbb44143SStephen Hemminger 			exit(0);
325cbb44143SStephen Hemminger 		}
326cbb44143SStephen Hemminger 
3276026bfaeSStephen Hemminger 		intf->bpf_prm = bpf_prm;
3286026bfaeSStephen Hemminger 
329cbb44143SStephen Hemminger 		/* Don't care about original program any more */
330cbb44143SStephen Hemminger 		pcap_freecode(&bf);
331cbb44143SStephen Hemminger 		pcap_close(pcap);
332cbb44143SStephen Hemminger 	}
3336026bfaeSStephen Hemminger }
334cbb44143SStephen Hemminger 
335cbb44143SStephen Hemminger /*
336cbb44143SStephen Hemminger  * Parse command line options.
337cbb44143SStephen Hemminger  * These are chosen to be similar to dumpcap command.
338cbb44143SStephen Hemminger  */
339cbb44143SStephen Hemminger static void parse_opts(int argc, char **argv)
340cbb44143SStephen Hemminger {
341cbb44143SStephen Hemminger 	static const struct option long_options[] = {
342cbb44143SStephen Hemminger 		{ "autostop",        required_argument, NULL, 'a' },
343cbb44143SStephen Hemminger 		{ "capture-comment", required_argument, NULL, 0 },
344eeb6cad4SStephen Hemminger 		{ "file-prefix",     required_argument, NULL, 0 },
345cbb44143SStephen Hemminger 		{ "help",            no_argument,       NULL, 'h' },
346d1920ed6SStephen Hemminger 		{ "ifdescr",	     required_argument, NULL, 0 },
347d1920ed6SStephen Hemminger 		{ "ifname",	     required_argument, NULL, 0 },
348cbb44143SStephen Hemminger 		{ "interface",       required_argument, NULL, 'i' },
349311137f1SStephen Hemminger 		{ "lcore",           required_argument, NULL, 0 },
350cbb44143SStephen Hemminger 		{ "list-interfaces", no_argument,       NULL, 'D' },
351cbb44143SStephen Hemminger 		{ "no-promiscuous-mode", no_argument,   NULL, 'p' },
352cbb44143SStephen Hemminger 		{ "output-file",     required_argument, NULL, 'w' },
353cbb44143SStephen Hemminger 		{ "ring-buffer",     required_argument, NULL, 'b' },
354cbb44143SStephen Hemminger 		{ "snapshot-length", required_argument, NULL, 's' },
355b39d52a5SStephen Hemminger 		{ "temp-dir",        required_argument, NULL, 0 },
356cbb44143SStephen Hemminger 		{ "version",         no_argument,       NULL, 'v' },
357cbb44143SStephen Hemminger 		{ NULL },
358cbb44143SStephen Hemminger 	};
359cbb44143SStephen Hemminger 	int option_index, c;
3606026bfaeSStephen Hemminger 	struct interface *last_intf = NULL;
3616026bfaeSStephen Hemminger 	uint32_t len;
362cbb44143SStephen Hemminger 
363cbb44143SStephen Hemminger 	for (;;) {
3648744f84bSStephen Hemminger 		c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqSs:vw:",
365cbb44143SStephen Hemminger 				long_options, &option_index);
366cbb44143SStephen Hemminger 		if (c == -1)
367cbb44143SStephen Hemminger 			break;
368cbb44143SStephen Hemminger 
369cbb44143SStephen Hemminger 		switch (c) {
370d1920ed6SStephen Hemminger 		case 0: {
371d1920ed6SStephen Hemminger 			const char *longopt
372d1920ed6SStephen Hemminger 				= long_options[option_index].name;
373d1920ed6SStephen Hemminger 
374d1920ed6SStephen Hemminger 			if (!strcmp(longopt, "capture-comment")) {
375cbb44143SStephen Hemminger 				capture_comment = optarg;
376311137f1SStephen Hemminger 			} else if (!strcmp(longopt, "lcore")) {
377311137f1SStephen Hemminger 				lcore_arg = optarg;
378d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "file-prefix")) {
379eeb6cad4SStephen Hemminger 				file_prefix = optarg;
380d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "temp-dir")) {
381b39d52a5SStephen Hemminger 				tmp_dir = optarg;
382d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "ifdescr")) {
383d1920ed6SStephen Hemminger 				if (last_intf == NULL)
384d1920ed6SStephen Hemminger 					rte_exit(EXIT_FAILURE,
385d1920ed6SStephen Hemminger 						 "--ifdescr must be specified after a -i option\n");
386d1920ed6SStephen Hemminger 				last_intf->ifdescr = optarg;
387d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "ifname")) {
388d1920ed6SStephen Hemminger 				if (last_intf == NULL)
389d1920ed6SStephen Hemminger 					rte_exit(EXIT_FAILURE,
390d1920ed6SStephen Hemminger 						 "--ifname must be specified after a -i option\n");
391d1920ed6SStephen Hemminger 				last_intf->ifname = optarg;
392eeb6cad4SStephen Hemminger 			} else {
393cbb44143SStephen Hemminger 				usage();
394cbb44143SStephen Hemminger 				exit(1);
395cbb44143SStephen Hemminger 			}
396cbb44143SStephen Hemminger 			break;
397d1920ed6SStephen Hemminger 		}
398cbb44143SStephen Hemminger 		case 'a':
399cbb44143SStephen Hemminger 			auto_stop(optarg);
400cbb44143SStephen Hemminger 			break;
401cbb44143SStephen Hemminger 		case 'b':
402cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
403cbb44143SStephen Hemminger 				 "multiple files not implemented\n");
404cbb44143SStephen Hemminger 			break;
405cbb44143SStephen Hemminger 		case 'c':
406cbb44143SStephen Hemminger 			stop.packets = get_uint(optarg, "packet_count", 0);
407cbb44143SStephen Hemminger 			break;
408cbb44143SStephen Hemminger 		case 'd':
409cbb44143SStephen Hemminger 			dump_bpf = true;
410cbb44143SStephen Hemminger 			break;
411cbb44143SStephen Hemminger 		case 'D':
412d59fb4d1SStephen Hemminger 			show_interfaces = true;
413d59fb4d1SStephen Hemminger 			break;
414cbb44143SStephen Hemminger 		case 'f':
4156026bfaeSStephen Hemminger 			if (last_intf == NULL)
4166026bfaeSStephen Hemminger 				capture.filter = optarg;
4176026bfaeSStephen Hemminger 			else
4186026bfaeSStephen Hemminger 				last_intf->opts.filter = optarg;
419cbb44143SStephen Hemminger 			break;
420cbb44143SStephen Hemminger 		case 'g':
421cbb44143SStephen Hemminger 			group_read = true;
422cbb44143SStephen Hemminger 			break;
423cbb44143SStephen Hemminger 		case 'h':
424cbb44143SStephen Hemminger 			printf("%s\n\n", version());
425cbb44143SStephen Hemminger 			usage();
426cbb44143SStephen Hemminger 			exit(0);
427cbb44143SStephen Hemminger 		case 'i':
4286026bfaeSStephen Hemminger 			last_intf = add_interface(optarg);
429cbb44143SStephen Hemminger 			break;
430cbb44143SStephen Hemminger 		case 'n':
431cbb44143SStephen Hemminger 			use_pcapng = true;
432cbb44143SStephen Hemminger 			break;
433cbb44143SStephen Hemminger 		case 'N':
434cbb44143SStephen Hemminger 			ring_size = get_uint(optarg, "packet_limit", 0);
435cbb44143SStephen Hemminger 			break;
436cbb44143SStephen Hemminger 		case 'p':
4376026bfaeSStephen Hemminger 			/* Like dumpcap this option can occur multiple times.
4386026bfaeSStephen Hemminger 			 *
4396026bfaeSStephen Hemminger 			 * If used before the first occurrence of the -i option,
4406026bfaeSStephen Hemminger 			 * no interface will be put into the promiscuous mode.
4416026bfaeSStephen Hemminger 			 * If used after an -i option, the interface specified
4426026bfaeSStephen Hemminger 			 * by the last -i option occurring before this option
4436026bfaeSStephen Hemminger 			 * will not be put into the promiscuous mode.
4446026bfaeSStephen Hemminger 			 */
4456026bfaeSStephen Hemminger 			if (last_intf == NULL)
4466026bfaeSStephen Hemminger 				capture.promisc_mode = false;
4476026bfaeSStephen Hemminger 			else
4486026bfaeSStephen Hemminger 				last_intf->opts.promisc_mode = false;
449cbb44143SStephen Hemminger 			break;
450cbb44143SStephen Hemminger 		case 'P':
451cbb44143SStephen Hemminger 			use_pcapng = false;
452cbb44143SStephen Hemminger 			break;
453cbb44143SStephen Hemminger 		case 'q':
454cbb44143SStephen Hemminger 			quiet = true;
455cbb44143SStephen Hemminger 			break;
456cbb44143SStephen Hemminger 		case 's':
4576026bfaeSStephen Hemminger 			len = get_uint(optarg, "snap_len", 0);
4586026bfaeSStephen Hemminger 			if (last_intf == NULL)
4596026bfaeSStephen Hemminger 				capture.snap_len = len;
4606026bfaeSStephen Hemminger 			else
4616026bfaeSStephen Hemminger 				last_intf->opts.snap_len = len;
462cbb44143SStephen Hemminger 			break;
4638744f84bSStephen Hemminger 		case 'S':
4648744f84bSStephen Hemminger 			print_stats = true;
4658744f84bSStephen Hemminger 			break;
466cbb44143SStephen Hemminger 		case 'w':
467cbb44143SStephen Hemminger 			output_name = optarg;
468cbb44143SStephen Hemminger 			break;
469cbb44143SStephen Hemminger 		case 'v':
470cbb44143SStephen Hemminger 			printf("%s\n", version());
471cbb44143SStephen Hemminger 			exit(0);
472cbb44143SStephen Hemminger 		default:
473cbb44143SStephen Hemminger 			fprintf(stderr, "Invalid option: %s\n",
474cbb44143SStephen Hemminger 				argv[optind - 1]);
475cbb44143SStephen Hemminger 			usage();
476cbb44143SStephen Hemminger 			exit(1);
477cbb44143SStephen Hemminger 		}
478cbb44143SStephen Hemminger 	}
479cbb44143SStephen Hemminger }
480cbb44143SStephen Hemminger 
481cbb44143SStephen Hemminger static void
482cbb44143SStephen Hemminger signal_handler(int sig_num __rte_unused)
483cbb44143SStephen Hemminger {
484b6a7e685STyler Retzlaff 	rte_atomic_store_explicit(&quit_signal, true, rte_memory_order_relaxed);
485cbb44143SStephen Hemminger }
486cbb44143SStephen Hemminger 
4878744f84bSStephen Hemminger 
4888744f84bSStephen Hemminger /* Instead of capturing, it tracks interface statistics */
4898744f84bSStephen Hemminger static void statistics_loop(void)
4908744f84bSStephen Hemminger {
4918744f84bSStephen Hemminger 	struct rte_eth_stats stats;
4928744f84bSStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
4938744f84bSStephen Hemminger 	uint16_t p;
4948744f84bSStephen Hemminger 	int r;
4958744f84bSStephen Hemminger 
4968744f84bSStephen Hemminger 	printf("%-15s  %10s  %10s\n",
4978744f84bSStephen Hemminger 	       "Interface", "Received", "Dropped");
4988744f84bSStephen Hemminger 
499b6a7e685STyler Retzlaff 	while (!rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed)) {
5008744f84bSStephen Hemminger 		RTE_ETH_FOREACH_DEV(p) {
5018744f84bSStephen Hemminger 			if (rte_eth_dev_get_name_by_port(p, name) < 0)
5028744f84bSStephen Hemminger 				continue;
5038744f84bSStephen Hemminger 
5048744f84bSStephen Hemminger 			r = rte_eth_stats_get(p, &stats);
5058744f84bSStephen Hemminger 			if (r < 0) {
5068744f84bSStephen Hemminger 				fprintf(stderr,
5078744f84bSStephen Hemminger 					"stats_get for port %u failed: %d (%s)\n",
5081bda147fSStephen Hemminger 					p, r, strerror(-r));
5098744f84bSStephen Hemminger 				return;
5108744f84bSStephen Hemminger 			}
5118744f84bSStephen Hemminger 
5128744f84bSStephen Hemminger 			printf("%-15s  %10"PRIu64"  %10"PRIu64"\n",
5138744f84bSStephen Hemminger 			       name, stats.ipackets,
5148744f84bSStephen Hemminger 			       stats.imissed + stats.ierrors + stats.rx_nombuf);
5158744f84bSStephen Hemminger 		}
5168744f84bSStephen Hemminger 		sleep(1);
5178744f84bSStephen Hemminger 	}
5188744f84bSStephen Hemminger }
5198744f84bSStephen Hemminger 
520cbb44143SStephen Hemminger static void
521cbb44143SStephen Hemminger cleanup_pdump_resources(void)
522cbb44143SStephen Hemminger {
523cbb44143SStephen Hemminger 	struct interface *intf;
524cbb44143SStephen Hemminger 
525cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
526cbb44143SStephen Hemminger 		rte_pdump_disable(intf->port,
527cbb44143SStephen Hemminger 				  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
5286026bfaeSStephen Hemminger 		if (intf->opts.promisc_mode)
529cbb44143SStephen Hemminger 			rte_eth_promiscuous_disable(intf->port);
530cbb44143SStephen Hemminger 	}
531cbb44143SStephen Hemminger }
532cbb44143SStephen Hemminger 
533cbb44143SStephen Hemminger /* Alarm signal handler, used to check that primary process */
534cbb44143SStephen Hemminger static void
535cbb44143SStephen Hemminger monitor_primary(void *arg __rte_unused)
536cbb44143SStephen Hemminger {
537b6a7e685STyler Retzlaff 	if (rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed))
538cbb44143SStephen Hemminger 		return;
539cbb44143SStephen Hemminger 
540cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL)) {
541cbb44143SStephen Hemminger 		rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
542cbb44143SStephen Hemminger 	} else {
543cbb44143SStephen Hemminger 		fprintf(stderr,
544cbb44143SStephen Hemminger 			"Primary process is no longer active, exiting...\n");
545b6a7e685STyler Retzlaff 		rte_atomic_store_explicit(&quit_signal, true, rte_memory_order_relaxed);
546cbb44143SStephen Hemminger 	}
547cbb44143SStephen Hemminger }
548cbb44143SStephen Hemminger 
549cbb44143SStephen Hemminger /* Setup handler to check when primary exits. */
550cbb44143SStephen Hemminger static void
551cbb44143SStephen Hemminger enable_primary_monitor(void)
552cbb44143SStephen Hemminger {
553cbb44143SStephen Hemminger 	int ret;
554cbb44143SStephen Hemminger 
555cbb44143SStephen Hemminger 	/* Once primary exits, so will pdump. */
556cbb44143SStephen Hemminger 	ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
557cbb44143SStephen Hemminger 	if (ret < 0)
558cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to enable monitor:%d\n", ret);
559cbb44143SStephen Hemminger }
560cbb44143SStephen Hemminger 
561cbb44143SStephen Hemminger static void
562cbb44143SStephen Hemminger disable_primary_monitor(void)
563cbb44143SStephen Hemminger {
564cbb44143SStephen Hemminger 	int ret;
565cbb44143SStephen Hemminger 
566cbb44143SStephen Hemminger 	ret = rte_eal_alarm_cancel(monitor_primary, NULL);
567cbb44143SStephen Hemminger 	if (ret < 0)
568cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to disable monitor:%d\n", ret);
569cbb44143SStephen Hemminger }
570cbb44143SStephen Hemminger 
571cbb44143SStephen Hemminger static void
572cbb44143SStephen Hemminger report_packet_stats(dumpcap_out_t out)
573cbb44143SStephen Hemminger {
574cbb44143SStephen Hemminger 	struct rte_pdump_stats pdump_stats;
575cbb44143SStephen Hemminger 	struct interface *intf;
576cbb44143SStephen Hemminger 	uint64_t ifrecv, ifdrop;
577cbb44143SStephen Hemminger 	double percent;
578cbb44143SStephen Hemminger 
579cbb44143SStephen Hemminger 	fputc('\n', stderr);
580cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
581cbb44143SStephen Hemminger 		if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
582cbb44143SStephen Hemminger 			continue;
583cbb44143SStephen Hemminger 
584cbb44143SStephen Hemminger 		/* do what Wiretap does */
585cbb44143SStephen Hemminger 		ifrecv = pdump_stats.accepted + pdump_stats.filtered;
586cbb44143SStephen Hemminger 		ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
587cbb44143SStephen Hemminger 
588cbb44143SStephen Hemminger 		if (use_pcapng)
58916659193SStephen Hemminger 			rte_pcapng_write_stats(out.pcapng, intf->port,
59016659193SStephen Hemminger 					       ifrecv, ifdrop, NULL);
591cbb44143SStephen Hemminger 
592cbb44143SStephen Hemminger 		if (ifrecv == 0)
593cbb44143SStephen Hemminger 			percent = 0;
594cbb44143SStephen Hemminger 		else
595cbb44143SStephen Hemminger 			percent = 100. * ifrecv / (ifrecv + ifdrop);
596cbb44143SStephen Hemminger 
597cbb44143SStephen Hemminger 		fprintf(stderr,
598cbb44143SStephen Hemminger 			"Packets received/dropped on interface '%s': "
599cbb44143SStephen Hemminger 			"%"PRIu64 "/%" PRIu64 " (%.1f)\n",
600cbb44143SStephen Hemminger 			intf->name, ifrecv, ifdrop, percent);
601cbb44143SStephen Hemminger 	}
602cbb44143SStephen Hemminger }
603cbb44143SStephen Hemminger 
604cbb44143SStephen Hemminger /*
605cbb44143SStephen Hemminger  * Start DPDK EAL with arguments.
606cbb44143SStephen Hemminger  * Unlike most DPDK programs, this application does not use the
607cbb44143SStephen Hemminger  * typical EAL command line arguments.
608cbb44143SStephen Hemminger  * We don't want to expose all the DPDK internals to the user.
609cbb44143SStephen Hemminger  */
610cbb44143SStephen Hemminger static void dpdk_init(void)
611cbb44143SStephen Hemminger {
612cbb44143SStephen Hemminger 	static const char * const args[] = {
613cbb44143SStephen Hemminger 		"dumpcap", "--proc-type", "secondary",
614cbb44143SStephen Hemminger 		"--log-level", "notice"
615cbb44143SStephen Hemminger 	};
616eeb6cad4SStephen Hemminger 	int eal_argc = RTE_DIM(args);
617311137f1SStephen Hemminger 	rte_cpuset_t cpuset = { };
618cbb44143SStephen Hemminger 	char **eal_argv;
619cbb44143SStephen Hemminger 	unsigned int i;
620cbb44143SStephen Hemminger 
621eeb6cad4SStephen Hemminger 	if (file_prefix != NULL)
622eeb6cad4SStephen Hemminger 		eal_argc += 2;
623eeb6cad4SStephen Hemminger 
624311137f1SStephen Hemminger 	if (lcore_arg != NULL)
625311137f1SStephen Hemminger 		eal_argc += 2;
626311137f1SStephen Hemminger 
627cbb44143SStephen Hemminger 	/* DPDK API requires mutable versions of command line arguments. */
628cbb44143SStephen Hemminger 	eal_argv = calloc(eal_argc + 1, sizeof(char *));
629cbb44143SStephen Hemminger 	if (eal_argv == NULL)
630cbb44143SStephen Hemminger 		rte_panic("No memory\n");
631cbb44143SStephen Hemminger 
632cbb44143SStephen Hemminger 	eal_argv[0] = strdup(progname);
633cbb44143SStephen Hemminger 	for (i = 1; i < RTE_DIM(args); i++)
634cbb44143SStephen Hemminger 		eal_argv[i] = strdup(args[i]);
635cbb44143SStephen Hemminger 
636311137f1SStephen Hemminger 	if (lcore_arg != NULL) {
637311137f1SStephen Hemminger 		eal_argv[i++] = strdup("--lcores");
638311137f1SStephen Hemminger 		eal_argv[i++] = strdup(lcore_arg);
639311137f1SStephen Hemminger 	}
640311137f1SStephen Hemminger 
641eeb6cad4SStephen Hemminger 	if (file_prefix != NULL) {
642eeb6cad4SStephen Hemminger 		eal_argv[i++] = strdup("--file-prefix");
643eeb6cad4SStephen Hemminger 		eal_argv[i++] = strdup(file_prefix);
644eeb6cad4SStephen Hemminger 	}
645eeb6cad4SStephen Hemminger 
6466bb5ffe3SChengwen Feng 	for (i = 0; i < (unsigned int)eal_argc; i++) {
6476bb5ffe3SChengwen Feng 		if (eal_argv[i] == NULL)
6486bb5ffe3SChengwen Feng 			rte_panic("No memory\n");
6496bb5ffe3SChengwen Feng 	}
6506bb5ffe3SChengwen Feng 
651311137f1SStephen Hemminger 	/*
652311137f1SStephen Hemminger 	 * Need to get the original cpuset, before EAL init changes
653311137f1SStephen Hemminger 	 * the affinity of this thread (main lcore).
654311137f1SStephen Hemminger 	 */
655311137f1SStephen Hemminger 	if (lcore_arg == NULL &&
656311137f1SStephen Hemminger 	    rte_thread_get_affinity_by_id(rte_thread_self(), &cpuset) != 0)
657311137f1SStephen Hemminger 		rte_panic("rte_thread_getaffinity failed\n");
658311137f1SStephen Hemminger 
659cbb44143SStephen Hemminger 	if (rte_eal_init(eal_argc, eal_argv) < 0)
660cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
661311137f1SStephen Hemminger 
662311137f1SStephen Hemminger 	/*
663311137f1SStephen Hemminger 	 * If no lcore argument was specified, then run this program as a normal process
664311137f1SStephen Hemminger 	 * which can be scheduled on any non-isolated CPU.
665311137f1SStephen Hemminger 	 */
666311137f1SStephen Hemminger 	if (lcore_arg == NULL &&
667311137f1SStephen Hemminger 	    rte_thread_set_affinity_by_id(rte_thread_self(), &cpuset) != 0)
668311137f1SStephen Hemminger 		rte_exit(EXIT_FAILURE, "Can not restore original CPU affinity\n");
669cbb44143SStephen Hemminger }
670cbb44143SStephen Hemminger 
671cbb44143SStephen Hemminger /* Create packet ring shared between callbacks and process */
672cbb44143SStephen Hemminger static struct rte_ring *create_ring(void)
673cbb44143SStephen Hemminger {
674cbb44143SStephen Hemminger 	struct rte_ring *ring;
675e0235c0eSStephen Hemminger 	char ring_name[RTE_RING_NAMESIZE];
676cbb44143SStephen Hemminger 	size_t size, log2;
677cbb44143SStephen Hemminger 
678cbb44143SStephen Hemminger 	/* Find next power of 2 >= size. */
679cbb44143SStephen Hemminger 	size = ring_size;
6802a682d65SStephen Hemminger 	log2 = sizeof(size) * 8 - rte_clz64(size - 1);
681cbb44143SStephen Hemminger 	size = 1u << log2;
682cbb44143SStephen Hemminger 
683cbb44143SStephen Hemminger 	if (size != ring_size) {
684cbb44143SStephen Hemminger 		fprintf(stderr, "Ring size %u rounded up to %zu\n",
685cbb44143SStephen Hemminger 			ring_size, size);
686cbb44143SStephen Hemminger 		ring_size = size;
687cbb44143SStephen Hemminger 	}
688cbb44143SStephen Hemminger 
689e0235c0eSStephen Hemminger 	/* Want one ring per invocation of program */
690e0235c0eSStephen Hemminger 	snprintf(ring_name, sizeof(ring_name),
691e0235c0eSStephen Hemminger 		 "dumpcap-%d", getpid());
692e0235c0eSStephen Hemminger 
693e0235c0eSStephen Hemminger 	ring = rte_ring_create(ring_name, ring_size,
694cbb44143SStephen Hemminger 			       rte_socket_id(), 0);
695cbb44143SStephen Hemminger 	if (ring == NULL)
696cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
697cbb44143SStephen Hemminger 			 rte_strerror(rte_errno));
698e0235c0eSStephen Hemminger 
699cbb44143SStephen Hemminger 	return ring;
700cbb44143SStephen Hemminger }
701cbb44143SStephen Hemminger 
702cbb44143SStephen Hemminger static struct rte_mempool *create_mempool(void)
703cbb44143SStephen Hemminger {
7046026bfaeSStephen Hemminger 	const struct interface *intf;
705e0235c0eSStephen Hemminger 	char pool_name[RTE_MEMPOOL_NAMESIZE];
706cbb44143SStephen Hemminger 	size_t num_mbufs = 2 * ring_size;
707cbb44143SStephen Hemminger 	struct rte_mempool *mp;
7086026bfaeSStephen Hemminger 	uint32_t data_size = 128;
709cbb44143SStephen Hemminger 
710e0235c0eSStephen Hemminger 	snprintf(pool_name, sizeof(pool_name), "capture_%d", getpid());
711cbb44143SStephen Hemminger 
7126026bfaeSStephen Hemminger 	/* Common pool so size mbuf for biggest snap length */
7136026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
7146026bfaeSStephen Hemminger 		uint32_t mbuf_size = rte_pcapng_mbuf_size(intf->opts.snap_len);
7156026bfaeSStephen Hemminger 
7166026bfaeSStephen Hemminger 		if (mbuf_size > data_size)
7176026bfaeSStephen Hemminger 			data_size = mbuf_size;
7186026bfaeSStephen Hemminger 	}
7196026bfaeSStephen Hemminger 
720cbb44143SStephen Hemminger 	mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
721cbb44143SStephen Hemminger 					    MBUF_POOL_CACHE_SIZE, 0,
7226026bfaeSStephen Hemminger 					    data_size,
72327a26d65SStephen Hemminger 					    rte_socket_id(), "ring_mp_mc");
724cbb44143SStephen Hemminger 	if (mp == NULL)
725cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
726cbb44143SStephen Hemminger 			 "Mempool (%s) creation failed: %s\n", pool_name,
727cbb44143SStephen Hemminger 			 rte_strerror(rte_errno));
728cbb44143SStephen Hemminger 
729cbb44143SStephen Hemminger 	return mp;
730cbb44143SStephen Hemminger }
731cbb44143SStephen Hemminger 
732cbb44143SStephen Hemminger /*
733cbb44143SStephen Hemminger  * Get Operating System information.
734cbb44143SStephen Hemminger  * Returns an string allocated via malloc().
735cbb44143SStephen Hemminger  */
736cbb44143SStephen Hemminger static char *get_os_info(void)
737cbb44143SStephen Hemminger {
738cbb44143SStephen Hemminger 	struct utsname uts;
739cbb44143SStephen Hemminger 	char *osname = NULL;
740cbb44143SStephen Hemminger 
741cbb44143SStephen Hemminger 	if (uname(&uts) < 0)
742cbb44143SStephen Hemminger 		return NULL;
743cbb44143SStephen Hemminger 
744cbb44143SStephen Hemminger 	if (asprintf(&osname, "%s %s",
745cbb44143SStephen Hemminger 		     uts.sysname, uts.release) == -1)
746cbb44143SStephen Hemminger 		return NULL;
747cbb44143SStephen Hemminger 
748cbb44143SStephen Hemminger 	return osname;
749cbb44143SStephen Hemminger }
750cbb44143SStephen Hemminger 
751cbb44143SStephen Hemminger static dumpcap_out_t create_output(void)
752cbb44143SStephen Hemminger {
753cbb44143SStephen Hemminger 	dumpcap_out_t ret;
754cbb44143SStephen Hemminger 	static char tmp_path[PATH_MAX];
755cbb44143SStephen Hemminger 	int fd;
756cbb44143SStephen Hemminger 
757cbb44143SStephen Hemminger 	/* If no filename specified make a tempfile name */
758cbb44143SStephen Hemminger 	if (output_name == NULL) {
759cbb44143SStephen Hemminger 		struct interface *intf;
760cbb44143SStephen Hemminger 		struct tm *tm;
761cbb44143SStephen Hemminger 		time_t now;
762cbb44143SStephen Hemminger 		char ts[32];
763cbb44143SStephen Hemminger 
764cbb44143SStephen Hemminger 		intf = TAILQ_FIRST(&interfaces);
765cbb44143SStephen Hemminger 		now = time(NULL);
766cbb44143SStephen Hemminger 		tm = localtime(&now);
767cbb44143SStephen Hemminger 		if (!tm)
768cbb44143SStephen Hemminger 			rte_panic("localtime failed\n");
769cbb44143SStephen Hemminger 
770cbb44143SStephen Hemminger 		strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
771cbb44143SStephen Hemminger 
772cbb44143SStephen Hemminger 		snprintf(tmp_path, sizeof(tmp_path),
773b39d52a5SStephen Hemminger 			 "%s/%s_%u_%s_%s.%s", tmp_dir,
774cbb44143SStephen Hemminger 			 progname, intf->port, intf->name, ts,
775cbb44143SStephen Hemminger 			 use_pcapng ? "pcapng" : "pcap");
776cbb44143SStephen Hemminger 		output_name = tmp_path;
777cbb44143SStephen Hemminger 	}
778cbb44143SStephen Hemminger 
779cbb44143SStephen Hemminger 	if (strcmp(output_name, "-") == 0)
780cbb44143SStephen Hemminger 		fd = STDOUT_FILENO;
781cbb44143SStephen Hemminger 	else {
782cbb44143SStephen Hemminger 		mode_t mode = group_read ? 0640 : 0600;
783cbb44143SStephen Hemminger 
784117e3b64SStephen Hemminger 		fprintf(stderr, "File: %s\n", output_name);
785cbb44143SStephen Hemminger 		fd = open(output_name, O_WRONLY | O_CREAT, mode);
786cbb44143SStephen Hemminger 		if (fd < 0)
787cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
788cbb44143SStephen Hemminger 				 output_name, strerror(errno));
789cbb44143SStephen Hemminger 	}
790cbb44143SStephen Hemminger 
791cbb44143SStephen Hemminger 	if (use_pcapng) {
792d1920ed6SStephen Hemminger 		struct interface *intf;
793cbb44143SStephen Hemminger 		char *os = get_os_info();
794cbb44143SStephen Hemminger 
795cbb44143SStephen Hemminger 		ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
796cbb44143SStephen Hemminger 					   version(), capture_comment);
797cbb44143SStephen Hemminger 		if (ret.pcapng == NULL)
798cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
799cbb44143SStephen Hemminger 				 strerror(rte_errno));
800cbb44143SStephen Hemminger 		free(os);
801d1920ed6SStephen Hemminger 
802d1920ed6SStephen Hemminger 		TAILQ_FOREACH(intf, &interfaces, next) {
803*c79900e3SStephen Hemminger 			if (rte_pcapng_add_interface(ret.pcapng, intf->port, intf->ifname,
804*c79900e3SStephen Hemminger 						     intf->ifdescr, intf->opts.filter) < 0)
805*c79900e3SStephen Hemminger 				rte_exit(EXIT_FAILURE, "rte_pcapng_add_interface %u failed\n",
806*c79900e3SStephen Hemminger 					intf->port);
807d1920ed6SStephen Hemminger 		}
808cbb44143SStephen Hemminger 	} else {
809cbb44143SStephen Hemminger 		pcap_t *pcap;
810cbb44143SStephen Hemminger 
8116026bfaeSStephen Hemminger 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
8126026bfaeSStephen Hemminger 							    capture.snap_len,
813cbb44143SStephen Hemminger 							    PCAP_TSTAMP_PRECISION_NANO);
814cbb44143SStephen Hemminger 		if (pcap == NULL)
815cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
816cbb44143SStephen Hemminger 
817cbb44143SStephen Hemminger 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
818cbb44143SStephen Hemminger 		if (ret.dumper == NULL)
819cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
820cbb44143SStephen Hemminger 				 pcap_geterr(pcap));
821cbb44143SStephen Hemminger 	}
822cbb44143SStephen Hemminger 
823cbb44143SStephen Hemminger 	return ret;
824cbb44143SStephen Hemminger }
825cbb44143SStephen Hemminger 
826cbb44143SStephen Hemminger static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
827cbb44143SStephen Hemminger {
828cbb44143SStephen Hemminger 	struct interface *intf;
8296026bfaeSStephen Hemminger 	unsigned int count = 0;
830cbb44143SStephen Hemminger 	uint32_t flags;
831cbb44143SStephen Hemminger 	int ret;
832cbb44143SStephen Hemminger 
833cbb44143SStephen Hemminger 	flags = RTE_PDUMP_FLAG_RXTX;
834cbb44143SStephen Hemminger 	if (use_pcapng)
835cbb44143SStephen Hemminger 		flags |= RTE_PDUMP_FLAG_PCAPNG;
836cbb44143SStephen Hemminger 
837cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
8386026bfaeSStephen Hemminger 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
8396026bfaeSStephen Hemminger 					   flags, intf->opts.snap_len,
8406026bfaeSStephen Hemminger 					   r, mp, intf->bpf_prm);
8416026bfaeSStephen Hemminger 		if (ret < 0) {
8426026bfaeSStephen Hemminger 			const struct interface *intf2;
8436026bfaeSStephen Hemminger 
8446026bfaeSStephen Hemminger 			/* unwind any previous enables */
8456026bfaeSStephen Hemminger 			TAILQ_FOREACH(intf2, &interfaces, next) {
8466026bfaeSStephen Hemminger 				if (intf == intf2)
8476026bfaeSStephen Hemminger 					break;
8486026bfaeSStephen Hemminger 				rte_pdump_disable(intf2->port,
8496026bfaeSStephen Hemminger 						  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
8506026bfaeSStephen Hemminger 				if (intf2->opts.promisc_mode)
8516026bfaeSStephen Hemminger 					rte_eth_promiscuous_disable(intf2->port);
8526026bfaeSStephen Hemminger 			}
8536026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE,
8546026bfaeSStephen Hemminger 				"Packet dump enable on %u:%s failed %s\n",
8556026bfaeSStephen Hemminger 				intf->port, intf->name,
856e0235c0eSStephen Hemminger 				rte_strerror(rte_errno));
8576026bfaeSStephen Hemminger 		}
8586026bfaeSStephen Hemminger 
8596026bfaeSStephen Hemminger 		if (intf->opts.promisc_mode) {
8606026bfaeSStephen Hemminger 			if (rte_eth_promiscuous_get(intf->port) == 1) {
8616026bfaeSStephen Hemminger 				/* promiscuous already enabled */
8626026bfaeSStephen Hemminger 				intf->opts.promisc_mode = false;
863b4f865beSIsaac Boukris 			} else if (rte_eth_promiscuous_enable(intf->port) < 0) {
864b4f865beSIsaac Boukris 				fprintf(stderr, "port %u:%s set promiscuous failed\n",
865b4f865beSIsaac Boukris 					intf->port, intf->name);
8666026bfaeSStephen Hemminger 				intf->opts.promisc_mode = false;
8676026bfaeSStephen Hemminger 			}
8686026bfaeSStephen Hemminger 		}
8696026bfaeSStephen Hemminger 		++count;
870499b1cbcSStephen Hemminger 	}
871cbb44143SStephen Hemminger 
8726026bfaeSStephen Hemminger 	fputs("Capturing on ", stdout);
8736026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
8746026bfaeSStephen Hemminger 		if (intf != TAILQ_FIRST(&interfaces)) {
8756026bfaeSStephen Hemminger 			if (count > 2)
8766026bfaeSStephen Hemminger 				putchar(',');
8776026bfaeSStephen Hemminger 			putchar(' ');
8786026bfaeSStephen Hemminger 			if (TAILQ_NEXT(intf, next) == NULL)
8796026bfaeSStephen Hemminger 				fputs("and ", stdout);
880cbb44143SStephen Hemminger 		}
8816026bfaeSStephen Hemminger 		printf("'%s'", intf->name);
8826026bfaeSStephen Hemminger 	}
8836026bfaeSStephen Hemminger 	putchar('\n');
884cbb44143SStephen Hemminger }
885cbb44143SStephen Hemminger 
886cbb44143SStephen Hemminger /*
887cbb44143SStephen Hemminger  * Show current count of captured packets
888cbb44143SStephen Hemminger  * with backspaces to overwrite last value.
889cbb44143SStephen Hemminger  */
890cbb44143SStephen Hemminger static void show_count(uint64_t count)
891cbb44143SStephen Hemminger {
892cbb44143SStephen Hemminger 	unsigned int i;
893cbb44143SStephen Hemminger 	static unsigned int bt;
894cbb44143SStephen Hemminger 
895cbb44143SStephen Hemminger 	for (i = 0; i < bt; i++)
896cbb44143SStephen Hemminger 		fputc('\b', stderr);
897cbb44143SStephen Hemminger 
898cbb44143SStephen Hemminger 	bt = fprintf(stderr, "%"PRIu64" ", count);
899cbb44143SStephen Hemminger }
900cbb44143SStephen Hemminger 
901cbb44143SStephen Hemminger /* Write multiple packets in older pcap format */
902cbb44143SStephen Hemminger static ssize_t
903cbb44143SStephen Hemminger pcap_write_packets(pcap_dumper_t *dumper,
904cbb44143SStephen Hemminger 		   struct rte_mbuf *pkts[], uint16_t n)
905cbb44143SStephen Hemminger {
9065c0f970cSStephen Hemminger 	uint8_t temp_data[RTE_ETHER_MAX_JUMBO_FRAME_LEN];
907cbb44143SStephen Hemminger 	struct pcap_pkthdr header;
908cbb44143SStephen Hemminger 	uint16_t i;
909cbb44143SStephen Hemminger 	size_t total = 0;
910cbb44143SStephen Hemminger 
911cbb44143SStephen Hemminger 	gettimeofday(&header.ts, NULL);
912cbb44143SStephen Hemminger 
913cbb44143SStephen Hemminger 	for (i = 0; i < n; i++) {
914cbb44143SStephen Hemminger 		struct rte_mbuf *m = pkts[i];
9155c0f970cSStephen Hemminger 		size_t len, caplen;
916cbb44143SStephen Hemminger 
9175c0f970cSStephen Hemminger 		len = caplen = rte_pktmbuf_pkt_len(m);
9185c0f970cSStephen Hemminger 		if (unlikely(!rte_pktmbuf_is_contiguous(m) && len > sizeof(temp_data)))
9195c0f970cSStephen Hemminger 			caplen = sizeof(temp_data);
9205c0f970cSStephen Hemminger 
9215c0f970cSStephen Hemminger 		header.len = len;
9225c0f970cSStephen Hemminger 		header.caplen = caplen;
923cbb44143SStephen Hemminger 
924cbb44143SStephen Hemminger 		pcap_dump((u_char *)dumper, &header,
9255c0f970cSStephen Hemminger 			  rte_pktmbuf_read(m, 0, caplen, temp_data));
926cbb44143SStephen Hemminger 
9275c0f970cSStephen Hemminger 		total += sizeof(header) + caplen;
928cbb44143SStephen Hemminger 	}
929cbb44143SStephen Hemminger 
930cbb44143SStephen Hemminger 	return total;
931cbb44143SStephen Hemminger }
932cbb44143SStephen Hemminger 
933cbb44143SStephen Hemminger /* Process all packets in ring and dump to capture file */
934cbb44143SStephen Hemminger static int process_ring(dumpcap_out_t out, struct rte_ring *r)
935cbb44143SStephen Hemminger {
936cbb44143SStephen Hemminger 	struct rte_mbuf *pkts[BURST_SIZE];
937cbb44143SStephen Hemminger 	unsigned int avail, n;
938cbb44143SStephen Hemminger 	static unsigned int empty_count;
939cbb44143SStephen Hemminger 	ssize_t written;
940cbb44143SStephen Hemminger 
941cbb44143SStephen Hemminger 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
942cbb44143SStephen Hemminger 				      &avail);
943cbb44143SStephen Hemminger 	if (n == 0) {
944cbb44143SStephen Hemminger 		/* don't consume endless amounts of cpu if idle */
945cbb44143SStephen Hemminger 		if (empty_count < SLEEP_THRESHOLD)
946cbb44143SStephen Hemminger 			++empty_count;
947cbb44143SStephen Hemminger 		else
948cbb44143SStephen Hemminger 			usleep(10);
949cbb44143SStephen Hemminger 		return 0;
950cbb44143SStephen Hemminger 	}
951cbb44143SStephen Hemminger 
952cbb44143SStephen Hemminger 	empty_count = (avail == 0);
953cbb44143SStephen Hemminger 
954cbb44143SStephen Hemminger 	if (use_pcapng)
955cbb44143SStephen Hemminger 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
956cbb44143SStephen Hemminger 	else
957cbb44143SStephen Hemminger 		written = pcap_write_packets(out.dumper, pkts, n);
958cbb44143SStephen Hemminger 
959cbb44143SStephen Hemminger 	rte_pktmbuf_free_bulk(pkts, n);
960cbb44143SStephen Hemminger 
961cbb44143SStephen Hemminger 	if (written < 0)
962cbb44143SStephen Hemminger 		return -1;
963cbb44143SStephen Hemminger 
964cbb44143SStephen Hemminger 	file_size += written;
965cbb44143SStephen Hemminger 	packets_received += n;
966cbb44143SStephen Hemminger 	if (!quiet)
967cbb44143SStephen Hemminger 		show_count(packets_received);
968cbb44143SStephen Hemminger 
969cbb44143SStephen Hemminger 	return 0;
970cbb44143SStephen Hemminger }
971cbb44143SStephen Hemminger 
972cbb44143SStephen Hemminger int main(int argc, char **argv)
973cbb44143SStephen Hemminger {
974cbb44143SStephen Hemminger 	struct rte_ring *r;
975cbb44143SStephen Hemminger 	struct rte_mempool *mp;
976b04d11bdSStephen Hemminger 	struct sigaction action = {
977b04d11bdSStephen Hemminger 		.sa_flags = SA_RESTART,
978b04d11bdSStephen Hemminger 		.sa_handler = signal_handler,
979b04d11bdSStephen Hemminger 	};
980b04d11bdSStephen Hemminger 	struct sigaction origaction;
981cbb44143SStephen Hemminger 	dumpcap_out_t out;
982117e3b64SStephen Hemminger 	char *p;
983cbb44143SStephen Hemminger 
984117e3b64SStephen Hemminger 	p = strrchr(argv[0], '/');
985117e3b64SStephen Hemminger 	if (p == NULL)
986cbb44143SStephen Hemminger 		progname = argv[0];
987117e3b64SStephen Hemminger 	else
988117e3b64SStephen Hemminger 		progname = p + 1;
989cbb44143SStephen Hemminger 
990cbb44143SStephen Hemminger 	parse_opts(argc, argv);
991a8dde09fSBen Magistro 	dpdk_init();
992cbb44143SStephen Hemminger 
993d59fb4d1SStephen Hemminger 	if (show_interfaces)
994d59fb4d1SStephen Hemminger 		dump_interfaces();
995d59fb4d1SStephen Hemminger 
996d59fb4d1SStephen Hemminger 	if (rte_eth_dev_count_avail() == 0)
997d59fb4d1SStephen Hemminger 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
998d59fb4d1SStephen Hemminger 
999cbb44143SStephen Hemminger 	if (TAILQ_EMPTY(&interfaces))
1000cbb44143SStephen Hemminger 		set_default_interface();
10016026bfaeSStephen Hemminger 	else
10026026bfaeSStephen Hemminger 		find_interfaces();
10036026bfaeSStephen Hemminger 
10046026bfaeSStephen Hemminger 	compile_filters();
1005cbb44143SStephen Hemminger 
1006b04d11bdSStephen Hemminger 	sigemptyset(&action.sa_mask);
1007b04d11bdSStephen Hemminger 	sigaction(SIGTERM, &action, NULL);
1008b04d11bdSStephen Hemminger 	sigaction(SIGINT, &action, NULL);
1009b04d11bdSStephen Hemminger 	sigaction(SIGPIPE, &action, NULL);
1010b04d11bdSStephen Hemminger 	sigaction(SIGHUP, NULL, &origaction);
1011b04d11bdSStephen Hemminger 	if (origaction.sa_handler == SIG_DFL)
1012b04d11bdSStephen Hemminger 		sigaction(SIGHUP, &action, NULL);
10138744f84bSStephen Hemminger 
10148744f84bSStephen Hemminger 	enable_primary_monitor();
10158744f84bSStephen Hemminger 
10168744f84bSStephen Hemminger 	if (print_stats) {
10178744f84bSStephen Hemminger 		statistics_loop();
10188744f84bSStephen Hemminger 		exit(0);
10198744f84bSStephen Hemminger 	}
10208744f84bSStephen Hemminger 
1021cbb44143SStephen Hemminger 	r = create_ring();
1022cbb44143SStephen Hemminger 	mp = create_mempool();
1023cbb44143SStephen Hemminger 	out = create_output();
1024cbb44143SStephen Hemminger 
102516659193SStephen Hemminger 	start_time = time(NULL);
1026cbb44143SStephen Hemminger 	enable_pdump(r, mp);
1027cbb44143SStephen Hemminger 
1028cbb44143SStephen Hemminger 	if (!quiet) {
1029cbb44143SStephen Hemminger 		fprintf(stderr, "Packets captured: ");
1030cbb44143SStephen Hemminger 		show_count(0);
1031cbb44143SStephen Hemminger 	}
1032cbb44143SStephen Hemminger 
1033b6a7e685STyler Retzlaff 	while (!rte_atomic_load_explicit(&quit_signal, rte_memory_order_relaxed)) {
1034cbb44143SStephen Hemminger 		if (process_ring(out, r) < 0) {
1035cbb44143SStephen Hemminger 			fprintf(stderr, "pcapng file write failed; %s\n",
1036cbb44143SStephen Hemminger 				strerror(errno));
1037cbb44143SStephen Hemminger 			break;
1038cbb44143SStephen Hemminger 		}
1039cbb44143SStephen Hemminger 
1040cbb44143SStephen Hemminger 		if (stop.size && file_size >= stop.size)
1041cbb44143SStephen Hemminger 			break;
1042cbb44143SStephen Hemminger 
1043cbb44143SStephen Hemminger 		if (stop.packets && packets_received >= stop.packets)
1044cbb44143SStephen Hemminger 			break;
1045cbb44143SStephen Hemminger 
1046cbb44143SStephen Hemminger 		if (stop.duration != 0 &&
104716659193SStephen Hemminger 		    time(NULL) - start_time > stop.duration)
1048cbb44143SStephen Hemminger 			break;
1049cbb44143SStephen Hemminger 	}
1050cbb44143SStephen Hemminger 
1051cbb44143SStephen Hemminger 	disable_primary_monitor();
1052cbb44143SStephen Hemminger 
1053cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL))
1054cbb44143SStephen Hemminger 		report_packet_stats(out);
1055cbb44143SStephen Hemminger 
1056cbb44143SStephen Hemminger 	if (use_pcapng)
1057cbb44143SStephen Hemminger 		rte_pcapng_close(out.pcapng);
1058cbb44143SStephen Hemminger 	else
1059cbb44143SStephen Hemminger 		pcap_dump_close(out.dumper);
1060cbb44143SStephen Hemminger 
1061cbb44143SStephen Hemminger 	cleanup_pdump_resources();
10621835ea99SStephen Hemminger 
1063cbb44143SStephen Hemminger 	rte_ring_free(r);
1064cbb44143SStephen Hemminger 	rte_mempool_free(mp);
1065cbb44143SStephen Hemminger 
1066cbb44143SStephen Hemminger 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
1067cbb44143SStephen Hemminger }
1068