xref: /dpdk/app/dumpcap/main.c (revision cbb44143be74e7dd19853f4f360b51104e02380f)
1*cbb44143SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2*cbb44143SStephen Hemminger  * Copyright(c) 2019-2020 Microsoft Corporation
3*cbb44143SStephen Hemminger  *
4*cbb44143SStephen Hemminger  * DPDK application to dump network traffic
5*cbb44143SStephen Hemminger  * This is designed to look and act like the Wireshark
6*cbb44143SStephen Hemminger  * dumpcap program.
7*cbb44143SStephen Hemminger  */
8*cbb44143SStephen Hemminger 
9*cbb44143SStephen Hemminger #include <errno.h>
10*cbb44143SStephen Hemminger #include <fcntl.h>
11*cbb44143SStephen Hemminger #include <getopt.h>
12*cbb44143SStephen Hemminger #include <inttypes.h>
13*cbb44143SStephen Hemminger #include <limits.h>
14*cbb44143SStephen Hemminger #include <signal.h>
15*cbb44143SStephen Hemminger #include <stdbool.h>
16*cbb44143SStephen Hemminger #include <stdint.h>
17*cbb44143SStephen Hemminger #include <stdio.h>
18*cbb44143SStephen Hemminger #include <stdlib.h>
19*cbb44143SStephen Hemminger #include <string.h>
20*cbb44143SStephen Hemminger #include <sys/queue.h>
21*cbb44143SStephen Hemminger #include <sys/types.h>
22*cbb44143SStephen Hemminger #include <sys/utsname.h>
23*cbb44143SStephen Hemminger #include <time.h>
24*cbb44143SStephen Hemminger #include <unistd.h>
25*cbb44143SStephen Hemminger 
26*cbb44143SStephen Hemminger #include <rte_alarm.h>
27*cbb44143SStephen Hemminger #include <rte_bpf.h>
28*cbb44143SStephen Hemminger #include <rte_config.h>
29*cbb44143SStephen Hemminger #include <rte_debug.h>
30*cbb44143SStephen Hemminger #include <rte_eal.h>
31*cbb44143SStephen Hemminger #include <rte_errno.h>
32*cbb44143SStephen Hemminger #include <rte_ethdev.h>
33*cbb44143SStephen Hemminger #include <rte_lcore.h>
34*cbb44143SStephen Hemminger #include <rte_malloc.h>
35*cbb44143SStephen Hemminger #include <rte_mbuf.h>
36*cbb44143SStephen Hemminger #include <rte_mempool.h>
37*cbb44143SStephen Hemminger #include <rte_pcapng.h>
38*cbb44143SStephen Hemminger #include <rte_pdump.h>
39*cbb44143SStephen Hemminger #include <rte_ring.h>
40*cbb44143SStephen Hemminger #include <rte_string_fns.h>
41*cbb44143SStephen Hemminger #include <rte_time.h>
42*cbb44143SStephen Hemminger #include <rte_version.h>
43*cbb44143SStephen Hemminger 
44*cbb44143SStephen Hemminger #include <pcap/pcap.h>
45*cbb44143SStephen Hemminger #include <pcap/bpf.h>
46*cbb44143SStephen Hemminger 
47*cbb44143SStephen Hemminger #define RING_NAME "capture-ring"
48*cbb44143SStephen Hemminger #define MONITOR_INTERVAL  (500 * 1000)
49*cbb44143SStephen Hemminger #define MBUF_POOL_CACHE_SIZE 32
50*cbb44143SStephen Hemminger #define BURST_SIZE 32
51*cbb44143SStephen Hemminger #define SLEEP_THRESHOLD 1000
52*cbb44143SStephen Hemminger 
53*cbb44143SStephen Hemminger /* command line flags */
54*cbb44143SStephen Hemminger static const char *progname;
55*cbb44143SStephen Hemminger static bool quit_signal;
56*cbb44143SStephen Hemminger static bool group_read;
57*cbb44143SStephen Hemminger static bool quiet;
58*cbb44143SStephen Hemminger static bool promiscuous_mode = true;
59*cbb44143SStephen Hemminger static bool use_pcapng = true;
60*cbb44143SStephen Hemminger static char *output_name;
61*cbb44143SStephen Hemminger static const char *filter_str;
62*cbb44143SStephen Hemminger static unsigned int ring_size = 2048;
63*cbb44143SStephen Hemminger static const char *capture_comment;
64*cbb44143SStephen Hemminger static uint32_t snaplen = RTE_MBUF_DEFAULT_BUF_SIZE;
65*cbb44143SStephen Hemminger static bool dump_bpf;
66*cbb44143SStephen Hemminger static struct {
67*cbb44143SStephen Hemminger 	uint64_t  duration;	/* nanoseconds */
68*cbb44143SStephen Hemminger 	unsigned long packets;  /* number of packets in file */
69*cbb44143SStephen Hemminger 	size_t size;		/* file size (bytes) */
70*cbb44143SStephen Hemminger } stop;
71*cbb44143SStephen Hemminger 
72*cbb44143SStephen Hemminger /* Running state */
73*cbb44143SStephen Hemminger static struct rte_bpf_prm *bpf_prm;
74*cbb44143SStephen Hemminger static uint64_t start_time, end_time;
75*cbb44143SStephen Hemminger static uint64_t packets_received;
76*cbb44143SStephen Hemminger static size_t file_size;
77*cbb44143SStephen Hemminger 
78*cbb44143SStephen Hemminger struct interface {
79*cbb44143SStephen Hemminger 	TAILQ_ENTRY(interface) next;
80*cbb44143SStephen Hemminger 	uint16_t port;
81*cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
82*cbb44143SStephen Hemminger 
83*cbb44143SStephen Hemminger 	struct rte_rxtx_callback *rx_cb[RTE_MAX_QUEUES_PER_PORT];
84*cbb44143SStephen Hemminger };
85*cbb44143SStephen Hemminger 
86*cbb44143SStephen Hemminger TAILQ_HEAD(interface_list, interface);
87*cbb44143SStephen Hemminger static struct interface_list interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
88*cbb44143SStephen Hemminger static struct interface *port2intf[RTE_MAX_ETHPORTS];
89*cbb44143SStephen Hemminger 
90*cbb44143SStephen Hemminger /* Can do either pcap or pcapng format output */
91*cbb44143SStephen Hemminger typedef union {
92*cbb44143SStephen Hemminger 	rte_pcapng_t  *pcapng;
93*cbb44143SStephen Hemminger 	pcap_dumper_t *dumper;
94*cbb44143SStephen Hemminger } dumpcap_out_t;
95*cbb44143SStephen Hemminger 
96*cbb44143SStephen Hemminger static void usage(void)
97*cbb44143SStephen Hemminger {
98*cbb44143SStephen Hemminger 	printf("Usage: %s [options] ...\n\n", progname);
99*cbb44143SStephen Hemminger 	printf("Capture Interface:\n"
100*cbb44143SStephen Hemminger 	       "  -i <interface>           name or port index of interface\n"
101*cbb44143SStephen Hemminger 	       "  -f <capture filter>      packet filter in libpcap filter syntax\n");
102*cbb44143SStephen Hemminger 	printf("  -s <snaplen>, --snapshot-length <snaplen>\n"
103*cbb44143SStephen Hemminger 	       "                           packet snapshot length (def: %u)\n",
104*cbb44143SStephen Hemminger 	       RTE_MBUF_DEFAULT_BUF_SIZE);
105*cbb44143SStephen Hemminger 	printf("  -p, --no-promiscuous-mode\n"
106*cbb44143SStephen Hemminger 	       "                           don't capture in promiscuous mode\n"
107*cbb44143SStephen Hemminger 	       "  -D, --list-interfaces    print list of interfaces and exit\n"
108*cbb44143SStephen Hemminger 	       "  -d                       print generated BPF code for capture filter\n"
109*cbb44143SStephen Hemminger 	       "\n"
110*cbb44143SStephen Hemminger 	       "Stop conditions:\n"
111*cbb44143SStephen Hemminger 	       "  -c <packet count>        stop after n packets (def: infinite)\n"
112*cbb44143SStephen Hemminger 	       "  -a <autostop cond.> ..., --autostop <autostop cond.> ...\n"
113*cbb44143SStephen Hemminger 	       "                           duration:NUM - stop after NUM seconds\n"
114*cbb44143SStephen Hemminger 	       "                           filesize:NUM - stop this file after NUM kB\n"
115*cbb44143SStephen Hemminger 	       "                            packets:NUM - stop after NUM packets\n"
116*cbb44143SStephen Hemminger 	       "Output (files):\n"
117*cbb44143SStephen Hemminger 	       "  -w <filename>            name of file to save (def: tempfile)\n"
118*cbb44143SStephen Hemminger 	       "  -g                       enable group read access on the output file(s)\n"
119*cbb44143SStephen Hemminger 	       "  -n                       use pcapng format instead of pcap (default)\n"
120*cbb44143SStephen Hemminger 	       "  -P                       use libpcap format instead of pcapng\n"
121*cbb44143SStephen Hemminger 	       "  --capture-comment <comment>\n"
122*cbb44143SStephen Hemminger 	       "                           add a capture comment to the output file\n"
123*cbb44143SStephen Hemminger 	       "\n"
124*cbb44143SStephen Hemminger 	       "Miscellaneous:\n"
125*cbb44143SStephen Hemminger 	       "  -q                       don't report packet capture counts\n"
126*cbb44143SStephen Hemminger 	       "  -v, --version            print version information and exit\n"
127*cbb44143SStephen Hemminger 	       "  -h, --help               display this help and exit\n"
128*cbb44143SStephen Hemminger 	       "\n"
129*cbb44143SStephen Hemminger 	       "Use Ctrl-C to stop capturing at any time.\n");
130*cbb44143SStephen Hemminger }
131*cbb44143SStephen Hemminger 
132*cbb44143SStephen Hemminger static const char *version(void)
133*cbb44143SStephen Hemminger {
134*cbb44143SStephen Hemminger 	static char str[128];
135*cbb44143SStephen Hemminger 
136*cbb44143SStephen Hemminger 	snprintf(str, sizeof(str),
137*cbb44143SStephen Hemminger 		 "%s 1.0 (%s)\n", progname, rte_version());
138*cbb44143SStephen Hemminger 	return str;
139*cbb44143SStephen Hemminger }
140*cbb44143SStephen Hemminger 
141*cbb44143SStephen Hemminger /* Parse numeric argument from command line */
142*cbb44143SStephen Hemminger static unsigned long get_uint(const char *arg, const char *name,
143*cbb44143SStephen Hemminger 			     unsigned int limit)
144*cbb44143SStephen Hemminger {
145*cbb44143SStephen Hemminger 	unsigned long u;
146*cbb44143SStephen Hemminger 	char *endp;
147*cbb44143SStephen Hemminger 
148*cbb44143SStephen Hemminger 	u = strtoul(arg, &endp, 0);
149*cbb44143SStephen Hemminger 	if (*arg == '\0' || *endp != '\0')
150*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
151*cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is not a valid number\n",
152*cbb44143SStephen Hemminger 			 name, arg);
153*cbb44143SStephen Hemminger 	if (limit && u > limit)
154*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
155*cbb44143SStephen Hemminger 			 "Specified %s \"%s\" is too large (greater than %u)\n",
156*cbb44143SStephen Hemminger 			 name, arg, limit);
157*cbb44143SStephen Hemminger 
158*cbb44143SStephen Hemminger 	return u;
159*cbb44143SStephen Hemminger }
160*cbb44143SStephen Hemminger 
161*cbb44143SStephen Hemminger /* Set auto stop values */
162*cbb44143SStephen Hemminger static void auto_stop(char *opt)
163*cbb44143SStephen Hemminger {
164*cbb44143SStephen Hemminger 	char *value, *endp;
165*cbb44143SStephen Hemminger 
166*cbb44143SStephen Hemminger 	value = strchr(opt, ':');
167*cbb44143SStephen Hemminger 	if (value == NULL)
168*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
169*cbb44143SStephen Hemminger 			 "Missing colon in auto stop parameter\n");
170*cbb44143SStephen Hemminger 
171*cbb44143SStephen Hemminger 	*value++ = '\0';
172*cbb44143SStephen Hemminger 	if (strcmp(opt, "duration") == 0) {
173*cbb44143SStephen Hemminger 		double interval = strtod(value, &endp);
174*cbb44143SStephen Hemminger 
175*cbb44143SStephen Hemminger 		if (*value == '\0' || *endp != '\0' || interval <= 0)
176*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
177*cbb44143SStephen Hemminger 				 "Invalid duration \"%s\"\n", value);
178*cbb44143SStephen Hemminger 		stop.duration = NSEC_PER_SEC * interval;
179*cbb44143SStephen Hemminger 	} else if (strcmp(opt, "filesize") == 0) {
180*cbb44143SStephen Hemminger 		stop.size = get_uint(value, "filesize", 0) * 1024;
181*cbb44143SStephen Hemminger 	} else if (strcmp(opt, "packets") == 0) {
182*cbb44143SStephen Hemminger 		stop.packets = get_uint(value, "packets", 0);
183*cbb44143SStephen Hemminger 	} else {
184*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
185*cbb44143SStephen Hemminger 			 "Unknown autostop parameter \"%s\"\n", opt);
186*cbb44143SStephen Hemminger 	}
187*cbb44143SStephen Hemminger }
188*cbb44143SStephen Hemminger 
189*cbb44143SStephen Hemminger /* Add interface to list of interfaces to capture */
190*cbb44143SStephen Hemminger static void add_interface(uint16_t port, const char *name)
191*cbb44143SStephen Hemminger {
192*cbb44143SStephen Hemminger 	struct interface *intf;
193*cbb44143SStephen Hemminger 
194*cbb44143SStephen Hemminger 	intf = malloc(sizeof(*intf));
195*cbb44143SStephen Hemminger 	if (!intf)
196*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "no memory for interface\n");
197*cbb44143SStephen Hemminger 
198*cbb44143SStephen Hemminger 	memset(intf, 0, sizeof(*intf));
199*cbb44143SStephen Hemminger 	rte_strscpy(intf->name, name, sizeof(intf->name));
200*cbb44143SStephen Hemminger 
201*cbb44143SStephen Hemminger 	printf("Capturing on '%s'\n", name);
202*cbb44143SStephen Hemminger 
203*cbb44143SStephen Hemminger 	port2intf[port] = intf;
204*cbb44143SStephen Hemminger 	TAILQ_INSERT_TAIL(&interfaces, intf, next);
205*cbb44143SStephen Hemminger }
206*cbb44143SStephen Hemminger 
207*cbb44143SStephen Hemminger /* Select all valid DPDK interfaces */
208*cbb44143SStephen Hemminger static void select_all_interfaces(void)
209*cbb44143SStephen Hemminger {
210*cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
211*cbb44143SStephen Hemminger 	uint16_t p;
212*cbb44143SStephen Hemminger 
213*cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
214*cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
215*cbb44143SStephen Hemminger 			continue;
216*cbb44143SStephen Hemminger 		add_interface(p, name);
217*cbb44143SStephen Hemminger 	}
218*cbb44143SStephen Hemminger }
219*cbb44143SStephen Hemminger 
220*cbb44143SStephen Hemminger /*
221*cbb44143SStephen Hemminger  * Choose interface to capture if no -i option given.
222*cbb44143SStephen Hemminger  * Select the first DPDK port, this matches what dumpcap does.
223*cbb44143SStephen Hemminger  */
224*cbb44143SStephen Hemminger static void set_default_interface(void)
225*cbb44143SStephen Hemminger {
226*cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
227*cbb44143SStephen Hemminger 	uint16_t p;
228*cbb44143SStephen Hemminger 
229*cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
230*cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
231*cbb44143SStephen Hemminger 			continue;
232*cbb44143SStephen Hemminger 		add_interface(p, name);
233*cbb44143SStephen Hemminger 		return;
234*cbb44143SStephen Hemminger 	}
235*cbb44143SStephen Hemminger 	rte_exit(EXIT_FAILURE, "No usable interfaces found\n");
236*cbb44143SStephen Hemminger }
237*cbb44143SStephen Hemminger 
238*cbb44143SStephen Hemminger /* Lookup interface by name or port and add it to the list */
239*cbb44143SStephen Hemminger static void select_interface(const char *arg)
240*cbb44143SStephen Hemminger {
241*cbb44143SStephen Hemminger 	uint16_t port;
242*cbb44143SStephen Hemminger 
243*cbb44143SStephen Hemminger 	if (strcmp(arg, "*"))
244*cbb44143SStephen Hemminger 		select_all_interfaces();
245*cbb44143SStephen Hemminger 	else if (rte_eth_dev_get_port_by_name(arg, &port) == 0)
246*cbb44143SStephen Hemminger 		add_interface(port, arg);
247*cbb44143SStephen Hemminger 	else {
248*cbb44143SStephen Hemminger 		char name[RTE_ETH_NAME_MAX_LEN];
249*cbb44143SStephen Hemminger 
250*cbb44143SStephen Hemminger 		port = get_uint(arg, "port_number", UINT16_MAX);
251*cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(port, name) < 0)
252*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Invalid port number %u\n",
253*cbb44143SStephen Hemminger 				 port);
254*cbb44143SStephen Hemminger 		add_interface(port, name);
255*cbb44143SStephen Hemminger 	}
256*cbb44143SStephen Hemminger }
257*cbb44143SStephen Hemminger 
258*cbb44143SStephen Hemminger /* Display list of possible interfaces that can be used. */
259*cbb44143SStephen Hemminger static void show_interfaces(void)
260*cbb44143SStephen Hemminger {
261*cbb44143SStephen Hemminger 	char name[RTE_ETH_NAME_MAX_LEN];
262*cbb44143SStephen Hemminger 	uint16_t p;
263*cbb44143SStephen Hemminger 
264*cbb44143SStephen Hemminger 	RTE_ETH_FOREACH_DEV(p) {
265*cbb44143SStephen Hemminger 		if (rte_eth_dev_get_name_by_port(p, name) < 0)
266*cbb44143SStephen Hemminger 			continue;
267*cbb44143SStephen Hemminger 		printf("%u. %s\n", p, name);
268*cbb44143SStephen Hemminger 	}
269*cbb44143SStephen Hemminger }
270*cbb44143SStephen Hemminger 
271*cbb44143SStephen Hemminger static void compile_filter(void)
272*cbb44143SStephen Hemminger {
273*cbb44143SStephen Hemminger 	struct bpf_program bf;
274*cbb44143SStephen Hemminger 	pcap_t *pcap;
275*cbb44143SStephen Hemminger 
276*cbb44143SStephen Hemminger 	pcap = pcap_open_dead(DLT_EN10MB, snaplen);
277*cbb44143SStephen Hemminger 	if (!pcap)
278*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "can not open pcap\n");
279*cbb44143SStephen Hemminger 
280*cbb44143SStephen Hemminger 	if (pcap_compile(pcap, &bf, filter_str,
281*cbb44143SStephen Hemminger 			 1, PCAP_NETMASK_UNKNOWN) != 0)
282*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "pcap filter string not valid (%s)\n",
283*cbb44143SStephen Hemminger 			 pcap_geterr(pcap));
284*cbb44143SStephen Hemminger 
285*cbb44143SStephen Hemminger 	bpf_prm = rte_bpf_convert(&bf);
286*cbb44143SStephen Hemminger 	if (bpf_prm == NULL)
287*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
288*cbb44143SStephen Hemminger 			 "bpf convert failed\n");
289*cbb44143SStephen Hemminger 
290*cbb44143SStephen Hemminger 	if (dump_bpf) {
291*cbb44143SStephen Hemminger 		printf("cBPF program (%u insns)\n", bf.bf_len);
292*cbb44143SStephen Hemminger 		bpf_dump(&bf, 1);
293*cbb44143SStephen Hemminger 		printf("\neBPF program (%u insns)\n", bpf_prm->nb_ins);
294*cbb44143SStephen Hemminger 		rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins);
295*cbb44143SStephen Hemminger 		exit(0);
296*cbb44143SStephen Hemminger 	}
297*cbb44143SStephen Hemminger 
298*cbb44143SStephen Hemminger 	/* Don't care about original program any more */
299*cbb44143SStephen Hemminger 	pcap_freecode(&bf);
300*cbb44143SStephen Hemminger 	pcap_close(pcap);
301*cbb44143SStephen Hemminger }
302*cbb44143SStephen Hemminger 
303*cbb44143SStephen Hemminger /*
304*cbb44143SStephen Hemminger  * Parse command line options.
305*cbb44143SStephen Hemminger  * These are chosen to be similar to dumpcap command.
306*cbb44143SStephen Hemminger  */
307*cbb44143SStephen Hemminger static void parse_opts(int argc, char **argv)
308*cbb44143SStephen Hemminger {
309*cbb44143SStephen Hemminger 	static const struct option long_options[] = {
310*cbb44143SStephen Hemminger 		{ "autostop",        required_argument, NULL, 'a' },
311*cbb44143SStephen Hemminger 		{ "capture-comment", required_argument, NULL, 0 },
312*cbb44143SStephen Hemminger 		{ "help",            no_argument,       NULL, 'h' },
313*cbb44143SStephen Hemminger 		{ "interface",       required_argument, NULL, 'i' },
314*cbb44143SStephen Hemminger 		{ "list-interfaces", no_argument,       NULL, 'D' },
315*cbb44143SStephen Hemminger 		{ "no-promiscuous-mode", no_argument,   NULL, 'p' },
316*cbb44143SStephen Hemminger 		{ "output-file",     required_argument, NULL, 'w' },
317*cbb44143SStephen Hemminger 		{ "ring-buffer",     required_argument, NULL, 'b' },
318*cbb44143SStephen Hemminger 		{ "snapshot-length", required_argument, NULL, 's' },
319*cbb44143SStephen Hemminger 		{ "version",         no_argument,       NULL, 'v' },
320*cbb44143SStephen Hemminger 		{ NULL },
321*cbb44143SStephen Hemminger 	};
322*cbb44143SStephen Hemminger 	int option_index, c;
323*cbb44143SStephen Hemminger 
324*cbb44143SStephen Hemminger 	for (;;) {
325*cbb44143SStephen Hemminger 		c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqs:vw:",
326*cbb44143SStephen Hemminger 				long_options, &option_index);
327*cbb44143SStephen Hemminger 		if (c == -1)
328*cbb44143SStephen Hemminger 			break;
329*cbb44143SStephen Hemminger 
330*cbb44143SStephen Hemminger 		switch (c) {
331*cbb44143SStephen Hemminger 		case 0:
332*cbb44143SStephen Hemminger 			switch (option_index) {
333*cbb44143SStephen Hemminger 			case 0:
334*cbb44143SStephen Hemminger 				capture_comment = optarg;
335*cbb44143SStephen Hemminger 				break;
336*cbb44143SStephen Hemminger 			default:
337*cbb44143SStephen Hemminger 				usage();
338*cbb44143SStephen Hemminger 				exit(1);
339*cbb44143SStephen Hemminger 			}
340*cbb44143SStephen Hemminger 			break;
341*cbb44143SStephen Hemminger 		case 'a':
342*cbb44143SStephen Hemminger 			auto_stop(optarg);
343*cbb44143SStephen Hemminger 			break;
344*cbb44143SStephen Hemminger 		case 'b':
345*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
346*cbb44143SStephen Hemminger 				 "multiple files not implemented\n");
347*cbb44143SStephen Hemminger 			break;
348*cbb44143SStephen Hemminger 		case 'c':
349*cbb44143SStephen Hemminger 			stop.packets = get_uint(optarg, "packet_count", 0);
350*cbb44143SStephen Hemminger 			break;
351*cbb44143SStephen Hemminger 		case 'd':
352*cbb44143SStephen Hemminger 			dump_bpf = true;
353*cbb44143SStephen Hemminger 			break;
354*cbb44143SStephen Hemminger 		case 'D':
355*cbb44143SStephen Hemminger 			show_interfaces();
356*cbb44143SStephen Hemminger 			exit(0);
357*cbb44143SStephen Hemminger 		case 'f':
358*cbb44143SStephen Hemminger 			filter_str = optarg;
359*cbb44143SStephen Hemminger 			break;
360*cbb44143SStephen Hemminger 		case 'g':
361*cbb44143SStephen Hemminger 			group_read = true;
362*cbb44143SStephen Hemminger 			break;
363*cbb44143SStephen Hemminger 		case 'h':
364*cbb44143SStephen Hemminger 			printf("%s\n\n", version());
365*cbb44143SStephen Hemminger 			usage();
366*cbb44143SStephen Hemminger 			exit(0);
367*cbb44143SStephen Hemminger 		case 'i':
368*cbb44143SStephen Hemminger 			select_interface(optarg);
369*cbb44143SStephen Hemminger 			break;
370*cbb44143SStephen Hemminger 		case 'n':
371*cbb44143SStephen Hemminger 			use_pcapng = true;
372*cbb44143SStephen Hemminger 			break;
373*cbb44143SStephen Hemminger 		case 'N':
374*cbb44143SStephen Hemminger 			ring_size = get_uint(optarg, "packet_limit", 0);
375*cbb44143SStephen Hemminger 			break;
376*cbb44143SStephen Hemminger 		case 'p':
377*cbb44143SStephen Hemminger 			promiscuous_mode = false;
378*cbb44143SStephen Hemminger 			break;
379*cbb44143SStephen Hemminger 		case 'P':
380*cbb44143SStephen Hemminger 			use_pcapng = false;
381*cbb44143SStephen Hemminger 			break;
382*cbb44143SStephen Hemminger 		case 'q':
383*cbb44143SStephen Hemminger 			quiet = true;
384*cbb44143SStephen Hemminger 			break;
385*cbb44143SStephen Hemminger 		case 's':
386*cbb44143SStephen Hemminger 			snaplen = get_uint(optarg, "snap_len", 0);
387*cbb44143SStephen Hemminger 			break;
388*cbb44143SStephen Hemminger 		case 'w':
389*cbb44143SStephen Hemminger 			output_name = optarg;
390*cbb44143SStephen Hemminger 			break;
391*cbb44143SStephen Hemminger 		case 'v':
392*cbb44143SStephen Hemminger 			printf("%s\n", version());
393*cbb44143SStephen Hemminger 			exit(0);
394*cbb44143SStephen Hemminger 		default:
395*cbb44143SStephen Hemminger 			fprintf(stderr, "Invalid option: %s\n",
396*cbb44143SStephen Hemminger 				argv[optind - 1]);
397*cbb44143SStephen Hemminger 			usage();
398*cbb44143SStephen Hemminger 			exit(1);
399*cbb44143SStephen Hemminger 		}
400*cbb44143SStephen Hemminger 	}
401*cbb44143SStephen Hemminger }
402*cbb44143SStephen Hemminger 
403*cbb44143SStephen Hemminger static void
404*cbb44143SStephen Hemminger signal_handler(int sig_num __rte_unused)
405*cbb44143SStephen Hemminger {
406*cbb44143SStephen Hemminger 	__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
407*cbb44143SStephen Hemminger }
408*cbb44143SStephen Hemminger 
409*cbb44143SStephen Hemminger /* Return the time since 1/1/1970 in nanoseconds */
410*cbb44143SStephen Hemminger static uint64_t create_timestamp(void)
411*cbb44143SStephen Hemminger {
412*cbb44143SStephen Hemminger 	struct timespec now;
413*cbb44143SStephen Hemminger 
414*cbb44143SStephen Hemminger 	clock_gettime(CLOCK_MONOTONIC, &now);
415*cbb44143SStephen Hemminger 	return rte_timespec_to_ns(&now);
416*cbb44143SStephen Hemminger }
417*cbb44143SStephen Hemminger 
418*cbb44143SStephen Hemminger static void
419*cbb44143SStephen Hemminger cleanup_pdump_resources(void)
420*cbb44143SStephen Hemminger {
421*cbb44143SStephen Hemminger 	struct interface *intf;
422*cbb44143SStephen Hemminger 
423*cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
424*cbb44143SStephen Hemminger 		rte_pdump_disable(intf->port,
425*cbb44143SStephen Hemminger 				  RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX);
426*cbb44143SStephen Hemminger 		if (promiscuous_mode)
427*cbb44143SStephen Hemminger 			rte_eth_promiscuous_disable(intf->port);
428*cbb44143SStephen Hemminger 	}
429*cbb44143SStephen Hemminger }
430*cbb44143SStephen Hemminger 
431*cbb44143SStephen Hemminger /* Alarm signal handler, used to check that primary process */
432*cbb44143SStephen Hemminger static void
433*cbb44143SStephen Hemminger monitor_primary(void *arg __rte_unused)
434*cbb44143SStephen Hemminger {
435*cbb44143SStephen Hemminger 	if (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED))
436*cbb44143SStephen Hemminger 		return;
437*cbb44143SStephen Hemminger 
438*cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL)) {
439*cbb44143SStephen Hemminger 		rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
440*cbb44143SStephen Hemminger 	} else {
441*cbb44143SStephen Hemminger 		fprintf(stderr,
442*cbb44143SStephen Hemminger 			"Primary process is no longer active, exiting...\n");
443*cbb44143SStephen Hemminger 		__atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED);
444*cbb44143SStephen Hemminger 	}
445*cbb44143SStephen Hemminger }
446*cbb44143SStephen Hemminger 
447*cbb44143SStephen Hemminger /* Setup handler to check when primary exits. */
448*cbb44143SStephen Hemminger static void
449*cbb44143SStephen Hemminger enable_primary_monitor(void)
450*cbb44143SStephen Hemminger {
451*cbb44143SStephen Hemminger 	int ret;
452*cbb44143SStephen Hemminger 
453*cbb44143SStephen Hemminger 	/* Once primary exits, so will pdump. */
454*cbb44143SStephen Hemminger 	ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL);
455*cbb44143SStephen Hemminger 	if (ret < 0)
456*cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to enable monitor:%d\n", ret);
457*cbb44143SStephen Hemminger }
458*cbb44143SStephen Hemminger 
459*cbb44143SStephen Hemminger static void
460*cbb44143SStephen Hemminger disable_primary_monitor(void)
461*cbb44143SStephen Hemminger {
462*cbb44143SStephen Hemminger 	int ret;
463*cbb44143SStephen Hemminger 
464*cbb44143SStephen Hemminger 	ret = rte_eal_alarm_cancel(monitor_primary, NULL);
465*cbb44143SStephen Hemminger 	if (ret < 0)
466*cbb44143SStephen Hemminger 		fprintf(stderr, "Fail to disable monitor:%d\n", ret);
467*cbb44143SStephen Hemminger }
468*cbb44143SStephen Hemminger 
469*cbb44143SStephen Hemminger static void
470*cbb44143SStephen Hemminger report_packet_stats(dumpcap_out_t out)
471*cbb44143SStephen Hemminger {
472*cbb44143SStephen Hemminger 	struct rte_pdump_stats pdump_stats;
473*cbb44143SStephen Hemminger 	struct interface *intf;
474*cbb44143SStephen Hemminger 	uint64_t ifrecv, ifdrop;
475*cbb44143SStephen Hemminger 	double percent;
476*cbb44143SStephen Hemminger 
477*cbb44143SStephen Hemminger 	fputc('\n', stderr);
478*cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
479*cbb44143SStephen Hemminger 		if (rte_pdump_stats(intf->port, &pdump_stats) < 0)
480*cbb44143SStephen Hemminger 			continue;
481*cbb44143SStephen Hemminger 
482*cbb44143SStephen Hemminger 		/* do what Wiretap does */
483*cbb44143SStephen Hemminger 		ifrecv = pdump_stats.accepted + pdump_stats.filtered;
484*cbb44143SStephen Hemminger 		ifdrop = pdump_stats.nombuf + pdump_stats.ringfull;
485*cbb44143SStephen Hemminger 
486*cbb44143SStephen Hemminger 		if (use_pcapng)
487*cbb44143SStephen Hemminger 			rte_pcapng_write_stats(out.pcapng, intf->port, NULL,
488*cbb44143SStephen Hemminger 					       start_time, end_time,
489*cbb44143SStephen Hemminger 					       ifrecv, ifdrop);
490*cbb44143SStephen Hemminger 
491*cbb44143SStephen Hemminger 		if (ifrecv == 0)
492*cbb44143SStephen Hemminger 			percent = 0;
493*cbb44143SStephen Hemminger 		else
494*cbb44143SStephen Hemminger 			percent = 100. * ifrecv / (ifrecv + ifdrop);
495*cbb44143SStephen Hemminger 
496*cbb44143SStephen Hemminger 		fprintf(stderr,
497*cbb44143SStephen Hemminger 			"Packets received/dropped on interface '%s': "
498*cbb44143SStephen Hemminger 			"%"PRIu64 "/%" PRIu64 " (%.1f)\n",
499*cbb44143SStephen Hemminger 			intf->name, ifrecv, ifdrop, percent);
500*cbb44143SStephen Hemminger 	}
501*cbb44143SStephen Hemminger }
502*cbb44143SStephen Hemminger 
503*cbb44143SStephen Hemminger /*
504*cbb44143SStephen Hemminger  * Start DPDK EAL with arguments.
505*cbb44143SStephen Hemminger  * Unlike most DPDK programs, this application does not use the
506*cbb44143SStephen Hemminger  * typical EAL command line arguments.
507*cbb44143SStephen Hemminger  * We don't want to expose all the DPDK internals to the user.
508*cbb44143SStephen Hemminger  */
509*cbb44143SStephen Hemminger static void dpdk_init(void)
510*cbb44143SStephen Hemminger {
511*cbb44143SStephen Hemminger 	static const char * const args[] = {
512*cbb44143SStephen Hemminger 		"dumpcap", "--proc-type", "secondary",
513*cbb44143SStephen Hemminger 		"--log-level", "notice"
514*cbb44143SStephen Hemminger 
515*cbb44143SStephen Hemminger 	};
516*cbb44143SStephen Hemminger 	const int eal_argc = RTE_DIM(args);
517*cbb44143SStephen Hemminger 	char **eal_argv;
518*cbb44143SStephen Hemminger 	unsigned int i;
519*cbb44143SStephen Hemminger 
520*cbb44143SStephen Hemminger 	/* DPDK API requires mutable versions of command line arguments. */
521*cbb44143SStephen Hemminger 	eal_argv = calloc(eal_argc + 1, sizeof(char *));
522*cbb44143SStephen Hemminger 	if (eal_argv == NULL)
523*cbb44143SStephen Hemminger 		rte_panic("No memory\n");
524*cbb44143SStephen Hemminger 
525*cbb44143SStephen Hemminger 	eal_argv[0] = strdup(progname);
526*cbb44143SStephen Hemminger 	for (i = 1; i < RTE_DIM(args); i++)
527*cbb44143SStephen Hemminger 		eal_argv[i] = strdup(args[i]);
528*cbb44143SStephen Hemminger 
529*cbb44143SStephen Hemminger 	if (rte_eal_init(eal_argc, eal_argv) < 0)
530*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n");
531*cbb44143SStephen Hemminger 
532*cbb44143SStephen Hemminger 	if (rte_eth_dev_count_avail() == 0)
533*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
534*cbb44143SStephen Hemminger }
535*cbb44143SStephen Hemminger 
536*cbb44143SStephen Hemminger /* Create packet ring shared between callbacks and process */
537*cbb44143SStephen Hemminger static struct rte_ring *create_ring(void)
538*cbb44143SStephen Hemminger {
539*cbb44143SStephen Hemminger 	struct rte_ring *ring;
540*cbb44143SStephen Hemminger 	size_t size, log2;
541*cbb44143SStephen Hemminger 
542*cbb44143SStephen Hemminger 	/* Find next power of 2 >= size. */
543*cbb44143SStephen Hemminger 	size = ring_size;
544*cbb44143SStephen Hemminger 	log2 = sizeof(size) * 8 - __builtin_clzl(size - 1);
545*cbb44143SStephen Hemminger 	size = 1u << log2;
546*cbb44143SStephen Hemminger 
547*cbb44143SStephen Hemminger 	if (size != ring_size) {
548*cbb44143SStephen Hemminger 		fprintf(stderr, "Ring size %u rounded up to %zu\n",
549*cbb44143SStephen Hemminger 			ring_size, size);
550*cbb44143SStephen Hemminger 		ring_size = size;
551*cbb44143SStephen Hemminger 	}
552*cbb44143SStephen Hemminger 
553*cbb44143SStephen Hemminger 	ring = rte_ring_lookup(RING_NAME);
554*cbb44143SStephen Hemminger 	if (ring == NULL) {
555*cbb44143SStephen Hemminger 		ring = rte_ring_create(RING_NAME, ring_size,
556*cbb44143SStephen Hemminger 					rte_socket_id(), 0);
557*cbb44143SStephen Hemminger 		if (ring == NULL)
558*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Could not create ring :%s\n",
559*cbb44143SStephen Hemminger 				 rte_strerror(rte_errno));
560*cbb44143SStephen Hemminger 	}
561*cbb44143SStephen Hemminger 	return ring;
562*cbb44143SStephen Hemminger }
563*cbb44143SStephen Hemminger 
564*cbb44143SStephen Hemminger static struct rte_mempool *create_mempool(void)
565*cbb44143SStephen Hemminger {
566*cbb44143SStephen Hemminger 	static const char pool_name[] = "capture_mbufs";
567*cbb44143SStephen Hemminger 	size_t num_mbufs = 2 * ring_size;
568*cbb44143SStephen Hemminger 	struct rte_mempool *mp;
569*cbb44143SStephen Hemminger 
570*cbb44143SStephen Hemminger 	mp = rte_mempool_lookup(pool_name);
571*cbb44143SStephen Hemminger 	if (mp)
572*cbb44143SStephen Hemminger 		return mp;
573*cbb44143SStephen Hemminger 
574*cbb44143SStephen Hemminger 	mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs,
575*cbb44143SStephen Hemminger 					    MBUF_POOL_CACHE_SIZE, 0,
576*cbb44143SStephen Hemminger 					    rte_pcapng_mbuf_size(snaplen),
577*cbb44143SStephen Hemminger 					    rte_socket_id(), "ring_mp_sc");
578*cbb44143SStephen Hemminger 	if (mp == NULL)
579*cbb44143SStephen Hemminger 		rte_exit(EXIT_FAILURE,
580*cbb44143SStephen Hemminger 			 "Mempool (%s) creation failed: %s\n", pool_name,
581*cbb44143SStephen Hemminger 			 rte_strerror(rte_errno));
582*cbb44143SStephen Hemminger 
583*cbb44143SStephen Hemminger 	return mp;
584*cbb44143SStephen Hemminger }
585*cbb44143SStephen Hemminger 
586*cbb44143SStephen Hemminger /*
587*cbb44143SStephen Hemminger  * Get Operating System information.
588*cbb44143SStephen Hemminger  * Returns an string allocated via malloc().
589*cbb44143SStephen Hemminger  */
590*cbb44143SStephen Hemminger static char *get_os_info(void)
591*cbb44143SStephen Hemminger {
592*cbb44143SStephen Hemminger 	struct utsname uts;
593*cbb44143SStephen Hemminger 	char *osname = NULL;
594*cbb44143SStephen Hemminger 
595*cbb44143SStephen Hemminger 	if (uname(&uts) < 0)
596*cbb44143SStephen Hemminger 		return NULL;
597*cbb44143SStephen Hemminger 
598*cbb44143SStephen Hemminger 	if (asprintf(&osname, "%s %s",
599*cbb44143SStephen Hemminger 		     uts.sysname, uts.release) == -1)
600*cbb44143SStephen Hemminger 		return NULL;
601*cbb44143SStephen Hemminger 
602*cbb44143SStephen Hemminger 	return osname;
603*cbb44143SStephen Hemminger }
604*cbb44143SStephen Hemminger 
605*cbb44143SStephen Hemminger static dumpcap_out_t create_output(void)
606*cbb44143SStephen Hemminger {
607*cbb44143SStephen Hemminger 	dumpcap_out_t ret;
608*cbb44143SStephen Hemminger 	static char tmp_path[PATH_MAX];
609*cbb44143SStephen Hemminger 	int fd;
610*cbb44143SStephen Hemminger 
611*cbb44143SStephen Hemminger 	/* If no filename specified make a tempfile name */
612*cbb44143SStephen Hemminger 	if (output_name == NULL) {
613*cbb44143SStephen Hemminger 		struct interface *intf;
614*cbb44143SStephen Hemminger 		struct tm *tm;
615*cbb44143SStephen Hemminger 		time_t now;
616*cbb44143SStephen Hemminger 		char ts[32];
617*cbb44143SStephen Hemminger 
618*cbb44143SStephen Hemminger 		intf = TAILQ_FIRST(&interfaces);
619*cbb44143SStephen Hemminger 		now = time(NULL);
620*cbb44143SStephen Hemminger 		tm = localtime(&now);
621*cbb44143SStephen Hemminger 		if (!tm)
622*cbb44143SStephen Hemminger 			rte_panic("localtime failed\n");
623*cbb44143SStephen Hemminger 
624*cbb44143SStephen Hemminger 		strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm);
625*cbb44143SStephen Hemminger 
626*cbb44143SStephen Hemminger 		snprintf(tmp_path, sizeof(tmp_path),
627*cbb44143SStephen Hemminger 			 "/tmp/%s_%u_%s_%s.%s",
628*cbb44143SStephen Hemminger 			 progname, intf->port, intf->name, ts,
629*cbb44143SStephen Hemminger 			 use_pcapng ? "pcapng" : "pcap");
630*cbb44143SStephen Hemminger 		output_name = tmp_path;
631*cbb44143SStephen Hemminger 	}
632*cbb44143SStephen Hemminger 
633*cbb44143SStephen Hemminger 	if (strcmp(output_name, "-") == 0)
634*cbb44143SStephen Hemminger 		fd = STDOUT_FILENO;
635*cbb44143SStephen Hemminger 	else {
636*cbb44143SStephen Hemminger 		mode_t mode = group_read ? 0640 : 0600;
637*cbb44143SStephen Hemminger 
638*cbb44143SStephen Hemminger 		fd = open(output_name, O_WRONLY | O_CREAT, mode);
639*cbb44143SStephen Hemminger 		if (fd < 0)
640*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n",
641*cbb44143SStephen Hemminger 				 output_name, strerror(errno));
642*cbb44143SStephen Hemminger 	}
643*cbb44143SStephen Hemminger 
644*cbb44143SStephen Hemminger 	if (use_pcapng) {
645*cbb44143SStephen Hemminger 		char *os = get_os_info();
646*cbb44143SStephen Hemminger 
647*cbb44143SStephen Hemminger 		ret.pcapng = rte_pcapng_fdopen(fd, os, NULL,
648*cbb44143SStephen Hemminger 					   version(), capture_comment);
649*cbb44143SStephen Hemminger 		if (ret.pcapng == NULL)
650*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n",
651*cbb44143SStephen Hemminger 				 strerror(rte_errno));
652*cbb44143SStephen Hemminger 		free(os);
653*cbb44143SStephen Hemminger 	} else {
654*cbb44143SStephen Hemminger 		pcap_t *pcap;
655*cbb44143SStephen Hemminger 
656*cbb44143SStephen Hemminger 		pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, snaplen,
657*cbb44143SStephen Hemminger 							    PCAP_TSTAMP_PRECISION_NANO);
658*cbb44143SStephen Hemminger 		if (pcap == NULL)
659*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n");
660*cbb44143SStephen Hemminger 
661*cbb44143SStephen Hemminger 		ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w"));
662*cbb44143SStephen Hemminger 		if (ret.dumper == NULL)
663*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n",
664*cbb44143SStephen Hemminger 				 pcap_geterr(pcap));
665*cbb44143SStephen Hemminger 	}
666*cbb44143SStephen Hemminger 
667*cbb44143SStephen Hemminger 	return ret;
668*cbb44143SStephen Hemminger }
669*cbb44143SStephen Hemminger 
670*cbb44143SStephen Hemminger static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp)
671*cbb44143SStephen Hemminger {
672*cbb44143SStephen Hemminger 	struct interface *intf;
673*cbb44143SStephen Hemminger 	uint32_t flags;
674*cbb44143SStephen Hemminger 	int ret;
675*cbb44143SStephen Hemminger 
676*cbb44143SStephen Hemminger 	flags = RTE_PDUMP_FLAG_RXTX;
677*cbb44143SStephen Hemminger 	if (use_pcapng)
678*cbb44143SStephen Hemminger 		flags |= RTE_PDUMP_FLAG_PCAPNG;
679*cbb44143SStephen Hemminger 
680*cbb44143SStephen Hemminger 	TAILQ_FOREACH(intf, &interfaces, next) {
681*cbb44143SStephen Hemminger 		if (promiscuous_mode)
682*cbb44143SStephen Hemminger 			rte_eth_promiscuous_enable(intf->port);
683*cbb44143SStephen Hemminger 
684*cbb44143SStephen Hemminger 		ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES,
685*cbb44143SStephen Hemminger 					   flags, snaplen,
686*cbb44143SStephen Hemminger 					   r, mp, bpf_prm);
687*cbb44143SStephen Hemminger 		if (ret < 0)
688*cbb44143SStephen Hemminger 			rte_exit(EXIT_FAILURE,
689*cbb44143SStephen Hemminger 				 "Packet dump enable failed: %s\n",
690*cbb44143SStephen Hemminger 				 rte_strerror(-ret));
691*cbb44143SStephen Hemminger 	}
692*cbb44143SStephen Hemminger }
693*cbb44143SStephen Hemminger 
694*cbb44143SStephen Hemminger /*
695*cbb44143SStephen Hemminger  * Show current count of captured packets
696*cbb44143SStephen Hemminger  * with backspaces to overwrite last value.
697*cbb44143SStephen Hemminger  */
698*cbb44143SStephen Hemminger static void show_count(uint64_t count)
699*cbb44143SStephen Hemminger {
700*cbb44143SStephen Hemminger 	unsigned int i;
701*cbb44143SStephen Hemminger 	static unsigned int bt;
702*cbb44143SStephen Hemminger 
703*cbb44143SStephen Hemminger 	for (i = 0; i < bt; i++)
704*cbb44143SStephen Hemminger 		fputc('\b', stderr);
705*cbb44143SStephen Hemminger 
706*cbb44143SStephen Hemminger 	bt = fprintf(stderr, "%"PRIu64" ", count);
707*cbb44143SStephen Hemminger }
708*cbb44143SStephen Hemminger 
709*cbb44143SStephen Hemminger /* Write multiple packets in older pcap format */
710*cbb44143SStephen Hemminger static ssize_t
711*cbb44143SStephen Hemminger pcap_write_packets(pcap_dumper_t *dumper,
712*cbb44143SStephen Hemminger 		   struct rte_mbuf *pkts[], uint16_t n)
713*cbb44143SStephen Hemminger {
714*cbb44143SStephen Hemminger 	uint8_t temp_data[snaplen];
715*cbb44143SStephen Hemminger 	struct pcap_pkthdr header;
716*cbb44143SStephen Hemminger 	uint16_t i;
717*cbb44143SStephen Hemminger 	size_t total = 0;
718*cbb44143SStephen Hemminger 
719*cbb44143SStephen Hemminger 	gettimeofday(&header.ts, NULL);
720*cbb44143SStephen Hemminger 
721*cbb44143SStephen Hemminger 	for (i = 0; i < n; i++) {
722*cbb44143SStephen Hemminger 		struct rte_mbuf *m = pkts[i];
723*cbb44143SStephen Hemminger 
724*cbb44143SStephen Hemminger 		header.len = rte_pktmbuf_pkt_len(m);
725*cbb44143SStephen Hemminger 		header.caplen = RTE_MIN(header.len, snaplen);
726*cbb44143SStephen Hemminger 
727*cbb44143SStephen Hemminger 		pcap_dump((u_char *)dumper, &header,
728*cbb44143SStephen Hemminger 			  rte_pktmbuf_read(m, 0, header.caplen, temp_data));
729*cbb44143SStephen Hemminger 
730*cbb44143SStephen Hemminger 		total += sizeof(header) + header.len;
731*cbb44143SStephen Hemminger 	}
732*cbb44143SStephen Hemminger 
733*cbb44143SStephen Hemminger 	return total;
734*cbb44143SStephen Hemminger }
735*cbb44143SStephen Hemminger 
736*cbb44143SStephen Hemminger /* Process all packets in ring and dump to capture file */
737*cbb44143SStephen Hemminger static int process_ring(dumpcap_out_t out, struct rte_ring *r)
738*cbb44143SStephen Hemminger {
739*cbb44143SStephen Hemminger 	struct rte_mbuf *pkts[BURST_SIZE];
740*cbb44143SStephen Hemminger 	unsigned int avail, n;
741*cbb44143SStephen Hemminger 	static unsigned int empty_count;
742*cbb44143SStephen Hemminger 	ssize_t written;
743*cbb44143SStephen Hemminger 
744*cbb44143SStephen Hemminger 	n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE,
745*cbb44143SStephen Hemminger 				      &avail);
746*cbb44143SStephen Hemminger 	if (n == 0) {
747*cbb44143SStephen Hemminger 		/* don't consume endless amounts of cpu if idle */
748*cbb44143SStephen Hemminger 		if (empty_count < SLEEP_THRESHOLD)
749*cbb44143SStephen Hemminger 			++empty_count;
750*cbb44143SStephen Hemminger 		else
751*cbb44143SStephen Hemminger 			usleep(10);
752*cbb44143SStephen Hemminger 		return 0;
753*cbb44143SStephen Hemminger 	}
754*cbb44143SStephen Hemminger 
755*cbb44143SStephen Hemminger 	empty_count = (avail == 0);
756*cbb44143SStephen Hemminger 
757*cbb44143SStephen Hemminger 	if (use_pcapng)
758*cbb44143SStephen Hemminger 		written = rte_pcapng_write_packets(out.pcapng, pkts, n);
759*cbb44143SStephen Hemminger 	else
760*cbb44143SStephen Hemminger 		written = pcap_write_packets(out.dumper, pkts, n);
761*cbb44143SStephen Hemminger 
762*cbb44143SStephen Hemminger 	rte_pktmbuf_free_bulk(pkts, n);
763*cbb44143SStephen Hemminger 
764*cbb44143SStephen Hemminger 	if (written < 0)
765*cbb44143SStephen Hemminger 		return -1;
766*cbb44143SStephen Hemminger 
767*cbb44143SStephen Hemminger 	file_size += written;
768*cbb44143SStephen Hemminger 	packets_received += n;
769*cbb44143SStephen Hemminger 	if (!quiet)
770*cbb44143SStephen Hemminger 		show_count(packets_received);
771*cbb44143SStephen Hemminger 
772*cbb44143SStephen Hemminger 	return 0;
773*cbb44143SStephen Hemminger }
774*cbb44143SStephen Hemminger 
775*cbb44143SStephen Hemminger int main(int argc, char **argv)
776*cbb44143SStephen Hemminger {
777*cbb44143SStephen Hemminger 	struct rte_ring *r;
778*cbb44143SStephen Hemminger 	struct rte_mempool *mp;
779*cbb44143SStephen Hemminger 	dumpcap_out_t out;
780*cbb44143SStephen Hemminger 
781*cbb44143SStephen Hemminger 	progname = argv[0];
782*cbb44143SStephen Hemminger 
783*cbb44143SStephen Hemminger 	dpdk_init();
784*cbb44143SStephen Hemminger 	parse_opts(argc, argv);
785*cbb44143SStephen Hemminger 
786*cbb44143SStephen Hemminger 	if (filter_str)
787*cbb44143SStephen Hemminger 		compile_filter();
788*cbb44143SStephen Hemminger 
789*cbb44143SStephen Hemminger 	if (TAILQ_EMPTY(&interfaces))
790*cbb44143SStephen Hemminger 		set_default_interface();
791*cbb44143SStephen Hemminger 
792*cbb44143SStephen Hemminger 	r = create_ring();
793*cbb44143SStephen Hemminger 	mp = create_mempool();
794*cbb44143SStephen Hemminger 	out = create_output();
795*cbb44143SStephen Hemminger 
796*cbb44143SStephen Hemminger 	start_time = create_timestamp();
797*cbb44143SStephen Hemminger 	enable_pdump(r, mp);
798*cbb44143SStephen Hemminger 
799*cbb44143SStephen Hemminger 	signal(SIGINT, signal_handler);
800*cbb44143SStephen Hemminger 	signal(SIGPIPE, SIG_IGN);
801*cbb44143SStephen Hemminger 
802*cbb44143SStephen Hemminger 	enable_primary_monitor();
803*cbb44143SStephen Hemminger 
804*cbb44143SStephen Hemminger 	if (!quiet) {
805*cbb44143SStephen Hemminger 		fprintf(stderr, "Packets captured: ");
806*cbb44143SStephen Hemminger 		show_count(0);
807*cbb44143SStephen Hemminger 	}
808*cbb44143SStephen Hemminger 
809*cbb44143SStephen Hemminger 	while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) {
810*cbb44143SStephen Hemminger 		if (process_ring(out, r) < 0) {
811*cbb44143SStephen Hemminger 			fprintf(stderr, "pcapng file write failed; %s\n",
812*cbb44143SStephen Hemminger 				strerror(errno));
813*cbb44143SStephen Hemminger 			break;
814*cbb44143SStephen Hemminger 		}
815*cbb44143SStephen Hemminger 
816*cbb44143SStephen Hemminger 		if (stop.size && file_size >= stop.size)
817*cbb44143SStephen Hemminger 			break;
818*cbb44143SStephen Hemminger 
819*cbb44143SStephen Hemminger 		if (stop.packets && packets_received >= stop.packets)
820*cbb44143SStephen Hemminger 			break;
821*cbb44143SStephen Hemminger 
822*cbb44143SStephen Hemminger 		if (stop.duration != 0 &&
823*cbb44143SStephen Hemminger 		    create_timestamp() - start_time > stop.duration)
824*cbb44143SStephen Hemminger 			break;
825*cbb44143SStephen Hemminger 	}
826*cbb44143SStephen Hemminger 
827*cbb44143SStephen Hemminger 	end_time = create_timestamp();
828*cbb44143SStephen Hemminger 	disable_primary_monitor();
829*cbb44143SStephen Hemminger 
830*cbb44143SStephen Hemminger 	if (rte_eal_primary_proc_alive(NULL))
831*cbb44143SStephen Hemminger 		report_packet_stats(out);
832*cbb44143SStephen Hemminger 
833*cbb44143SStephen Hemminger 	if (use_pcapng)
834*cbb44143SStephen Hemminger 		rte_pcapng_close(out.pcapng);
835*cbb44143SStephen Hemminger 	else
836*cbb44143SStephen Hemminger 		pcap_dump_close(out.dumper);
837*cbb44143SStephen Hemminger 
838*cbb44143SStephen Hemminger 	cleanup_pdump_resources();
839*cbb44143SStephen Hemminger 	rte_free(bpf_filter);
840*cbb44143SStephen Hemminger 	rte_ring_free(r);
841*cbb44143SStephen Hemminger 	rte_mempool_free(mp);
842*cbb44143SStephen Hemminger 
843*cbb44143SStephen Hemminger 	return rte_eal_cleanup() ? EXIT_FAILURE : 0;
844*cbb44143SStephen Hemminger }
845