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