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\n"); 289 290 if (dump_bpf) { 291 printf("cBPF program (%u insns)\n", bf.bf_len); 292 bpf_dump(&bf, 1); 293 printf("\neBPF program (%u insns)\n", bpf_prm->nb_ins); 294 rte_bpf_dump(stdout, bpf_prm->ins, bpf_prm->nb_ins); 295 exit(0); 296 } 297 298 /* Don't care about original program any more */ 299 pcap_freecode(&bf); 300 pcap_close(pcap); 301 } 302 303 /* 304 * Parse command line options. 305 * These are chosen to be similar to dumpcap command. 306 */ 307 static void parse_opts(int argc, char **argv) 308 { 309 static const struct option long_options[] = { 310 { "autostop", required_argument, NULL, 'a' }, 311 { "capture-comment", required_argument, NULL, 0 }, 312 { "help", no_argument, NULL, 'h' }, 313 { "interface", required_argument, NULL, 'i' }, 314 { "list-interfaces", no_argument, NULL, 'D' }, 315 { "no-promiscuous-mode", no_argument, NULL, 'p' }, 316 { "output-file", required_argument, NULL, 'w' }, 317 { "ring-buffer", required_argument, NULL, 'b' }, 318 { "snapshot-length", required_argument, NULL, 's' }, 319 { "version", no_argument, NULL, 'v' }, 320 { NULL }, 321 }; 322 int option_index, c; 323 324 for (;;) { 325 c = getopt_long(argc, argv, "a:b:c:dDf:ghi:nN:pPqs:vw:", 326 long_options, &option_index); 327 if (c == -1) 328 break; 329 330 switch (c) { 331 case 0: 332 switch (option_index) { 333 case 0: 334 capture_comment = optarg; 335 break; 336 default: 337 usage(); 338 exit(1); 339 } 340 break; 341 case 'a': 342 auto_stop(optarg); 343 break; 344 case 'b': 345 rte_exit(EXIT_FAILURE, 346 "multiple files not implemented\n"); 347 break; 348 case 'c': 349 stop.packets = get_uint(optarg, "packet_count", 0); 350 break; 351 case 'd': 352 dump_bpf = true; 353 break; 354 case 'D': 355 show_interfaces(); 356 exit(0); 357 case 'f': 358 filter_str = optarg; 359 break; 360 case 'g': 361 group_read = true; 362 break; 363 case 'h': 364 printf("%s\n\n", version()); 365 usage(); 366 exit(0); 367 case 'i': 368 select_interface(optarg); 369 break; 370 case 'n': 371 use_pcapng = true; 372 break; 373 case 'N': 374 ring_size = get_uint(optarg, "packet_limit", 0); 375 break; 376 case 'p': 377 promiscuous_mode = false; 378 break; 379 case 'P': 380 use_pcapng = false; 381 break; 382 case 'q': 383 quiet = true; 384 break; 385 case 's': 386 snaplen = get_uint(optarg, "snap_len", 0); 387 break; 388 case 'w': 389 output_name = optarg; 390 break; 391 case 'v': 392 printf("%s\n", version()); 393 exit(0); 394 default: 395 fprintf(stderr, "Invalid option: %s\n", 396 argv[optind - 1]); 397 usage(); 398 exit(1); 399 } 400 } 401 } 402 403 static void 404 signal_handler(int sig_num __rte_unused) 405 { 406 __atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED); 407 } 408 409 /* Return the time since 1/1/1970 in nanoseconds */ 410 static uint64_t create_timestamp(void) 411 { 412 struct timespec now; 413 414 clock_gettime(CLOCK_MONOTONIC, &now); 415 return rte_timespec_to_ns(&now); 416 } 417 418 static void 419 cleanup_pdump_resources(void) 420 { 421 struct interface *intf; 422 423 TAILQ_FOREACH(intf, &interfaces, next) { 424 rte_pdump_disable(intf->port, 425 RTE_PDUMP_ALL_QUEUES, RTE_PDUMP_FLAG_RXTX); 426 if (promiscuous_mode) 427 rte_eth_promiscuous_disable(intf->port); 428 } 429 } 430 431 /* Alarm signal handler, used to check that primary process */ 432 static void 433 monitor_primary(void *arg __rte_unused) 434 { 435 if (__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) 436 return; 437 438 if (rte_eal_primary_proc_alive(NULL)) { 439 rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL); 440 } else { 441 fprintf(stderr, 442 "Primary process is no longer active, exiting...\n"); 443 __atomic_store_n(&quit_signal, true, __ATOMIC_RELAXED); 444 } 445 } 446 447 /* Setup handler to check when primary exits. */ 448 static void 449 enable_primary_monitor(void) 450 { 451 int ret; 452 453 /* Once primary exits, so will pdump. */ 454 ret = rte_eal_alarm_set(MONITOR_INTERVAL, monitor_primary, NULL); 455 if (ret < 0) 456 fprintf(stderr, "Fail to enable monitor:%d\n", ret); 457 } 458 459 static void 460 disable_primary_monitor(void) 461 { 462 int ret; 463 464 ret = rte_eal_alarm_cancel(monitor_primary, NULL); 465 if (ret < 0) 466 fprintf(stderr, "Fail to disable monitor:%d\n", ret); 467 } 468 469 static void 470 report_packet_stats(dumpcap_out_t out) 471 { 472 struct rte_pdump_stats pdump_stats; 473 struct interface *intf; 474 uint64_t ifrecv, ifdrop; 475 double percent; 476 477 fputc('\n', stderr); 478 TAILQ_FOREACH(intf, &interfaces, next) { 479 if (rte_pdump_stats(intf->port, &pdump_stats) < 0) 480 continue; 481 482 /* do what Wiretap does */ 483 ifrecv = pdump_stats.accepted + pdump_stats.filtered; 484 ifdrop = pdump_stats.nombuf + pdump_stats.ringfull; 485 486 if (use_pcapng) 487 rte_pcapng_write_stats(out.pcapng, intf->port, NULL, 488 start_time, end_time, 489 ifrecv, ifdrop); 490 491 if (ifrecv == 0) 492 percent = 0; 493 else 494 percent = 100. * ifrecv / (ifrecv + ifdrop); 495 496 fprintf(stderr, 497 "Packets received/dropped on interface '%s': " 498 "%"PRIu64 "/%" PRIu64 " (%.1f)\n", 499 intf->name, ifrecv, ifdrop, percent); 500 } 501 } 502 503 /* 504 * Start DPDK EAL with arguments. 505 * Unlike most DPDK programs, this application does not use the 506 * typical EAL command line arguments. 507 * We don't want to expose all the DPDK internals to the user. 508 */ 509 static void dpdk_init(void) 510 { 511 static const char * const args[] = { 512 "dumpcap", "--proc-type", "secondary", 513 "--log-level", "notice" 514 515 }; 516 const int eal_argc = RTE_DIM(args); 517 char **eal_argv; 518 unsigned int i; 519 520 /* DPDK API requires mutable versions of command line arguments. */ 521 eal_argv = calloc(eal_argc + 1, sizeof(char *)); 522 if (eal_argv == NULL) 523 rte_panic("No memory\n"); 524 525 eal_argv[0] = strdup(progname); 526 for (i = 1; i < RTE_DIM(args); i++) 527 eal_argv[i] = strdup(args[i]); 528 529 if (rte_eal_init(eal_argc, eal_argv) < 0) 530 rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); 531 532 if (rte_eth_dev_count_avail() == 0) 533 rte_exit(EXIT_FAILURE, "No Ethernet ports found\n"); 534 } 535 536 /* Create packet ring shared between callbacks and process */ 537 static struct rte_ring *create_ring(void) 538 { 539 struct rte_ring *ring; 540 size_t size, log2; 541 542 /* Find next power of 2 >= size. */ 543 size = ring_size; 544 log2 = sizeof(size) * 8 - __builtin_clzl(size - 1); 545 size = 1u << log2; 546 547 if (size != ring_size) { 548 fprintf(stderr, "Ring size %u rounded up to %zu\n", 549 ring_size, size); 550 ring_size = size; 551 } 552 553 ring = rte_ring_lookup(RING_NAME); 554 if (ring == NULL) { 555 ring = rte_ring_create(RING_NAME, ring_size, 556 rte_socket_id(), 0); 557 if (ring == NULL) 558 rte_exit(EXIT_FAILURE, "Could not create ring :%s\n", 559 rte_strerror(rte_errno)); 560 } 561 return ring; 562 } 563 564 static struct rte_mempool *create_mempool(void) 565 { 566 static const char pool_name[] = "capture_mbufs"; 567 size_t num_mbufs = 2 * ring_size; 568 struct rte_mempool *mp; 569 570 mp = rte_mempool_lookup(pool_name); 571 if (mp) 572 return mp; 573 574 mp = rte_pktmbuf_pool_create_by_ops(pool_name, num_mbufs, 575 MBUF_POOL_CACHE_SIZE, 0, 576 rte_pcapng_mbuf_size(snaplen), 577 rte_socket_id(), "ring_mp_sc"); 578 if (mp == NULL) 579 rte_exit(EXIT_FAILURE, 580 "Mempool (%s) creation failed: %s\n", pool_name, 581 rte_strerror(rte_errno)); 582 583 return mp; 584 } 585 586 /* 587 * Get Operating System information. 588 * Returns an string allocated via malloc(). 589 */ 590 static char *get_os_info(void) 591 { 592 struct utsname uts; 593 char *osname = NULL; 594 595 if (uname(&uts) < 0) 596 return NULL; 597 598 if (asprintf(&osname, "%s %s", 599 uts.sysname, uts.release) == -1) 600 return NULL; 601 602 return osname; 603 } 604 605 static dumpcap_out_t create_output(void) 606 { 607 dumpcap_out_t ret; 608 static char tmp_path[PATH_MAX]; 609 int fd; 610 611 /* If no filename specified make a tempfile name */ 612 if (output_name == NULL) { 613 struct interface *intf; 614 struct tm *tm; 615 time_t now; 616 char ts[32]; 617 618 intf = TAILQ_FIRST(&interfaces); 619 now = time(NULL); 620 tm = localtime(&now); 621 if (!tm) 622 rte_panic("localtime failed\n"); 623 624 strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", tm); 625 626 snprintf(tmp_path, sizeof(tmp_path), 627 "/tmp/%s_%u_%s_%s.%s", 628 progname, intf->port, intf->name, ts, 629 use_pcapng ? "pcapng" : "pcap"); 630 output_name = tmp_path; 631 } 632 633 if (strcmp(output_name, "-") == 0) 634 fd = STDOUT_FILENO; 635 else { 636 mode_t mode = group_read ? 0640 : 0600; 637 638 fd = open(output_name, O_WRONLY | O_CREAT, mode); 639 if (fd < 0) 640 rte_exit(EXIT_FAILURE, "Can not open \"%s\": %s\n", 641 output_name, strerror(errno)); 642 } 643 644 if (use_pcapng) { 645 char *os = get_os_info(); 646 647 ret.pcapng = rte_pcapng_fdopen(fd, os, NULL, 648 version(), capture_comment); 649 if (ret.pcapng == NULL) 650 rte_exit(EXIT_FAILURE, "pcapng_fdopen failed: %s\n", 651 strerror(rte_errno)); 652 free(os); 653 } else { 654 pcap_t *pcap; 655 656 pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, snaplen, 657 PCAP_TSTAMP_PRECISION_NANO); 658 if (pcap == NULL) 659 rte_exit(EXIT_FAILURE, "pcap_open_dead failed\n"); 660 661 ret.dumper = pcap_dump_fopen(pcap, fdopen(fd, "w")); 662 if (ret.dumper == NULL) 663 rte_exit(EXIT_FAILURE, "pcap_dump_fopen failed: %s\n", 664 pcap_geterr(pcap)); 665 } 666 667 return ret; 668 } 669 670 static void enable_pdump(struct rte_ring *r, struct rte_mempool *mp) 671 { 672 struct interface *intf; 673 uint32_t flags; 674 int ret; 675 676 flags = RTE_PDUMP_FLAG_RXTX; 677 if (use_pcapng) 678 flags |= RTE_PDUMP_FLAG_PCAPNG; 679 680 TAILQ_FOREACH(intf, &interfaces, next) { 681 if (promiscuous_mode) 682 rte_eth_promiscuous_enable(intf->port); 683 684 ret = rte_pdump_enable_bpf(intf->port, RTE_PDUMP_ALL_QUEUES, 685 flags, snaplen, 686 r, mp, bpf_prm); 687 if (ret < 0) 688 rte_exit(EXIT_FAILURE, 689 "Packet dump enable failed: %s\n", 690 rte_strerror(-ret)); 691 } 692 } 693 694 /* 695 * Show current count of captured packets 696 * with backspaces to overwrite last value. 697 */ 698 static void show_count(uint64_t count) 699 { 700 unsigned int i; 701 static unsigned int bt; 702 703 for (i = 0; i < bt; i++) 704 fputc('\b', stderr); 705 706 bt = fprintf(stderr, "%"PRIu64" ", count); 707 } 708 709 /* Write multiple packets in older pcap format */ 710 static ssize_t 711 pcap_write_packets(pcap_dumper_t *dumper, 712 struct rte_mbuf *pkts[], uint16_t n) 713 { 714 uint8_t temp_data[snaplen]; 715 struct pcap_pkthdr header; 716 uint16_t i; 717 size_t total = 0; 718 719 gettimeofday(&header.ts, NULL); 720 721 for (i = 0; i < n; i++) { 722 struct rte_mbuf *m = pkts[i]; 723 724 header.len = rte_pktmbuf_pkt_len(m); 725 header.caplen = RTE_MIN(header.len, snaplen); 726 727 pcap_dump((u_char *)dumper, &header, 728 rte_pktmbuf_read(m, 0, header.caplen, temp_data)); 729 730 total += sizeof(header) + header.len; 731 } 732 733 return total; 734 } 735 736 /* Process all packets in ring and dump to capture file */ 737 static int process_ring(dumpcap_out_t out, struct rte_ring *r) 738 { 739 struct rte_mbuf *pkts[BURST_SIZE]; 740 unsigned int avail, n; 741 static unsigned int empty_count; 742 ssize_t written; 743 744 n = rte_ring_sc_dequeue_burst(r, (void **) pkts, BURST_SIZE, 745 &avail); 746 if (n == 0) { 747 /* don't consume endless amounts of cpu if idle */ 748 if (empty_count < SLEEP_THRESHOLD) 749 ++empty_count; 750 else 751 usleep(10); 752 return 0; 753 } 754 755 empty_count = (avail == 0); 756 757 if (use_pcapng) 758 written = rte_pcapng_write_packets(out.pcapng, pkts, n); 759 else 760 written = pcap_write_packets(out.dumper, pkts, n); 761 762 rte_pktmbuf_free_bulk(pkts, n); 763 764 if (written < 0) 765 return -1; 766 767 file_size += written; 768 packets_received += n; 769 if (!quiet) 770 show_count(packets_received); 771 772 return 0; 773 } 774 775 int main(int argc, char **argv) 776 { 777 struct rte_ring *r; 778 struct rte_mempool *mp; 779 dumpcap_out_t out; 780 781 progname = argv[0]; 782 783 dpdk_init(); 784 parse_opts(argc, argv); 785 786 if (filter_str) 787 compile_filter(); 788 789 if (TAILQ_EMPTY(&interfaces)) 790 set_default_interface(); 791 792 r = create_ring(); 793 mp = create_mempool(); 794 out = create_output(); 795 796 start_time = create_timestamp(); 797 enable_pdump(r, mp); 798 799 signal(SIGINT, signal_handler); 800 signal(SIGPIPE, SIG_IGN); 801 802 enable_primary_monitor(); 803 804 if (!quiet) { 805 fprintf(stderr, "Packets captured: "); 806 show_count(0); 807 } 808 809 while (!__atomic_load_n(&quit_signal, __ATOMIC_RELAXED)) { 810 if (process_ring(out, r) < 0) { 811 fprintf(stderr, "pcapng file write failed; %s\n", 812 strerror(errno)); 813 break; 814 } 815 816 if (stop.size && file_size >= stop.size) 817 break; 818 819 if (stop.packets && packets_received >= stop.packets) 820 break; 821 822 if (stop.duration != 0 && 823 create_timestamp() - start_time > stop.duration) 824 break; 825 } 826 827 end_time = create_timestamp(); 828 disable_primary_monitor(); 829 830 if (rte_eal_primary_proc_alive(NULL)) 831 report_packet_stats(out); 832 833 if (use_pcapng) 834 rte_pcapng_close(out.pcapng); 835 else 836 pcap_dump_close(out.dumper); 837 838 cleanup_pdump_resources(); 839 rte_free(bpf_filter); 840 rte_ring_free(r); 841 rte_mempool_free(mp); 842 843 return rte_eal_cleanup() ? EXIT_FAILURE : 0; 844 } 845