xref: /dpdk/app/dumpcap/main.c (revision 27a26d65f8039ec38a49932c4bb73801b4fd62b8)
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>
27cbb44143SStephen Hemminger #include <rte_bpf.h>
28cbb44143SStephen Hemminger #include <rte_config.h>
29cbb44143SStephen Hemminger #include <rte_debug.h>
30cbb44143SStephen Hemminger #include <rte_eal.h>
31cbb44143SStephen Hemminger #include <rte_errno.h>
32cbb44143SStephen Hemminger #include <rte_ethdev.h>
33cbb44143SStephen Hemminger #include <rte_lcore.h>
34cbb44143SStephen Hemminger #include <rte_malloc.h>
35cbb44143SStephen Hemminger #include <rte_mbuf.h>
36cbb44143SStephen Hemminger #include <rte_mempool.h>
37cbb44143SStephen Hemminger #include <rte_pcapng.h>
38cbb44143SStephen Hemminger #include <rte_pdump.h>
39cbb44143SStephen Hemminger #include <rte_ring.h>
40cbb44143SStephen Hemminger #include <rte_string_fns.h>
41cbb44143SStephen Hemminger #include <rte_time.h>
42cbb44143SStephen Hemminger #include <rte_version.h>
43cbb44143SStephen Hemminger 
44cbb44143SStephen Hemminger #include <pcap/pcap.h>
45cbb44143SStephen Hemminger #include <pcap/bpf.h>
46cbb44143SStephen Hemminger 
47cbb44143SStephen Hemminger #define RING_NAME "capture-ring"
48cbb44143SStephen Hemminger #define MONITOR_INTERVAL  (500 * 1000)
49cbb44143SStephen Hemminger #define MBUF_POOL_CACHE_SIZE 32
50cbb44143SStephen Hemminger #define BURST_SIZE 32
51cbb44143SStephen Hemminger #define SLEEP_THRESHOLD 1000
52cbb44143SStephen Hemminger 
53cbb44143SStephen Hemminger /* command line flags */
54cbb44143SStephen Hemminger static const char *progname;
55cbb44143SStephen Hemminger static bool quit_signal;
56cbb44143SStephen Hemminger static bool group_read;
57cbb44143SStephen Hemminger static bool quiet;
58cbb44143SStephen Hemminger static bool use_pcapng = true;
59cbb44143SStephen Hemminger static char *output_name;
60b39d52a5SStephen Hemminger static const char *tmp_dir = "/tmp";
61cbb44143SStephen Hemminger static unsigned int ring_size = 2048;
62cbb44143SStephen Hemminger static const char *capture_comment;
63eeb6cad4SStephen Hemminger static const char *file_prefix;
64cbb44143SStephen Hemminger static bool dump_bpf;
65d59fb4d1SStephen Hemminger static bool show_interfaces;
668744f84bSStephen Hemminger static bool print_stats;
67d59fb4d1SStephen Hemminger 
686026bfaeSStephen Hemminger /* capture limit options */
69cbb44143SStephen Hemminger static struct {
70cbb44143SStephen Hemminger 	uint64_t  duration;	/* nanoseconds */
71cbb44143SStephen Hemminger 	unsigned long packets;  /* number of packets in file */
72cbb44143SStephen Hemminger 	size_t size;		/* file size (bytes) */
73cbb44143SStephen Hemminger } stop;
74cbb44143SStephen Hemminger 
75cbb44143SStephen Hemminger /* Running state */
76cbb44143SStephen Hemminger static uint64_t start_time, end_time;
77cbb44143SStephen Hemminger static uint64_t packets_received;
78cbb44143SStephen Hemminger static size_t file_size;
79cbb44143SStephen Hemminger 
806026bfaeSStephen Hemminger /* capture options */
816026bfaeSStephen Hemminger struct capture_options {
826026bfaeSStephen Hemminger 	const char *filter;
836026bfaeSStephen Hemminger 	uint32_t snap_len;
846026bfaeSStephen Hemminger 	bool promisc_mode;
856026bfaeSStephen Hemminger } capture = {
866026bfaeSStephen Hemminger 	.snap_len = RTE_MBUF_DEFAULT_BUF_SIZE,
876026bfaeSStephen Hemminger 	.promisc_mode = true,
886026bfaeSStephen Hemminger };
896026bfaeSStephen Hemminger 
90cbb44143SStephen Hemminger struct interface {
91cbb44143SStephen Hemminger 	TAILQ_ENTRY(interface) next;
92cbb44143SStephen Hemminger 	uint16_t port;
936026bfaeSStephen Hemminger 	struct capture_options opts;
946026bfaeSStephen Hemminger 	struct rte_bpf_prm *bpf_prm;
95cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
96cbb44143SStephen Hemminger 
97cbb44143SStephen Hemminger 	struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];
98d1920ed6SStephen Hemminger 	const char *ifname;
99d1920ed6SStephen Hemminger 	const char *ifdescr;
100cbb44143SStephen Hemminger };
101cbb44143SStephen Hemminger 
102cbb44143SStephen Hemminger TAILQ_HEAD(interface_list, interface);
103cbb44143SStephen Hemminger static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
104cbb44143SStephen Hemminger 
105cbb44143SStephen Hemminger /* Can do either pcap or pcapng format output */
106cbb44143SStephen Hemminger typedef union {
107cbb44143SStephen Hemminger 	rte_pcapng_t  *pcapng;
108cbb44143SStephen Hemminger 	pcap_dumper_t *dumper;
109cbb44143SStephen Hemminger } dumpcap_out_t;
110cbb44143SStephen Hemminger 
111cbb44143SStephen Hemminger static void usage(void)
112cbb44143SStephen Hemminger {
113cbb44143SStephen Hemminger 	printf("Usage: %s [options] ...\n\n", progname);
114cbb44143SStephen Hemminger 	printf("Capture Interface:\n"
115137df50eSStephen Hemminger 	       "  -i <interface>, --interface <interface>\n"
116137df50eSStephen Hemminger 	       "                           name or port index of interface\n"
117cbb44143SStephen Hemminger 	       "  -f <capture filter>      packet filter in libpcap filter syntax\n");
118d1920ed6SStephen Hemminger 	printf("  --ifname <name>          name to use in the capture file\n");
119d1920ed6SStephen Hemminger 	printf("  --ifdescr <description>\n");
120d1920ed6SStephen Hemminger 	printf("                           description to use in the capture file\n");
121cbb44143SStephen Hemminger 	printf("  -s <snaplen>, --snapshot-length <snaplen>\n"
122cbb44143SStephen Hemminger 	       "                           packet snapshot length (def: %u)\n",
123cbb44143SStephen Hemminger 	       RTE_MBUF_DEFAULT_BUF_SIZE);
124cbb44143SStephen Hemminger 	printf("  -p, --no-promiscuous-mode\n"
125cbb44143SStephen Hemminger 	       "                           don't capture in promiscuous mode\n"
126cbb44143SStephen Hemminger 	       "  -D, --list-interfaces    print list of interfaces and exit\n"
127cbb44143SStephen Hemminger 	       "  -d                       print generated BPF code for capture filter\n"
1288744f84bSStephen Hemminger 	       "  -S                       print statistics for each interface once per second\n"
129cbb44143SStephen Hemminger 	       "\n"
130cbb44143SStephen Hemminger 	       "Stop conditions:\n"
131cbb44143SStephen Hemminger 	       "  -c <packet count>        stop after n packets (def: infinite)\n"
132cbb44143SStephen Hemminger 	       "  -a <autostop cond.> ..., --autostop <autostop cond.> ...\n"
133cbb44143SStephen Hemminger 	       "                           duration:NUM - stop after NUM seconds\n"
134cbb44143SStephen Hemminger 	       "                           filesize:NUM - stop this file after NUM kB\n"
135cbb44143SStephen Hemminger 	       "                            packets:NUM - stop after NUM packets\n"
136cbb44143SStephen Hemminger 	       "Output (files):\n"
137cbb44143SStephen Hemminger 	       "  -w <filename>            name of file to save (def: tempfile)\n"
138cbb44143SStephen Hemminger 	       "  -g                       enable group read access on the output file(s)\n"
139cbb44143SStephen Hemminger 	       "  -n                       use pcapng format instead of pcap (default)\n"
140cbb44143SStephen Hemminger 	       "  -P                       use libpcap format instead of pcapng\n"
141cbb44143SStephen Hemminger 	       "  --capture-comment <comment>\n"
142cbb44143SStephen Hemminger 	       "                           add a capture comment to the output file\n"
143b39d52a5SStephen Hemminger 	       "  --temp-dir <directory>   write temporary files to this directory\n"
144b39d52a5SStephen Hemminger 	       "                           (default: /tmp)\n"
145cbb44143SStephen Hemminger 	       "\n"
146cbb44143SStephen Hemminger 	       "Miscellaneous:\n"
147eeb6cad4SStephen Hemminger 	       "  --file-prefix=<prefix>   prefix to use for multi-process\n"
148cbb44143SStephen Hemminger 	       "  -q                       don't report packet capture counts\n"
149cbb44143SStephen Hemminger 	       "  -v, --version            print version information and exit\n"
150cbb44143SStephen Hemminger 	       "  -h, --help               display this help and exit\n"
151cbb44143SStephen Hemminger 	       "\n"
152cbb44143SStephen Hemminger 	       "Use Ctrl-C to stop capturing at any time.\n");
153cbb44143SStephen Hemminger }
154cbb44143SStephen Hemminger 
155cbb44143SStephen Hemminger static const char *version(void)
156cbb44143SStephen Hemminger {
157cbb44143SStephen Hemminger 	static char str[128];
158cbb44143SStephen Hemminger 
159cbb44143SStephen Hemminger 	snprintf(str, sizeof(str),
160cbb44143SStephen Hemminger 		 "%s 1.0 (%s)\n", progname, rte_version());
161cbb44143SStephen Hemminger 	return str;
162cbb44143SStephen Hemminger }
163cbb44143SStephen Hemminger 
164cbb44143SStephen Hemminger /* Parse numeric argument from command line */
165cbb44143SStephen Hemminger static unsigned long get_uint(const char *arg, const char *name,
166cbb44143SStephen Hemminger 			     unsigned int limit)
167cbb44143SStephen Hemminger {
168cbb44143SStephen Hemminger 	unsigned long u;
169cbb44143SStephen Hemminger 	char *endp;
170cbb44143SStephen Hemminger 
171cbb44143SStephen Hemminger 	u = strtoul(arg, &endp, 0);
172cbb44143SStephen Hemminger 	if (*arg == '\0' || *endp != '\0')
173cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
174cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is not a valid number\n",
175cbb44143SStephen Hemminger 			 name, arg);
176cbb44143SStephen Hemminger 	if (limit && u > limit)
177cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
178cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is too large (greater than %u)\n",
179cbb44143SStephen Hemminger 			 name, arg, limit);
180cbb44143SStephen Hemminger 
181cbb44143SStephen Hemminger 	return u;
182cbb44143SStephen Hemminger }
183cbb44143SStephen Hemminger 
184cbb44143SStephen Hemminger /* Set auto stop values */
185cbb44143SStephen Hemminger static void auto_stop(char *opt)
186cbb44143SStephen Hemminger {
187cbb44143SStephen Hemminger 	char *value, *endp;
188cbb44143SStephen Hemminger 
189cbb44143SStephen Hemminger 	value = strchr(opt, ':');
190cbb44143SStephen Hemminger 	if (value == NULL)
191cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
192cbb44143SStephen Hemminger 			 "Missing colon in auto stop parameter\n");
193cbb44143SStephen Hemminger 
194cbb44143SStephen Hemminger 	*value++ = '\0';
195cbb44143SStephen Hemminger 	if (strcmp(opt, "duration") == 0) {
196cbb44143SStephen Hemminger 		double interval = strtod(value, &endp);
197cbb44143SStephen Hemminger 
198cbb44143SStephen Hemminger 		if (*value == '\0' || *endp != '\0' || interval <= 0)
199cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
200cbb44143SStephen Hemminger 				 "Invalid duration \"%s\"\n", value);
201cbb44143SStephen Hemminger 		stop.duration = NSEC_PER_SEC * interval;
202cbb44143SStephen Hemminger 	} else if (strcmp(opt, "filesize") == 0) {
203cbb44143SStephen Hemminger 		stop.size = get_uint(value, "filesize", 0) * 1024;
204cbb44143SStephen Hemminger 	} else if (strcmp(opt, "packets") == 0) {
205cbb44143SStephen Hemminger 		stop.packets = get_uint(value, "packets", 0);
206cbb44143SStephen Hemminger 	} else {
207cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
208cbb44143SStephen Hemminger 			 "Unknown autostop parameter \"%s\"\n", opt);
209cbb44143SStephen Hemminger 	}
210cbb44143SStephen Hemminger }
211cbb44143SStephen Hemminger 
212cbb44143SStephen Hemminger /* Add interface to list of interfaces to capture */
2136026bfaeSStephen Hemminger static struct interface *add_interface(const char *name)
214cbb44143SStephen Hemminger {
215cbb44143SStephen Hemminger 	struct interface *intf;
216cbb44143SStephen Hemminger 
217742be6a4SStephen Hemminger 	if (strlen(name) >= RTE_ETH_NAME_MAX_LEN)
218742be6a4SStephen Hemminger 		rte_exit(EXIT_FAILURE, "invalid name for interface: '%s'\n", name);
219742be6a4SStephen Hemminger 
220cbb44143SStephen Hemminger 	intf = malloc(sizeof(*intf));
221cbb44143SStephen Hemminger 	if (!intf)
222cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "no memory for interface\n");
223cbb44143SStephen Hemminger 
224cbb44143SStephen Hemminger 	memset(intf, 0, sizeof(*intf));
225cbb44143SStephen Hemminger 	rte_strscpy(intf->name, name, sizeof(intf->name));
2266026bfaeSStephen Hemminger 	intf->opts = capture;
2276026bfaeSStephen Hemminger 	intf->port = -1;	/* port set later after EAL init */
228cbb44143SStephen Hemminger 
229cbb44143SStephen Hemminger 	TAILQ_INSERT_TAIL(&interfaces, intf, next);
2306026bfaeSStephen Hemminger 	return intf;
231cbb44143SStephen Hemminger }
232cbb44143SStephen Hemminger 
2336026bfaeSStephen Hemminger /* Name has been set but need to lookup port after eal_init */
2346026bfaeSStephen Hemminger static void find_interfaces(void)
235cbb44143SStephen Hemminger {
2366026bfaeSStephen Hemminger 	struct interface *intf;
237cbb44143SStephen Hemminger 
2386026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
2396026bfaeSStephen Hemminger 		/* if name is valid then just record port */
2406026bfaeSStephen Hemminger 		if (rte_eth_dev_get_port_by_name(intf->name, &intf->port) == 0)
241cbb44143SStephen Hemminger 			continue;
2426026bfaeSStephen Hemminger 
2436026bfaeSStephen Hemminger 		/* maybe got passed port number string as name */
2446026bfaeSStephen Hemminger 		intf->port = get_uint(intf->name, "port_number", UINT16_MAX);
2456026bfaeSStephen Hemminger 		if (rte_eth_dev_get_name_by_port(intf->port, intf->name) < 0)
2466026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
2476026bfaeSStephen Hemminger 				 intf->port);
248cbb44143SStephen Hemminger 	}
249cbb44143SStephen Hemminger }
250cbb44143SStephen Hemminger 
251cbb44143SStephen Hemminger /*
252cbb44143SStephen Hemminger  * Choose interface to capture if no -i option given.
253cbb44143SStephen Hemminger  * Select the first DPDK port, this matches what dumpcap does.
254cbb44143SStephen Hemminger  */
255cbb44143SStephen Hemminger static void set_default_interface(void)
256cbb44143SStephen Hemminger {
2576026bfaeSStephen Hemminger 	struct interface *intf;
258cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
259cbb44143SStephen Hemminger 	uint16_t p;
260cbb44143SStephen Hemminger 
261cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
262cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
263cbb44143SStephen Hemminger 			continue;
2646026bfaeSStephen Hemminger 
2656026bfaeSStephen Hemminger 		intf = add_interface(name);
2666026bfaeSStephen Hemminger 		intf->port = p;
267cbb44143SStephen Hemminger 		return;
268cbb44143SStephen Hemminger 	}
269cbb44143SStephen Hemminger 	rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
270cbb44143SStephen Hemminger }
271cbb44143SStephen Hemminger 
272cbb44143SStephen Hemminger /* Display list of possible interfaces that can be used. */
273d59fb4d1SStephen Hemminger static void dump_interfaces(void)
274cbb44143SStephen Hemminger {
275cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
276cbb44143SStephen Hemminger 	uint16_t p;
277cbb44143SStephen Hemminger 
278cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
279cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
280cbb44143SStephen Hemminger 			continue;
281cbb44143SStephen Hemminger 		printf("%u. %s\n", p, name);
282cbb44143SStephen Hemminger 	}
283d59fb4d1SStephen Hemminger 
284d59fb4d1SStephen Hemminger 	exit(0);
285cbb44143SStephen Hemminger }
286cbb44143SStephen Hemminger 
2876026bfaeSStephen Hemminger static void compile_filters(void)
288cbb44143SStephen Hemminger {
2896026bfaeSStephen Hemminger 	struct interface *intf;
2906026bfaeSStephen Hemminger 
2916026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
2926026bfaeSStephen Hemminger 		struct rte_bpf_prm *bpf_prm;
293cbb44143SStephen Hemminger 		struct bpf_program bf;
294cbb44143SStephen Hemminger 		pcap_t *pcap;
295cbb44143SStephen Hemminger 
2966026bfaeSStephen Hemminger 		pcap = pcap_open_dead(DLT_EN10MB, intf->opts.snap_len);
297cbb44143SStephen Hemminger 		if (!pcap)
298cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "can not open pcap\n");
299cbb44143SStephen Hemminger 
3006026bfaeSStephen Hemminger 		if (pcap_compile(pcap, &bf, intf->opts.filter,
3016026bfaeSStephen Hemminger 				 1, PCAP_NETMASK_UNKNOWN) != 0) {
3026026bfaeSStephen Hemminger 			fprintf(stderr,
3036026bfaeSStephen Hemminger 				"Invalid capture filter \"%s\": for interface '%s'\n",
3046026bfaeSStephen Hemminger 				intf->opts.filter, intf->name);
3056026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE, "\n%s\n",
306cbb44143SStephen Hemminger 				 pcap_geterr(pcap));
3076026bfaeSStephen Hemminger 		}
308cbb44143SStephen Hemminger 
309cbb44143SStephen Hemminger 		bpf_prm = rte_bpf_convert(&bf);
310cbb44143SStephen Hemminger 		if (bpf_prm == NULL)
311cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
3126026bfaeSStephen Hemminger 				 "BPF convert interface '%s'\n%s(%d)\n",
3136026bfaeSStephen Hemminger 				 intf->name,
31465d9b7c6SKonstantin Ananyev 				 rte_strerror(rte_errno), rte_errno);
315cbb44143SStephen Hemminger 
316cbb44143SStephen Hemminger 		if (dump_bpf) {
317cbb44143SStephen Hemminger 			printf("cBPF program (%u insns)\n", bf.bf_len);
318cbb44143SStephen Hemminger 			bpf_dump(&bf, 1);
3196026bfaeSStephen Hemminger 			printf("\neBPF program (%u insns)\n",
3206026bfaeSStephen Hemminger 			       bpf_prm->nb_ins);
321cbb44143SStephen Hemminger 			rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
322cbb44143SStephen Hemminger 			exit(0);
323cbb44143SStephen Hemminger 		}
324cbb44143SStephen Hemminger 
3256026bfaeSStephen Hemminger 		intf->bpf_prm = bpf_prm;
3266026bfaeSStephen Hemminger 
327cbb44143SStephen Hemminger 		/* Don't care about original program any more */
328cbb44143SStephen Hemminger 		pcap_freecode(&bf);
329cbb44143SStephen Hemminger 		pcap_close(pcap);
330cbb44143SStephen Hemminger 	}
3316026bfaeSStephen Hemminger }
332cbb44143SStephen Hemminger 
333cbb44143SStephen Hemminger /*
334cbb44143SStephen Hemminger  * Parse command line options.
335cbb44143SStephen Hemminger  * These are chosen to be similar to dumpcap command.
336cbb44143SStephen Hemminger  */
337cbb44143SStephen Hemminger static void parse_opts(int argc, char **argv)
338cbb44143SStephen Hemminger {
339cbb44143SStephen Hemminger 	static const struct option long_options[] = {
340cbb44143SStephen Hemminger 		{ "autostop",        required_argument, NULL, 'a' },
341cbb44143SStephen Hemminger 		{ "capture-comment", required_argument, NULL, 0 },
342eeb6cad4SStephen Hemminger 		{ "file-prefix",     required_argument, NULL, 0 },
343cbb44143SStephen Hemminger 		{ "help",            no_argument,       NULL, 'h' },
344d1920ed6SStephen Hemminger 		{ "ifdescr",	     required_argument, NULL, 0 },
345d1920ed6SStephen Hemminger 		{ "ifname",	     required_argument, NULL, 0 },
346cbb44143SStephen Hemminger 		{ "interface",       required_argument, NULL, 'i' },
347cbb44143SStephen Hemminger 		{ "list-interfaces", no_argument,       NULL, 'D' },
348cbb44143SStephen Hemminger 		{ "no-promiscuous-mode", no_argument,   NULL, 'p' },
349cbb44143SStephen Hemminger 		{ "output-file",     required_argument, NULL, 'w' },
350cbb44143SStephen Hemminger 		{ "ring-buffer",     required_argument, NULL, 'b' },
351cbb44143SStephen Hemminger 		{ "snapshot-length", required_argument, NULL, 's' },
352b39d52a5SStephen Hemminger 		{ "temp-dir",        required_argument, NULL, 0 },
353cbb44143SStephen Hemminger 		{ "version",         no_argument,       NULL, 'v' },
354cbb44143SStephen Hemminger 		{ NULL },
355cbb44143SStephen Hemminger 	};
356cbb44143SStephen Hemminger 	int option_index, c;
3576026bfaeSStephen Hemminger 	struct interface *last_intf = NULL;
3586026bfaeSStephen Hemminger 	uint32_t len;
359cbb44143SStephen Hemminger 
360cbb44143SStephen Hemminger 	for (;;) {
3618744f84bSStephen Hemminger 		c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqSs:vw:",
362cbb44143SStephen Hemminger 				long_options, &option_index);
363cbb44143SStephen Hemminger 		if (c == -1)
364cbb44143SStephen Hemminger 			break;
365cbb44143SStephen Hemminger 
366cbb44143SStephen Hemminger 		switch (c) {
367d1920ed6SStephen Hemminger 		case 0: {
368d1920ed6SStephen Hemminger 			const char *longopt
369d1920ed6SStephen Hemminger 				= long_options[option_index].name;
370d1920ed6SStephen Hemminger 
371d1920ed6SStephen Hemminger 			if (!strcmp(longopt, "capture-comment")) {
372cbb44143SStephen Hemminger 				capture_comment = optarg;
373d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "file-prefix")) {
374eeb6cad4SStephen Hemminger 				file_prefix = optarg;
375d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "temp-dir")) {
376b39d52a5SStephen Hemminger 				tmp_dir = optarg;
377d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "ifdescr")) {
378d1920ed6SStephen Hemminger 				if (last_intf == NULL)
379d1920ed6SStephen Hemminger 					rte_exit(EXIT_FAILURE,
380d1920ed6SStephen Hemminger 						 "--ifdescr must be specified after a -i option\n");
381d1920ed6SStephen Hemminger 				last_intf->ifdescr = optarg;
382d1920ed6SStephen Hemminger 			} else if (!strcmp(longopt, "ifname")) {
383d1920ed6SStephen Hemminger 				if (last_intf == NULL)
384d1920ed6SStephen Hemminger 					rte_exit(EXIT_FAILURE,
385d1920ed6SStephen Hemminger 						 "--ifname must be specified after a -i option\n");
386d1920ed6SStephen Hemminger 				last_intf->ifname = optarg;
387eeb6cad4SStephen Hemminger 			} else {
388cbb44143SStephen Hemminger 				usage();
389cbb44143SStephen Hemminger 				exit(1);
390cbb44143SStephen Hemminger 			}
391cbb44143SStephen Hemminger 			break;
392d1920ed6SStephen Hemminger 		}
393cbb44143SStephen Hemminger 		case 'a':
394cbb44143SStephen Hemminger 			auto_stop(optarg);
395cbb44143SStephen Hemminger 			break;
396cbb44143SStephen Hemminger 		case 'b':
397cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
398cbb44143SStephen Hemminger 				 "multiple files not implemented\n");
399cbb44143SStephen Hemminger 			break;
400cbb44143SStephen Hemminger 		case 'c':
401cbb44143SStephen Hemminger 			stop.packets = get_uint(optarg, "packet_count", 0);
402cbb44143SStephen Hemminger 			break;
403cbb44143SStephen Hemminger 		case 'd':
404cbb44143SStephen Hemminger 			dump_bpf = true;
405cbb44143SStephen Hemminger 			break;
406cbb44143SStephen Hemminger 		case 'D':
407d59fb4d1SStephen Hemminger 			show_interfaces = true;
408d59fb4d1SStephen Hemminger 			break;
409cbb44143SStephen Hemminger 		case 'f':
4106026bfaeSStephen Hemminger 			if (last_intf == NULL)
4116026bfaeSStephen Hemminger 				capture.filter = optarg;
4126026bfaeSStephen Hemminger 			else
4136026bfaeSStephen Hemminger 				last_intf->opts.filter = optarg;
414cbb44143SStephen Hemminger 			break;
415cbb44143SStephen Hemminger 		case 'g':
416cbb44143SStephen Hemminger 			group_read = true;
417cbb44143SStephen Hemminger 			break;
418cbb44143SStephen Hemminger 		case 'h':
419cbb44143SStephen Hemminger 			printf("%s\n\n", version());
420cbb44143SStephen Hemminger 			usage();
421cbb44143SStephen Hemminger 			exit(0);
422cbb44143SStephen Hemminger 		case 'i':
4236026bfaeSStephen Hemminger 			last_intf = add_interface(optarg);
424cbb44143SStephen Hemminger 			break;
425cbb44143SStephen Hemminger 		case 'n':
426cbb44143SStephen Hemminger 			use_pcapng = true;
427cbb44143SStephen Hemminger 			break;
428cbb44143SStephen Hemminger 		case 'N':
429cbb44143SStephen Hemminger 			ring_size = get_uint(optarg, "packet_limit", 0);
430cbb44143SStephen Hemminger 			break;
431cbb44143SStephen Hemminger 		case 'p':
4326026bfaeSStephen Hemminger 			/* Like dumpcap this option can occur multiple times.
4336026bfaeSStephen Hemminger 			 *
4346026bfaeSStephen Hemminger 			 * If used before the first occurrence of the -i option,
4356026bfaeSStephen Hemminger 			 * no interface will be put into the promiscuous mode.
4366026bfaeSStephen Hemminger 			 * If used after an -i option, the interface specified
4376026bfaeSStephen Hemminger 			 * by the last -i option occurring before this option
4386026bfaeSStephen Hemminger 			 * will not be put into the promiscuous mode.
4396026bfaeSStephen Hemminger 			 */
4406026bfaeSStephen Hemminger 			if (last_intf == NULL)
4416026bfaeSStephen Hemminger 				capture.promisc_mode = false;
4426026bfaeSStephen Hemminger 			else
4436026bfaeSStephen Hemminger 				last_intf->opts.promisc_mode = false;
444cbb44143SStephen Hemminger 			break;
445cbb44143SStephen Hemminger 		case 'P':
446cbb44143SStephen Hemminger 			use_pcapng = false;
447cbb44143SStephen Hemminger 			break;
448cbb44143SStephen Hemminger 		case 'q':
449cbb44143SStephen Hemminger 			quiet = true;
450cbb44143SStephen Hemminger 			break;
451cbb44143SStephen Hemminger 		case 's':
4526026bfaeSStephen Hemminger 			len = get_uint(optarg, "snap_len", 0);
4536026bfaeSStephen Hemminger 			if (last_intf == NULL)
4546026bfaeSStephen Hemminger 				capture.snap_len = len;
4556026bfaeSStephen Hemminger 			else
4566026bfaeSStephen Hemminger 				last_intf->opts.snap_len = len;
457cbb44143SStephen Hemminger 			break;
4588744f84bSStephen Hemminger 		case 'S':
4598744f84bSStephen Hemminger 			print_stats = true;
4608744f84bSStephen Hemminger 			break;
461cbb44143SStephen Hemminger 		case 'w':
462cbb44143SStephen Hemminger 			output_name = optarg;
463cbb44143SStephen Hemminger 			break;
464cbb44143SStephen Hemminger 		case 'v':
465cbb44143SStephen Hemminger 			printf("%s\n", version());
466cbb44143SStephen Hemminger 			exit(0);
467cbb44143SStephen Hemminger 		default:
468cbb44143SStephen Hemminger 			fprintf(stderr, "Invalid option: %s\n",
469cbb44143SStephen Hemminger 				argv[optind - 1]);
470cbb44143SStephen Hemminger 			usage();
471cbb44143SStephen Hemminger 			exit(1);
472cbb44143SStephen Hemminger 		}
473cbb44143SStephen Hemminger 	}
474cbb44143SStephen Hemminger }
475cbb44143SStephen Hemminger 
476cbb44143SStephen Hemminger static void
477cbb44143SStephen Hemminger signal_handler(int sig_num __rte_unused)
478cbb44143SStephen Hemminger {
479cbb44143SStephen Hemminger 	__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
480cbb44143SStephen Hemminger }
481cbb44143SStephen Hemminger 
4828744f84bSStephen Hemminger 
4838744f84bSStephen Hemminger /* Instead of capturing, it tracks interface statistics */
4848744f84bSStephen Hemminger static void statistics_loop(void)
4858744f84bSStephen Hemminger {
4868744f84bSStephen Hemminger 	struct rte_eth_stats stats;
4878744f84bSStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
4888744f84bSStephen Hemminger 	uint16_t p;
4898744f84bSStephen Hemminger 	int r;
4908744f84bSStephen Hemminger 
4918744f84bSStephen Hemminger 	printf("%-15s  %10s  %10s\n",
4928744f84bSStephen Hemminger 	       "Interface", "Received", "Dropped");
4938744f84bSStephen Hemminger 
4948744f84bSStephen Hemminger 	while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {
4958744f84bSStephen Hemminger 		RTE_ETH_FOREACH_DEV(p) {
4968744f84bSStephen Hemminger 			if (rte_eth_dev_get_name_by_port(p, name) < 0)
4978744f84bSStephen Hemminger 				continue;
4988744f84bSStephen Hemminger 
4998744f84bSStephen Hemminger 			r = rte_eth_stats_get(p, &stats);
5008744f84bSStephen Hemminger 			if (r < 0) {
5018744f84bSStephen Hemminger 				fprintf(stderr,
5028744f84bSStephen Hemminger 					"stats_get for port %u failed: %d (%s)\n",
5031bda147fSStephen Hemminger 					p, r, strerror(-r));
5048744f84bSStephen Hemminger 				return;
5058744f84bSStephen Hemminger 			}
5068744f84bSStephen Hemminger 
5078744f84bSStephen Hemminger 			printf("%-15s  %10"PRIu64"  %10"PRIu64"\n",
5088744f84bSStephen Hemminger 			       name, stats.ipackets,
5098744f84bSStephen Hemminger 			       stats.imissed + stats.ierrors + stats.rx_nombuf);
5108744f84bSStephen Hemminger 		}
5118744f84bSStephen Hemminger 		sleep(1);
5128744f84bSStephen Hemminger 	}
5138744f84bSStephen Hemminger }
5148744f84bSStephen Hemminger 
515cbb44143SStephen Hemminger /* Return the time since 1/1/1970 in nanoseconds */
516cbb44143SStephen Hemminger static uint64_t create_timestamp(void)
517cbb44143SStephen Hemminger {
518cbb44143SStephen Hemminger 	struct timespec now;
519cbb44143SStephen Hemminger 
520cbb44143SStephen Hemminger 	clock_gettime(CLOCK_MONOTONIC, &now);
521cbb44143SStephen Hemminger 	return rte_timespec_to_ns(&now);
522cbb44143SStephen Hemminger }
523cbb44143SStephen Hemminger 
524cbb44143SStephen Hemminger static void
525cbb44143SStephen Hemminger cleanup_pdump_resources(void)
526cbb44143SStephen Hemminger {
527cbb44143SStephen Hemminger 	struct interface *intf;
528cbb44143SStephen Hemminger 
529cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
530cbb44143SStephen Hemminger 		rte_pdump_disable(intf->port,
531cbb44143SStephen Hemminger 				  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
5326026bfaeSStephen Hemminger 		if (intf->opts.promisc_mode)
533cbb44143SStephen Hemminger 			rte_eth_promiscuous_disable(intf->port);
534cbb44143SStephen Hemminger 	}
535cbb44143SStephen Hemminger }
536cbb44143SStephen Hemminger 
537cbb44143SStephen Hemminger /* Alarm signal handler, used to check that primary process */
538cbb44143SStephen Hemminger static void
539cbb44143SStephen Hemminger monitor_primary(void *arg __rte_unused)
540cbb44143SStephen Hemminger {
541cbb44143SStephen Hemminger 	if (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED))
542cbb44143SStephen Hemminger 		return;
543cbb44143SStephen Hemminger 
544cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL)) {
545cbb44143SStephen Hemminger 		rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
546cbb44143SStephen Hemminger 	} else {
547cbb44143SStephen Hemminger 		fprintf(stderr,
548cbb44143SStephen Hemminger 			"Primary process is no longer active, exiting...\n");
549cbb44143SStephen Hemminger 		__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
550cbb44143SStephen Hemminger 	}
551cbb44143SStephen Hemminger }
552cbb44143SStephen Hemminger 
553cbb44143SStephen Hemminger /* Setup handler to check when primary exits. */
554cbb44143SStephen Hemminger static void
555cbb44143SStephen Hemminger enable_primary_monitor(void)
556cbb44143SStephen Hemminger {
557cbb44143SStephen Hemminger 	int ret;
558cbb44143SStephen Hemminger 
559cbb44143SStephen Hemminger 	/* Once primary exits, so will pdump. */
560cbb44143SStephen Hemminger 	ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
561cbb44143SStephen Hemminger 	if (ret < 0)
562cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to enable monitor:%d\n", ret);
563cbb44143SStephen Hemminger }
564cbb44143SStephen Hemminger 
565cbb44143SStephen Hemminger static void
566cbb44143SStephen Hemminger disable_primary_monitor(void)
567cbb44143SStephen Hemminger {
568cbb44143SStephen Hemminger 	int ret;
569cbb44143SStephen Hemminger 
570cbb44143SStephen Hemminger 	ret = rte_eal_alarm_cancel(monitor_primary, NULL);
571cbb44143SStephen Hemminger 	if (ret < 0)
572cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to disable monitor:%d\n", ret);
573cbb44143SStephen Hemminger }
574cbb44143SStephen Hemminger 
575cbb44143SStephen Hemminger static void
576cbb44143SStephen Hemminger report_packet_stats(dumpcap_out_t out)
577cbb44143SStephen Hemminger {
578cbb44143SStephen Hemminger 	struct rte_pdump_stats pdump_stats;
579cbb44143SStephen Hemminger 	struct interface *intf;
580cbb44143SStephen Hemminger 	uint64_t ifrecv, ifdrop;
581cbb44143SStephen Hemminger 	double percent;
582cbb44143SStephen Hemminger 
583cbb44143SStephen Hemminger 	fputc('\n', stderr);
584cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
585cbb44143SStephen Hemminger 		if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
586cbb44143SStephen Hemminger 			continue;
587cbb44143SStephen Hemminger 
588cbb44143SStephen Hemminger 		/* do what Wiretap does */
589cbb44143SStephen Hemminger 		ifrecv = pdump_stats.accepted + pdump_stats.filtered;
590cbb44143SStephen Hemminger 		ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
591cbb44143SStephen Hemminger 
592cbb44143SStephen Hemminger 		if (use_pcapng)
593cbb44143SStephen Hemminger 			rte_pcapng_write_stats(out.pcapng, intf->port, NULL,
594cbb44143SStephen Hemminger 					       start_time, end_time,
595cbb44143SStephen Hemminger 					       ifrecv, ifdrop);
596cbb44143SStephen Hemminger 
597cbb44143SStephen Hemminger 		if (ifrecv == 0)
598cbb44143SStephen Hemminger 			percent = 0;
599cbb44143SStephen Hemminger 		else
600cbb44143SStephen Hemminger 			percent = 100. * ifrecv / (ifrecv + ifdrop);
601cbb44143SStephen Hemminger 
602cbb44143SStephen Hemminger 		fprintf(stderr,
603cbb44143SStephen Hemminger 			"Packets received/dropped on interface '%s': "
604cbb44143SStephen Hemminger 			"%"PRIu64 "/%" PRIu64 " (%.1f)\n",
605cbb44143SStephen Hemminger 			intf->name, ifrecv, ifdrop, percent);
606cbb44143SStephen Hemminger 	}
607cbb44143SStephen Hemminger }
608cbb44143SStephen Hemminger 
609cbb44143SStephen Hemminger /*
610cbb44143SStephen Hemminger  * Start DPDK EAL with arguments.
611cbb44143SStephen Hemminger  * Unlike most DPDK programs, this application does not use the
612cbb44143SStephen Hemminger  * typical EAL command line arguments.
613cbb44143SStephen Hemminger  * We don't want to expose all the DPDK internals to the user.
614cbb44143SStephen Hemminger  */
615cbb44143SStephen Hemminger static void dpdk_init(void)
616cbb44143SStephen Hemminger {
617cbb44143SStephen Hemminger 	static const char * const args[] = {
618cbb44143SStephen Hemminger 		"dumpcap", "--proc-type", "secondary",
619cbb44143SStephen Hemminger 		"--log-level", "notice"
620cbb44143SStephen Hemminger 	};
621eeb6cad4SStephen Hemminger 	int eal_argc = RTE_DIM(args);
622cbb44143SStephen Hemminger 	char **eal_argv;
623cbb44143SStephen Hemminger 	unsigned int i;
624cbb44143SStephen Hemminger 
625eeb6cad4SStephen Hemminger 	if (file_prefix != NULL)
626eeb6cad4SStephen Hemminger 		eal_argc += 2;
627eeb6cad4SStephen Hemminger 
628cbb44143SStephen Hemminger 	/* DPDK API requires mutable versions of command line arguments. */
629cbb44143SStephen Hemminger 	eal_argv = calloc(eal_argc + 1, sizeof(char *));
630cbb44143SStephen Hemminger 	if (eal_argv == NULL)
631cbb44143SStephen Hemminger 		rte_panic("No memory\n");
632cbb44143SStephen Hemminger 
633cbb44143SStephen Hemminger 	eal_argv[0] = strdup(progname);
634cbb44143SStephen Hemminger 	for (i = 1; i < RTE_DIM(args); i++)
635cbb44143SStephen Hemminger 		eal_argv[i] = strdup(args[i]);
636cbb44143SStephen Hemminger 
637eeb6cad4SStephen Hemminger 	if (file_prefix != NULL) {
638eeb6cad4SStephen Hemminger 		eal_argv[i++] = strdup("--file-prefix");
639eeb6cad4SStephen Hemminger 		eal_argv[i++] = strdup(file_prefix);
640eeb6cad4SStephen Hemminger 	}
641eeb6cad4SStephen Hemminger 
642cbb44143SStephen Hemminger 	if (rte_eal_init(eal_argc, eal_argv) < 0)
643cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
644cbb44143SStephen Hemminger }
645cbb44143SStephen Hemminger 
646cbb44143SStephen Hemminger /* Create packet ring shared between callbacks and process */
647cbb44143SStephen Hemminger static struct rte_ring *create_ring(void)
648cbb44143SStephen Hemminger {
649cbb44143SStephen Hemminger 	struct rte_ring *ring;
650cbb44143SStephen Hemminger 	size_t size, log2;
651cbb44143SStephen Hemminger 
652cbb44143SStephen Hemminger 	/* Find next power of 2 >= size. */
653cbb44143SStephen Hemminger 	size = ring_size;
654cbb44143SStephen Hemminger 	log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
655cbb44143SStephen Hemminger 	size = 1u << log2;
656cbb44143SStephen Hemminger 
657cbb44143SStephen Hemminger 	if (size != ring_size) {
658cbb44143SStephen Hemminger 		fprintf(stderr, "Ring size %u rounded up to %zu\n",
659cbb44143SStephen Hemminger 			ring_size, size);
660cbb44143SStephen Hemminger 		ring_size = size;
661cbb44143SStephen Hemminger 	}
662cbb44143SStephen Hemminger 
663cbb44143SStephen Hemminger 	ring = rte_ring_lookup(RING_NAME);
664cbb44143SStephen Hemminger 	if (ring == NULL) {
665cbb44143SStephen Hemminger 		ring = rte_ring_create(RING_NAME, ring_size,
666cbb44143SStephen Hemminger 					rte_socket_id(), 0);
667cbb44143SStephen Hemminger 		if (ring == NULL)
668cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
669cbb44143SStephen Hemminger 				 rte_strerror(rte_errno));
670cbb44143SStephen Hemminger 	}
671cbb44143SStephen Hemminger 	return ring;
672cbb44143SStephen Hemminger }
673cbb44143SStephen Hemminger 
674cbb44143SStephen Hemminger static struct rte_mempool *create_mempool(void)
675cbb44143SStephen Hemminger {
6766026bfaeSStephen Hemminger 	const struct interface *intf;
677cbb44143SStephen Hemminger 	static const char pool_name[] = "capture_mbufs";
678cbb44143SStephen Hemminger 	size_t num_mbufs = 2 * ring_size;
679cbb44143SStephen Hemminger 	struct rte_mempool *mp;
6806026bfaeSStephen Hemminger 	uint32_t data_size = 128;
681cbb44143SStephen Hemminger 
682cbb44143SStephen Hemminger 	mp = rte_mempool_lookup(pool_name);
683cbb44143SStephen Hemminger 	if (mp)
684cbb44143SStephen Hemminger 		return mp;
685cbb44143SStephen Hemminger 
6866026bfaeSStephen Hemminger 	/* Common pool so size mbuf for biggest snap length */
6876026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
6886026bfaeSStephen Hemminger 		uint32_t mbuf_size = rte_pcapng_mbuf_size(intf->opts.snap_len);
6896026bfaeSStephen Hemminger 
6906026bfaeSStephen Hemminger 		if (mbuf_size > data_size)
6916026bfaeSStephen Hemminger 			data_size = mbuf_size;
6926026bfaeSStephen Hemminger 	}
6936026bfaeSStephen Hemminger 
694cbb44143SStephen Hemminger 	mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
695cbb44143SStephen Hemminger 					    MBUF_POOL_CACHE_SIZE, 0,
6966026bfaeSStephen Hemminger 					    data_size,
697*27a26d65SStephen Hemminger 					    rte_socket_id(), "ring_mp_mc");
698cbb44143SStephen Hemminger 	if (mp == NULL)
699cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
700cbb44143SStephen Hemminger 			 "Mempool (%s) creation failed: %s\n", pool_name,
701cbb44143SStephen Hemminger 			 rte_strerror(rte_errno));
702cbb44143SStephen Hemminger 
703cbb44143SStephen Hemminger 	return mp;
704cbb44143SStephen Hemminger }
705cbb44143SStephen Hemminger 
706cbb44143SStephen Hemminger /*
707cbb44143SStephen Hemminger  * Get Operating System information.
708cbb44143SStephen Hemminger  * Returns an string allocated via malloc().
709cbb44143SStephen Hemminger  */
710cbb44143SStephen Hemminger static char *get_os_info(void)
711cbb44143SStephen Hemminger {
712cbb44143SStephen Hemminger 	struct utsname uts;
713cbb44143SStephen Hemminger 	char *osname = NULL;
714cbb44143SStephen Hemminger 
715cbb44143SStephen Hemminger 	if (uname(&uts) < 0)
716cbb44143SStephen Hemminger 		return NULL;
717cbb44143SStephen Hemminger 
718cbb44143SStephen Hemminger 	if (asprintf(&osname, "%s %s",
719cbb44143SStephen Hemminger 		     uts.sysname, uts.release) == -1)
720cbb44143SStephen Hemminger 		return NULL;
721cbb44143SStephen Hemminger 
722cbb44143SStephen Hemminger 	return osname;
723cbb44143SStephen Hemminger }
724cbb44143SStephen Hemminger 
725cbb44143SStephen Hemminger static dumpcap_out_t create_output(void)
726cbb44143SStephen Hemminger {
727cbb44143SStephen Hemminger 	dumpcap_out_t ret;
728cbb44143SStephen Hemminger 	static char tmp_path[PATH_MAX];
729cbb44143SStephen Hemminger 	int fd;
730cbb44143SStephen Hemminger 
731cbb44143SStephen Hemminger 	/* If no filename specified make a tempfile name */
732cbb44143SStephen Hemminger 	if (output_name == NULL) {
733cbb44143SStephen Hemminger 		struct interface *intf;
734cbb44143SStephen Hemminger 		struct tm *tm;
735cbb44143SStephen Hemminger 		time_t now;
736cbb44143SStephen Hemminger 		char ts[32];
737cbb44143SStephen Hemminger 
738cbb44143SStephen Hemminger 		intf = TAILQ_FIRST(&interfaces);
739cbb44143SStephen Hemminger 		now = time(NULL);
740cbb44143SStephen Hemminger 		tm = localtime(&now);
741cbb44143SStephen Hemminger 		if (!tm)
742cbb44143SStephen Hemminger 			rte_panic("localtime failed\n");
743cbb44143SStephen Hemminger 
744cbb44143SStephen Hemminger 		strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
745cbb44143SStephen Hemminger 
746cbb44143SStephen Hemminger 		snprintf(tmp_path, sizeof(tmp_path),
747b39d52a5SStephen Hemminger 			 "%s/%s_%u_%s_%s.%s", tmp_dir,
748cbb44143SStephen Hemminger 			 progname, intf->port, intf->name, ts,
749cbb44143SStephen Hemminger 			 use_pcapng ? "pcapng" : "pcap");
750cbb44143SStephen Hemminger 		output_name = tmp_path;
751cbb44143SStephen Hemminger 	}
752cbb44143SStephen Hemminger 
753cbb44143SStephen Hemminger 	if (strcmp(output_name, "-") == 0)
754cbb44143SStephen Hemminger 		fd = STDOUT_FILENO;
755cbb44143SStephen Hemminger 	else {
756cbb44143SStephen Hemminger 		mode_t mode = group_read ? 0640 : 0600;
757cbb44143SStephen Hemminger 
758117e3b64SStephen Hemminger 		fprintf(stderr, "File: %s\n", output_name);
759cbb44143SStephen Hemminger 		fd = open(output_name, O_WRONLY | O_CREAT, mode);
760cbb44143SStephen Hemminger 		if (fd < 0)
761cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
762cbb44143SStephen Hemminger 				 output_name, strerror(errno));
763cbb44143SStephen Hemminger 	}
764cbb44143SStephen Hemminger 
765cbb44143SStephen Hemminger 	if (use_pcapng) {
766d1920ed6SStephen Hemminger 		struct interface *intf;
767cbb44143SStephen Hemminger 		char *os = get_os_info();
768cbb44143SStephen Hemminger 
769cbb44143SStephen Hemminger 		ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
770cbb44143SStephen Hemminger 					   version(), capture_comment);
771cbb44143SStephen Hemminger 		if (ret.pcapng == NULL)
772cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
773cbb44143SStephen Hemminger 				 strerror(rte_errno));
774cbb44143SStephen Hemminger 		free(os);
775d1920ed6SStephen Hemminger 
776d1920ed6SStephen Hemminger 		TAILQ_FOREACH(intf, &interfaces, next) {
777d1920ed6SStephen Hemminger 			rte_pcapng_add_interface(ret.pcapng, intf->port,
778d1920ed6SStephen Hemminger 						 intf->ifname, intf->ifdescr,
779d1920ed6SStephen Hemminger 						 intf->opts.filter);
780d1920ed6SStephen Hemminger 		}
781cbb44143SStephen Hemminger 	} else {
782cbb44143SStephen Hemminger 		pcap_t *pcap;
783cbb44143SStephen Hemminger 
7846026bfaeSStephen Hemminger 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
7856026bfaeSStephen Hemminger 							    capture.snap_len,
786cbb44143SStephen Hemminger 							    PCAP_TSTAMP_PRECISION_NANO);
787cbb44143SStephen Hemminger 		if (pcap == NULL)
788cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
789cbb44143SStephen Hemminger 
790cbb44143SStephen Hemminger 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
791cbb44143SStephen Hemminger 		if (ret.dumper == NULL)
792cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
793cbb44143SStephen Hemminger 				 pcap_geterr(pcap));
794cbb44143SStephen Hemminger 	}
795cbb44143SStephen Hemminger 
796cbb44143SStephen Hemminger 	return ret;
797cbb44143SStephen Hemminger }
798cbb44143SStephen Hemminger 
799cbb44143SStephen Hemminger static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
800cbb44143SStephen Hemminger {
801cbb44143SStephen Hemminger 	struct interface *intf;
8026026bfaeSStephen Hemminger 	unsigned int count = 0;
803cbb44143SStephen Hemminger 	uint32_t flags;
804cbb44143SStephen Hemminger 	int ret;
805cbb44143SStephen Hemminger 
806cbb44143SStephen Hemminger 	flags = RTE_PDUMP_FLAG_RXTX;
807cbb44143SStephen Hemminger 	if (use_pcapng)
808cbb44143SStephen Hemminger 		flags |= RTE_PDUMP_FLAG_PCAPNG;
809cbb44143SStephen Hemminger 
810cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
8116026bfaeSStephen Hemminger 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
8126026bfaeSStephen Hemminger 					   flags, intf->opts.snap_len,
8136026bfaeSStephen Hemminger 					   r, mp, intf->bpf_prm);
8146026bfaeSStephen Hemminger 		if (ret < 0) {
8156026bfaeSStephen Hemminger 			const struct interface *intf2;
8166026bfaeSStephen Hemminger 
8176026bfaeSStephen Hemminger 			/* unwind any previous enables */
8186026bfaeSStephen Hemminger 			TAILQ_FOREACH(intf2, &interfaces, next) {
8196026bfaeSStephen Hemminger 				if (intf == intf2)
8206026bfaeSStephen Hemminger 					break;
8216026bfaeSStephen Hemminger 				rte_pdump_disable(intf2->port,
8226026bfaeSStephen Hemminger 						  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
8236026bfaeSStephen Hemminger 				if (intf2->opts.promisc_mode)
8246026bfaeSStephen Hemminger 					rte_eth_promiscuous_disable(intf2->port);
8256026bfaeSStephen Hemminger 			}
8266026bfaeSStephen Hemminger 			rte_exit(EXIT_FAILURE,
8276026bfaeSStephen Hemminger 				"Packet dump enable on %u:%s failed %s\n",
8286026bfaeSStephen Hemminger 				intf->port, intf->name,
8296026bfaeSStephen Hemminger 				rte_strerror(-ret));
8306026bfaeSStephen Hemminger 		}
8316026bfaeSStephen Hemminger 
8326026bfaeSStephen Hemminger 		if (intf->opts.promisc_mode) {
8336026bfaeSStephen Hemminger 			if (rte_eth_promiscuous_get(intf->port) == 1) {
8346026bfaeSStephen Hemminger 				/* promiscuous already enabled */
8356026bfaeSStephen Hemminger 				intf->opts.promisc_mode = false;
8366026bfaeSStephen Hemminger 			} else {
837499b1cbcSStephen Hemminger 				ret = rte_eth_promiscuous_enable(intf->port);
838499b1cbcSStephen Hemminger 				if (ret != 0)
839499b1cbcSStephen Hemminger 					fprintf(stderr,
840499b1cbcSStephen Hemminger 						"port %u set promiscuous enable failed: %d\n",
841499b1cbcSStephen Hemminger 						intf->port, ret);
8426026bfaeSStephen Hemminger 				intf->opts.promisc_mode = false;
8436026bfaeSStephen Hemminger 			}
8446026bfaeSStephen Hemminger 		}
8456026bfaeSStephen Hemminger 		++count;
846499b1cbcSStephen Hemminger 	}
847cbb44143SStephen Hemminger 
8486026bfaeSStephen Hemminger 	fputs("Capturing on ", stdout);
8496026bfaeSStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
8506026bfaeSStephen Hemminger 		if (intf != TAILQ_FIRST(&interfaces)) {
8516026bfaeSStephen Hemminger 			if (count > 2)
8526026bfaeSStephen Hemminger 				putchar(',');
8536026bfaeSStephen Hemminger 			putchar(' ');
8546026bfaeSStephen Hemminger 			if (TAILQ_NEXT(intf, next) == NULL)
8556026bfaeSStephen Hemminger 				fputs("and ", stdout);
856cbb44143SStephen Hemminger 		}
8576026bfaeSStephen Hemminger 		printf("'%s'", intf->name);
8586026bfaeSStephen Hemminger 	}
8596026bfaeSStephen Hemminger 	putchar('\n');
860cbb44143SStephen Hemminger }
861cbb44143SStephen Hemminger 
862cbb44143SStephen Hemminger /*
863cbb44143SStephen Hemminger  * Show current count of captured packets
864cbb44143SStephen Hemminger  * with backspaces to overwrite last value.
865cbb44143SStephen Hemminger  */
866cbb44143SStephen Hemminger static void show_count(uint64_t count)
867cbb44143SStephen Hemminger {
868cbb44143SStephen Hemminger 	unsigned int i;
869cbb44143SStephen Hemminger 	static unsigned int bt;
870cbb44143SStephen Hemminger 
871cbb44143SStephen Hemminger 	for (i = 0; i < bt; i++)
872cbb44143SStephen Hemminger 		fputc('\b', stderr);
873cbb44143SStephen Hemminger 
874cbb44143SStephen Hemminger 	bt = fprintf(stderr, "%"PRIu64" ", count);
875cbb44143SStephen Hemminger }
876cbb44143SStephen Hemminger 
877cbb44143SStephen Hemminger /* Write multiple packets in older pcap format */
878cbb44143SStephen Hemminger static ssize_t
879cbb44143SStephen Hemminger pcap_write_packets(pcap_dumper_t *dumper,
880cbb44143SStephen Hemminger 		   struct rte_mbuf *pkts[], uint16_t n)
881cbb44143SStephen Hemminger {
8826026bfaeSStephen Hemminger 	uint8_t temp_data[RTE_MBUF_DEFAULT_BUF_SIZE];
883cbb44143SStephen Hemminger 	struct pcap_pkthdr header;
884cbb44143SStephen Hemminger 	uint16_t i;
885cbb44143SStephen Hemminger 	size_t total = 0;
886cbb44143SStephen Hemminger 
887cbb44143SStephen Hemminger 	gettimeofday(&header.ts, NULL);
888cbb44143SStephen Hemminger 
889cbb44143SStephen Hemminger 	for (i = 0; i < n; i++) {
890cbb44143SStephen Hemminger 		struct rte_mbuf *m = pkts[i];
891cbb44143SStephen Hemminger 
892cbb44143SStephen Hemminger 		header.len = rte_pktmbuf_pkt_len(m);
8936026bfaeSStephen Hemminger 		header.caplen = RTE_MIN(header.len, sizeof(temp_data));
894cbb44143SStephen Hemminger 
895cbb44143SStephen Hemminger 		pcap_dump((u_char *)dumper, &header,
896cbb44143SStephen Hemminger 			  rte_pktmbuf_read(m, 0, header.caplen, temp_data));
897cbb44143SStephen Hemminger 
898cbb44143SStephen Hemminger 		total += sizeof(header) + header.len;
899cbb44143SStephen Hemminger 	}
900cbb44143SStephen Hemminger 
901cbb44143SStephen Hemminger 	return total;
902cbb44143SStephen Hemminger }
903cbb44143SStephen Hemminger 
904cbb44143SStephen Hemminger /* Process all packets in ring and dump to capture file */
905cbb44143SStephen Hemminger static int process_ring(dumpcap_out_t out, struct rte_ring *r)
906cbb44143SStephen Hemminger {
907cbb44143SStephen Hemminger 	struct rte_mbuf *pkts[BURST_SIZE];
908cbb44143SStephen Hemminger 	unsigned int avail, n;
909cbb44143SStephen Hemminger 	static unsigned int empty_count;
910cbb44143SStephen Hemminger 	ssize_t written;
911cbb44143SStephen Hemminger 
912cbb44143SStephen Hemminger 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
913cbb44143SStephen Hemminger 				      &avail);
914cbb44143SStephen Hemminger 	if (n == 0) {
915cbb44143SStephen Hemminger 		/* don't consume endless amounts of cpu if idle */
916cbb44143SStephen Hemminger 		if (empty_count < SLEEP_THRESHOLD)
917cbb44143SStephen Hemminger 			++empty_count;
918cbb44143SStephen Hemminger 		else
919cbb44143SStephen Hemminger 			usleep(10);
920cbb44143SStephen Hemminger 		return 0;
921cbb44143SStephen Hemminger 	}
922cbb44143SStephen Hemminger 
923cbb44143SStephen Hemminger 	empty_count = (avail == 0);
924cbb44143SStephen Hemminger 
925cbb44143SStephen Hemminger 	if (use_pcapng)
926cbb44143SStephen Hemminger 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
927cbb44143SStephen Hemminger 	else
928cbb44143SStephen Hemminger 		written = pcap_write_packets(out.dumper, pkts, n);
929cbb44143SStephen Hemminger 
930cbb44143SStephen Hemminger 	rte_pktmbuf_free_bulk(pkts, n);
931cbb44143SStephen Hemminger 
932cbb44143SStephen Hemminger 	if (written < 0)
933cbb44143SStephen Hemminger 		return -1;
934cbb44143SStephen Hemminger 
935cbb44143SStephen Hemminger 	file_size += written;
936cbb44143SStephen Hemminger 	packets_received += n;
937cbb44143SStephen Hemminger 	if (!quiet)
938cbb44143SStephen Hemminger 		show_count(packets_received);
939cbb44143SStephen Hemminger 
940cbb44143SStephen Hemminger 	return 0;
941cbb44143SStephen Hemminger }
942cbb44143SStephen Hemminger 
943cbb44143SStephen Hemminger int main(int argc, char **argv)
944cbb44143SStephen Hemminger {
945cbb44143SStephen Hemminger 	struct rte_ring *r;
946cbb44143SStephen Hemminger 	struct rte_mempool *mp;
947cbb44143SStephen Hemminger 	dumpcap_out_t out;
948117e3b64SStephen Hemminger 	char *p;
949cbb44143SStephen Hemminger 
950117e3b64SStephen Hemminger 	p = strrchr(argv[0], '/');
951117e3b64SStephen Hemminger 	if (p == NULL)
952cbb44143SStephen Hemminger 		progname = argv[0];
953117e3b64SStephen Hemminger 	else
954117e3b64SStephen Hemminger 		progname = p + 1;
955cbb44143SStephen Hemminger 
956cbb44143SStephen Hemminger 	parse_opts(argc, argv);
957a8dde09fSBen Magistro 	dpdk_init();
958cbb44143SStephen Hemminger 
959d59fb4d1SStephen Hemminger 	if (show_interfaces)
960d59fb4d1SStephen Hemminger 		dump_interfaces();
961d59fb4d1SStephen Hemminger 
962d59fb4d1SStephen Hemminger 	if (rte_eth_dev_count_avail() == 0)
963d59fb4d1SStephen Hemminger 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
964d59fb4d1SStephen Hemminger 
965cbb44143SStephen Hemminger 	if (TAILQ_EMPTY(&interfaces))
966cbb44143SStephen Hemminger 		set_default_interface();
9676026bfaeSStephen Hemminger 	else
9686026bfaeSStephen Hemminger 		find_interfaces();
9696026bfaeSStephen Hemminger 
9706026bfaeSStephen Hemminger 	compile_filters();
971cbb44143SStephen Hemminger 
9728744f84bSStephen Hemminger 	signal(SIGINT, signal_handler);
9738744f84bSStephen Hemminger 	signal(SIGPIPE, SIG_IGN);
9748744f84bSStephen Hemminger 
9758744f84bSStephen Hemminger 	enable_primary_monitor();
9768744f84bSStephen Hemminger 
9778744f84bSStephen Hemminger 	if (print_stats) {
9788744f84bSStephen Hemminger 		statistics_loop();
9798744f84bSStephen Hemminger 		exit(0);
9808744f84bSStephen Hemminger 	}
9818744f84bSStephen Hemminger 
982cbb44143SStephen Hemminger 	r = create_ring();
983cbb44143SStephen Hemminger 	mp = create_mempool();
984cbb44143SStephen Hemminger 	out = create_output();
985cbb44143SStephen Hemminger 
986cbb44143SStephen Hemminger 	start_time = create_timestamp();
987cbb44143SStephen Hemminger 	enable_pdump(r, mp);
988cbb44143SStephen Hemminger 
989cbb44143SStephen Hemminger 	if (!quiet) {
990cbb44143SStephen Hemminger 		fprintf(stderr, "Packets captured: ");
991cbb44143SStephen Hemminger 		show_count(0);
992cbb44143SStephen Hemminger 	}
993cbb44143SStephen Hemminger 
994cbb44143SStephen Hemminger 	while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {
995cbb44143SStephen Hemminger 		if (process_ring(out, r) < 0) {
996cbb44143SStephen Hemminger 			fprintf(stderr, "pcapng file write failed; %s\n",
997cbb44143SStephen Hemminger 				strerror(errno));
998cbb44143SStephen Hemminger 			break;
999cbb44143SStephen Hemminger 		}
1000cbb44143SStephen Hemminger 
1001cbb44143SStephen Hemminger 		if (stop.size && file_size >= stop.size)
1002cbb44143SStephen Hemminger 			break;
1003cbb44143SStephen Hemminger 
1004cbb44143SStephen Hemminger 		if (stop.packets && packets_received >= stop.packets)
1005cbb44143SStephen Hemminger 			break;
1006cbb44143SStephen Hemminger 
1007cbb44143SStephen Hemminger 		if (stop.duration != 0 &&
1008cbb44143SStephen Hemminger 		    create_timestamp() - start_time > stop.duration)
1009cbb44143SStephen Hemminger 			break;
1010cbb44143SStephen Hemminger 	}
1011cbb44143SStephen Hemminger 
1012cbb44143SStephen Hemminger 	end_time = create_timestamp();
1013cbb44143SStephen Hemminger 	disable_primary_monitor();
1014cbb44143SStephen Hemminger 
1015cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL))
1016cbb44143SStephen Hemminger 		report_packet_stats(out);
1017cbb44143SStephen Hemminger 
1018cbb44143SStephen Hemminger 	if (use_pcapng)
1019cbb44143SStephen Hemminger 		rte_pcapng_close(out.pcapng);
1020cbb44143SStephen Hemminger 	else
1021cbb44143SStephen Hemminger 		pcap_dump_close(out.dumper);
1022cbb44143SStephen Hemminger 
1023cbb44143SStephen Hemminger 	cleanup_pdump_resources();
10241835ea99SStephen Hemminger 
1025cbb44143SStephen Hemminger 	rte_ring_free(r);
1026cbb44143SStephen Hemminger 	rte_mempool_free(mp);
1027cbb44143SStephen Hemminger 
1028cbb44143SStephen Hemminger 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
1029cbb44143SStephen Hemminger }
1030