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