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