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