diff options
author | Magnus Karlsson <magnus.karlsson@intel.com> | 2019-08-14 03:27:21 -0400 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2019-08-17 17:07:32 -0400 |
commit | 46738f73ea4f94906491cb8399bdeafa5b9cc5ec (patch) | |
tree | 8f556427a6e1995cdce6e2737349ac053b07527d | |
parent | a4500432c2587cb2ae7554537886a4516ff2e7aa (diff) |
samples/bpf: add use of need_wakeup flag in xdpsock
This commit adds using the need_wakeup flag to the xdpsock sample
application. It is turned on by default as we think it is a feature
that seems to always produce a performance benefit, if the application
has been written taking advantage of it. It can be turned off in the
sample app by using the '-m' command line option.
The txpush and l2fwd sub applications have also been updated to
support poll() with multiple sockets.
Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
Acked-by: Jonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r-- | samples/bpf/xdpsock_user.c | 192 |
1 files changed, 120 insertions, 72 deletions
diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index 93eaaf7239b2..da84c760c094 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c | |||
@@ -67,8 +67,10 @@ static int opt_ifindex; | |||
67 | static int opt_queue; | 67 | static int opt_queue; |
68 | static int opt_poll; | 68 | static int opt_poll; |
69 | static int opt_interval = 1; | 69 | static int opt_interval = 1; |
70 | static u32 opt_xdp_bind_flags; | 70 | static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP; |
71 | static int opt_xsk_frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; | 71 | static int opt_xsk_frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; |
72 | static int opt_timeout = 1000; | ||
73 | static bool opt_need_wakeup = true; | ||
72 | static __u32 prog_id; | 74 | static __u32 prog_id; |
73 | 75 | ||
74 | struct xsk_umem_info { | 76 | struct xsk_umem_info { |
@@ -352,6 +354,7 @@ static struct option long_options[] = { | |||
352 | {"zero-copy", no_argument, 0, 'z'}, | 354 | {"zero-copy", no_argument, 0, 'z'}, |
353 | {"copy", no_argument, 0, 'c'}, | 355 | {"copy", no_argument, 0, 'c'}, |
354 | {"frame-size", required_argument, 0, 'f'}, | 356 | {"frame-size", required_argument, 0, 'f'}, |
357 | {"no-need-wakeup", no_argument, 0, 'm'}, | ||
355 | {0, 0, 0, 0} | 358 | {0, 0, 0, 0} |
356 | }; | 359 | }; |
357 | 360 | ||
@@ -372,6 +375,7 @@ static void usage(const char *prog) | |||
372 | " -z, --zero-copy Force zero-copy mode.\n" | 375 | " -z, --zero-copy Force zero-copy mode.\n" |
373 | " -c, --copy Force copy mode.\n" | 376 | " -c, --copy Force copy mode.\n" |
374 | " -f, --frame-size=n Set the frame size (must be a power of two, default is %d).\n" | 377 | " -f, --frame-size=n Set the frame size (must be a power of two, default is %d).\n" |
378 | " -m, --no-need-wakeup Turn off use of driver need wakeup flag.\n" | ||
375 | "\n"; | 379 | "\n"; |
376 | fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE); | 380 | fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE); |
377 | exit(EXIT_FAILURE); | 381 | exit(EXIT_FAILURE); |
@@ -384,8 +388,9 @@ static void parse_command_line(int argc, char **argv) | |||
384 | opterr = 0; | 388 | opterr = 0; |
385 | 389 | ||
386 | for (;;) { | 390 | for (;;) { |
387 | c = getopt_long(argc, argv, "Frtli:q:psSNn:czf:", long_options, | 391 | |
388 | &option_index); | 392 | c = getopt_long(argc, argv, "Frtli:q:psSNn:czf:m", |
393 | long_options, &option_index); | ||
389 | if (c == -1) | 394 | if (c == -1) |
390 | break; | 395 | break; |
391 | 396 | ||
@@ -429,6 +434,9 @@ static void parse_command_line(int argc, char **argv) | |||
429 | break; | 434 | break; |
430 | case 'f': | 435 | case 'f': |
431 | opt_xsk_frame_size = atoi(optarg); | 436 | opt_xsk_frame_size = atoi(optarg); |
437 | case 'm': | ||
438 | opt_need_wakeup = false; | ||
439 | opt_xdp_bind_flags &= ~XDP_USE_NEED_WAKEUP; | ||
432 | break; | 440 | break; |
433 | default: | 441 | default: |
434 | usage(basename(argv[0])); | 442 | usage(basename(argv[0])); |
@@ -459,7 +467,8 @@ static void kick_tx(struct xsk_socket_info *xsk) | |||
459 | exit_with_error(errno); | 467 | exit_with_error(errno); |
460 | } | 468 | } |
461 | 469 | ||
462 | static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk) | 470 | static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk, |
471 | struct pollfd *fds) | ||
463 | { | 472 | { |
464 | u32 idx_cq = 0, idx_fq = 0; | 473 | u32 idx_cq = 0, idx_fq = 0; |
465 | unsigned int rcvd; | 474 | unsigned int rcvd; |
@@ -468,7 +477,9 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk) | |||
468 | if (!xsk->outstanding_tx) | 477 | if (!xsk->outstanding_tx) |
469 | return; | 478 | return; |
470 | 479 | ||
471 | kick_tx(xsk); | 480 | if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup(&xsk->tx)) |
481 | kick_tx(xsk); | ||
482 | |||
472 | ndescs = (xsk->outstanding_tx > BATCH_SIZE) ? BATCH_SIZE : | 483 | ndescs = (xsk->outstanding_tx > BATCH_SIZE) ? BATCH_SIZE : |
473 | xsk->outstanding_tx; | 484 | xsk->outstanding_tx; |
474 | 485 | ||
@@ -482,6 +493,8 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk) | |||
482 | while (ret != rcvd) { | 493 | while (ret != rcvd) { |
483 | if (ret < 0) | 494 | if (ret < 0) |
484 | exit_with_error(-ret); | 495 | exit_with_error(-ret); |
496 | if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) | ||
497 | ret = poll(fds, num_socks, opt_timeout); | ||
485 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, | 498 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, |
486 | &idx_fq); | 499 | &idx_fq); |
487 | } | 500 | } |
@@ -505,7 +518,8 @@ static inline void complete_tx_only(struct xsk_socket_info *xsk) | |||
505 | if (!xsk->outstanding_tx) | 518 | if (!xsk->outstanding_tx) |
506 | return; | 519 | return; |
507 | 520 | ||
508 | kick_tx(xsk); | 521 | if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup(&xsk->tx)) |
522 | kick_tx(xsk); | ||
509 | 523 | ||
510 | rcvd = xsk_ring_cons__peek(&xsk->umem->cq, BATCH_SIZE, &idx); | 524 | rcvd = xsk_ring_cons__peek(&xsk->umem->cq, BATCH_SIZE, &idx); |
511 | if (rcvd > 0) { | 525 | if (rcvd > 0) { |
@@ -515,20 +529,25 @@ static inline void complete_tx_only(struct xsk_socket_info *xsk) | |||
515 | } | 529 | } |
516 | } | 530 | } |
517 | 531 | ||
518 | static void rx_drop(struct xsk_socket_info *xsk) | 532 | static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds) |
519 | { | 533 | { |
520 | unsigned int rcvd, i; | 534 | unsigned int rcvd, i; |
521 | u32 idx_rx = 0, idx_fq = 0; | 535 | u32 idx_rx = 0, idx_fq = 0; |
522 | int ret; | 536 | int ret; |
523 | 537 | ||
524 | rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx); | 538 | rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx); |
525 | if (!rcvd) | 539 | if (!rcvd) { |
540 | if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) | ||
541 | ret = poll(fds, num_socks, opt_timeout); | ||
526 | return; | 542 | return; |
543 | } | ||
527 | 544 | ||
528 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq); | 545 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq); |
529 | while (ret != rcvd) { | 546 | while (ret != rcvd) { |
530 | if (ret < 0) | 547 | if (ret < 0) |
531 | exit_with_error(-ret); | 548 | exit_with_error(-ret); |
549 | if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) | ||
550 | ret = poll(fds, num_socks, opt_timeout); | ||
532 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq); | 551 | ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq); |
533 | } | 552 | } |
534 | 553 | ||
@@ -549,42 +568,65 @@ static void rx_drop(struct xsk_socket_info *xsk) | |||
549 | static void rx_drop_all(void) | 568 | static void rx_drop_all(void) |
550 | { | 569 | { |
551 | struct pollfd fds[MAX_SOCKS + 1]; | 570 | struct pollfd fds[MAX_SOCKS + 1]; |
552 | int i, ret, timeout, nfds = 1; | 571 | int i, ret; |
553 | 572 | ||
554 | memset(fds, 0, sizeof(fds)); | 573 | memset(fds, 0, sizeof(fds)); |
555 | 574 | ||
556 | for (i = 0; i < num_socks; i++) { | 575 | for (i = 0; i < num_socks; i++) { |
557 | fds[i].fd = xsk_socket__fd(xsks[i]->xsk); | 576 | fds[i].fd = xsk_socket__fd(xsks[i]->xsk); |
558 | fds[i].events = POLLIN; | 577 | fds[i].events = POLLIN; |
559 | timeout = 1000; /* 1sn */ | ||
560 | } | 578 | } |
561 | 579 | ||
562 | for (;;) { | 580 | for (;;) { |
563 | if (opt_poll) { | 581 | if (opt_poll) { |
564 | ret = poll(fds, nfds, timeout); | 582 | ret = poll(fds, num_socks, opt_timeout); |
565 | if (ret <= 0) | 583 | if (ret <= 0) |
566 | continue; | 584 | continue; |
567 | } | 585 | } |
568 | 586 | ||
569 | for (i = 0; i < num_socks; i++) | 587 | for (i = 0; i < num_socks; i++) |
570 | rx_drop(xsks[i]); | 588 | rx_drop(xsks[i], fds); |
589 | } | ||
590 | } | ||
591 | |||
592 | static void tx_only(struct xsk_socket_info *xsk, u32 frame_nb) | ||
593 | { | ||
594 | u32 idx; | ||
595 | |||
596 | if (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) == BATCH_SIZE) { | ||
597 | unsigned int i; | ||
598 | |||
599 | for (i = 0; i < BATCH_SIZE; i++) { | ||
600 | xsk_ring_prod__tx_desc(&xsk->tx, idx + i)->addr = | ||
601 | (frame_nb + i) << XSK_UMEM__DEFAULT_FRAME_SHIFT; | ||
602 | xsk_ring_prod__tx_desc(&xsk->tx, idx + i)->len = | ||
603 | sizeof(pkt_data) - 1; | ||
604 | } | ||
605 | |||
606 | xsk_ring_prod__submit(&xsk->tx, BATCH_SIZE); | ||
607 | xsk->outstanding_tx += BATCH_SIZE; | ||
608 | frame_nb += BATCH_SIZE; | ||
609 | frame_nb %= NUM_FRAMES; | ||
571 | } | 610 | } |
611 | |||
612 | complete_tx_only(xsk); | ||
572 | } | 613 | } |
573 | 614 | ||
574 | static void tx_only(struct xsk_socket_info *xsk) | 615 | static void tx_only_all(void) |
575 | { | 616 | { |
576 | int timeout, ret, nfds = 1; | 617 | struct pollfd fds[MAX_SOCKS]; |
577 | struct pollfd fds[nfds + 1]; | 618 | u32 frame_nb[MAX_SOCKS] = {}; |
578 | u32 idx, frame_nb = 0; | 619 | int i, ret; |
579 | 620 | ||
580 | memset(fds, 0, sizeof(fds)); | 621 | memset(fds, 0, sizeof(fds)); |
581 | fds[0].fd = xsk_socket__fd(xsk->xsk); | 622 | for (i = 0; i < num_socks; i++) { |
582 | fds[0].events = POLLOUT; | 623 | fds[0].fd = xsk_socket__fd(xsks[i]->xsk); |
583 | timeout = 1000; /* 1sn */ | 624 | fds[0].events = POLLOUT; |
625 | } | ||
584 | 626 | ||
585 | for (;;) { | 627 | for (;;) { |
586 | if (opt_poll) { | 628 | if (opt_poll) { |
587 | ret = poll(fds, nfds, timeout); | 629 | ret = poll(fds, num_socks, opt_timeout); |
588 | if (ret <= 0) | 630 | if (ret <= 0) |
589 | continue; | 631 | continue; |
590 | 632 | ||
@@ -592,69 +634,75 @@ static void tx_only(struct xsk_socket_info *xsk) | |||
592 | continue; | 634 | continue; |
593 | } | 635 | } |
594 | 636 | ||
595 | if (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) == | 637 | for (i = 0; i < num_socks; i++) |
596 | BATCH_SIZE) { | 638 | tx_only(xsks[i], frame_nb[i]); |
597 | unsigned int i; | ||
598 | |||
599 | for (i = 0; i < BATCH_SIZE; i++) { | ||
600 | xsk_ring_prod__tx_desc(&xsk->tx, idx + i)->addr | ||
601 | = (frame_nb + i) * opt_xsk_frame_size; | ||
602 | xsk_ring_prod__tx_desc(&xsk->tx, idx + i)->len = | ||
603 | sizeof(pkt_data) - 1; | ||
604 | } | ||
605 | |||
606 | xsk_ring_prod__submit(&xsk->tx, BATCH_SIZE); | ||
607 | xsk->outstanding_tx += BATCH_SIZE; | ||
608 | frame_nb += BATCH_SIZE; | ||
609 | frame_nb %= NUM_FRAMES; | ||
610 | } | ||
611 | |||
612 | complete_tx_only(xsk); | ||
613 | } | 639 | } |
614 | } | 640 | } |
615 | 641 | ||
616 | static void l2fwd(struct xsk_socket_info *xsk) | 642 | static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds) |
617 | { | 643 | { |
618 | for (;;) { | 644 | unsigned int rcvd, i; |
619 | unsigned int rcvd, i; | 645 | u32 idx_rx = 0, idx_tx = 0; |
620 | u32 idx_rx = 0, idx_tx = 0; | 646 | int ret; |
621 | int ret; | ||
622 | 647 | ||
623 | for (;;) { | 648 | complete_tx_l2fwd(xsk, fds); |
624 | complete_tx_l2fwd(xsk); | ||
625 | 649 | ||
626 | rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, | 650 | rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx); |
627 | &idx_rx); | 651 | if (!rcvd) { |
628 | if (rcvd > 0) | 652 | if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) |
629 | break; | 653 | ret = poll(fds, num_socks, opt_timeout); |
630 | } | 654 | return; |
655 | } | ||
631 | 656 | ||
657 | ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx); | ||
658 | while (ret != rcvd) { | ||
659 | if (ret < 0) | ||
660 | exit_with_error(-ret); | ||
661 | if (xsk_ring_prod__needs_wakeup(&xsk->tx)) | ||
662 | kick_tx(xsk); | ||
632 | ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx); | 663 | ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx); |
633 | while (ret != rcvd) { | 664 | } |
634 | if (ret < 0) | 665 | |
635 | exit_with_error(-ret); | 666 | for (i = 0; i < rcvd; i++) { |
636 | ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx); | 667 | u64 addr = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx)->addr; |
637 | } | 668 | u32 len = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++)->len; |
669 | char *pkt = xsk_umem__get_data(xsk->umem->buffer, addr); | ||
670 | |||
671 | swap_mac_addresses(pkt); | ||
638 | 672 | ||
639 | for (i = 0; i < rcvd; i++) { | 673 | hex_dump(pkt, len, addr); |
640 | u64 addr = xsk_ring_cons__rx_desc(&xsk->rx, | 674 | xsk_ring_prod__tx_desc(&xsk->tx, idx_tx)->addr = addr; |
641 | idx_rx)->addr; | 675 | xsk_ring_prod__tx_desc(&xsk->tx, idx_tx++)->len = len; |
642 | u32 len = xsk_ring_cons__rx_desc(&xsk->rx, | 676 | } |
643 | idx_rx++)->len; | ||
644 | char *pkt = xsk_umem__get_data(xsk->umem->buffer, addr); | ||
645 | 677 | ||
646 | swap_mac_addresses(pkt); | 678 | xsk_ring_prod__submit(&xsk->tx, rcvd); |
679 | xsk_ring_cons__release(&xsk->rx, rcvd); | ||
647 | 680 | ||
648 | hex_dump(pkt, len, addr); | 681 | xsk->rx_npkts += rcvd; |
649 | xsk_ring_prod__tx_desc(&xsk->tx, idx_tx)->addr = addr; | 682 | xsk->outstanding_tx += rcvd; |
650 | xsk_ring_prod__tx_desc(&xsk->tx, idx_tx++)->len = len; | 683 | } |
651 | } | 684 | |
685 | static void l2fwd_all(void) | ||
686 | { | ||
687 | struct pollfd fds[MAX_SOCKS]; | ||
688 | int i, ret; | ||
689 | |||
690 | memset(fds, 0, sizeof(fds)); | ||
691 | |||
692 | for (i = 0; i < num_socks; i++) { | ||
693 | fds[i].fd = xsk_socket__fd(xsks[i]->xsk); | ||
694 | fds[i].events = POLLOUT | POLLIN; | ||
695 | } | ||
652 | 696 | ||
653 | xsk_ring_prod__submit(&xsk->tx, rcvd); | 697 | for (;;) { |
654 | xsk_ring_cons__release(&xsk->rx, rcvd); | 698 | if (opt_poll) { |
699 | ret = poll(fds, num_socks, opt_timeout); | ||
700 | if (ret <= 0) | ||
701 | continue; | ||
702 | } | ||
655 | 703 | ||
656 | xsk->rx_npkts += rcvd; | 704 | for (i = 0; i < num_socks; i++) |
657 | xsk->outstanding_tx += rcvd; | 705 | l2fwd(xsks[i], fds); |
658 | } | 706 | } |
659 | } | 707 | } |
660 | 708 | ||
@@ -705,9 +753,9 @@ int main(int argc, char **argv) | |||
705 | if (opt_bench == BENCH_RXDROP) | 753 | if (opt_bench == BENCH_RXDROP) |
706 | rx_drop_all(); | 754 | rx_drop_all(); |
707 | else if (opt_bench == BENCH_TXONLY) | 755 | else if (opt_bench == BENCH_TXONLY) |
708 | tx_only(xsks[0]); | 756 | tx_only_all(); |
709 | else | 757 | else |
710 | l2fwd(xsks[0]); | 758 | l2fwd_all(); |
711 | 759 | ||
712 | return 0; | 760 | return 0; |
713 | } | 761 | } |