Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

samples/bpf: Attach XDP programs in driver mode by default

When attaching XDP programs, userspace can set flags to request the attach
mode (generic/SKB mode, driver mode or hw offloaded mode). If no such flags
are requested, the kernel will attempt to attach in driver mode, and then
silently fall back to SKB mode if this fails.

The silent fallback is a major source of user confusion, as users will try
to load a program on a device without XDP support, and instead of an error
they will get the silent fallback behaviour, not notice, and then wonder
why performance is not what they were expecting.

In an attempt to combat this, let's switch all the samples to default to
explicitly requesting driver-mode attach. As part of this, ensure that all
the userspace utilities have a switch to enable SKB mode. For those that
have a switch to request driver mode, keep it but turn it into a no-op.

Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: David Ahern <dsahern@gmail.com>
Link: https://lore.kernel.org/bpf/20191216110742.364456-1-toke@redhat.com

authored by

Toke Høiland-Jørgensen and committed by
Alexei Starovoitov
d50ecc46 45027897

+58 -12
+4 -1
samples/bpf/xdp1_user.c
··· 98 98 xdp_flags |= XDP_FLAGS_SKB_MODE; 99 99 break; 100 100 case 'N': 101 - xdp_flags |= XDP_FLAGS_DRV_MODE; 101 + /* default, set below */ 102 102 break; 103 103 case 'F': 104 104 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; ··· 108 108 return 1; 109 109 } 110 110 } 111 + 112 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 113 + xdp_flags |= XDP_FLAGS_DRV_MODE; 111 114 112 115 if (optind == argc) { 113 116 usage(basename(argv[0]));
+4 -1
samples/bpf/xdp_adjust_tail_user.c
··· 120 120 xdp_flags |= XDP_FLAGS_SKB_MODE; 121 121 break; 122 122 case 'N': 123 - xdp_flags |= XDP_FLAGS_DRV_MODE; 123 + /* default, set below */ 124 124 break; 125 125 case 'F': 126 126 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; ··· 131 131 } 132 132 opt_flags[opt] = 0; 133 133 } 134 + 135 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 136 + xdp_flags |= XDP_FLAGS_DRV_MODE; 134 137 135 138 for (i = 0; i < strlen(optstr); i++) { 136 139 if (opt_flags[(unsigned int)optstr[i]]) {
+14 -3
samples/bpf/xdp_fwd_user.c
··· 27 27 #include "libbpf.h" 28 28 #include <bpf/bpf.h> 29 29 30 + static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; 31 + 30 32 static int do_attach(int idx, int prog_fd, int map_fd, const char *name) 31 33 { 32 34 int err; 33 35 34 - err = bpf_set_link_xdp_fd(idx, prog_fd, 0); 36 + err = bpf_set_link_xdp_fd(idx, prog_fd, xdp_flags); 35 37 if (err < 0) { 36 38 printf("ERROR: failed to attach program to %s\n", name); 37 39 return err; ··· 51 49 { 52 50 int err; 53 51 54 - err = bpf_set_link_xdp_fd(idx, -1, 0); 52 + err = bpf_set_link_xdp_fd(idx, -1, xdp_flags); 55 53 if (err < 0) 56 54 printf("ERROR: failed to detach program from %s\n", name); 57 55 ··· 85 83 int attach = 1; 86 84 int ret = 0; 87 85 88 - while ((opt = getopt(argc, argv, ":dD")) != -1) { 86 + while ((opt = getopt(argc, argv, ":dDSF")) != -1) { 89 87 switch (opt) { 90 88 case 'd': 91 89 attach = 0; 90 + break; 91 + case 'S': 92 + xdp_flags |= XDP_FLAGS_SKB_MODE; 93 + break; 94 + case 'F': 95 + xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; 92 96 break; 93 97 case 'D': 94 98 prog_name = "xdp_fwd_direct"; ··· 104 96 return 1; 105 97 } 106 98 } 99 + 100 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 101 + xdp_flags |= XDP_FLAGS_DRV_MODE; 107 102 108 103 if (optind == argc) { 109 104 usage(basename(argv[0]));
+4
samples/bpf/xdp_redirect_cpu_user.c
··· 728 728 return EXIT_FAIL_OPTION; 729 729 } 730 730 } 731 + 732 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 733 + xdp_flags |= XDP_FLAGS_DRV_MODE; 734 + 731 735 /* Required option */ 732 736 if (ifindex == -1) { 733 737 fprintf(stderr, "ERR: required option --dev missing\n");
+4 -1
samples/bpf/xdp_redirect_map_user.c
··· 116 116 xdp_flags |= XDP_FLAGS_SKB_MODE; 117 117 break; 118 118 case 'N': 119 - xdp_flags |= XDP_FLAGS_DRV_MODE; 119 + /* default, set below */ 120 120 break; 121 121 case 'F': 122 122 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; ··· 126 126 return 1; 127 127 } 128 128 } 129 + 130 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 131 + xdp_flags |= XDP_FLAGS_DRV_MODE; 129 132 130 133 if (optind == argc) { 131 134 printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]);
+4 -1
samples/bpf/xdp_redirect_user.c
··· 117 117 xdp_flags |= XDP_FLAGS_SKB_MODE; 118 118 break; 119 119 case 'N': 120 - xdp_flags |= XDP_FLAGS_DRV_MODE; 120 + /* default, set below */ 121 121 break; 122 122 case 'F': 123 123 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; ··· 127 127 return 1; 128 128 } 129 129 } 130 + 131 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 132 + xdp_flags |= XDP_FLAGS_DRV_MODE; 130 133 131 134 if (optind == argc) { 132 135 printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]);
+3
samples/bpf/xdp_router_ipv4_user.c
··· 662 662 } 663 663 } 664 664 665 + if (!(flags & XDP_FLAGS_SKB_MODE)) 666 + flags |= XDP_FLAGS_DRV_MODE; 667 + 665 668 if (optind == ac) { 666 669 usage(basename(argv[0])); 667 670 return 1;
+4
samples/bpf/xdp_rxq_info_user.c
··· 551 551 return EXIT_FAIL_OPTION; 552 552 } 553 553 } 554 + 555 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 556 + xdp_flags |= XDP_FLAGS_DRV_MODE; 557 + 554 558 /* Required option */ 555 559 if (ifindex == -1) { 556 560 fprintf(stderr, "ERR: required option --dev missing\n");
+9 -3
samples/bpf/xdp_sample_pkts_user.c
··· 52 52 __u32 curr_prog_id = 0; 53 53 int err = 0; 54 54 55 - err = bpf_get_link_xdp_id(idx, &curr_prog_id, 0); 55 + err = bpf_get_link_xdp_id(idx, &curr_prog_id, xdp_flags); 56 56 if (err) { 57 57 printf("bpf_get_link_xdp_id failed\n"); 58 58 return err; 59 59 } 60 60 if (prog_id == curr_prog_id) { 61 - err = bpf_set_link_xdp_fd(idx, -1, 0); 61 + err = bpf_set_link_xdp_fd(idx, -1, xdp_flags); 62 62 if (err < 0) 63 63 printf("ERROR: failed to detach prog from %s\n", name); 64 64 } else if (!curr_prog_id) { ··· 115 115 .prog_type = BPF_PROG_TYPE_XDP, 116 116 }; 117 117 struct perf_buffer_opts pb_opts = {}; 118 - const char *optstr = "F"; 118 + const char *optstr = "FS"; 119 119 int prog_fd, map_fd, opt; 120 120 struct bpf_object *obj; 121 121 struct bpf_map *map; ··· 127 127 case 'F': 128 128 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; 129 129 break; 130 + case 'S': 131 + xdp_flags |= XDP_FLAGS_SKB_MODE; 132 + break; 130 133 default: 131 134 usage(basename(argv[0])); 132 135 return 1; 133 136 } 134 137 } 138 + 139 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 140 + xdp_flags |= XDP_FLAGS_DRV_MODE; 135 141 136 142 if (optind == argc) { 137 143 usage(basename(argv[0]));
+4 -1
samples/bpf/xdp_tx_iptunnel_user.c
··· 231 231 xdp_flags |= XDP_FLAGS_SKB_MODE; 232 232 break; 233 233 case 'N': 234 - xdp_flags |= XDP_FLAGS_DRV_MODE; 234 + /* default, set below */ 235 235 break; 236 236 case 'F': 237 237 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; ··· 242 242 } 243 243 opt_flags[opt] = 0; 244 244 } 245 + 246 + if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 247 + xdp_flags |= XDP_FLAGS_DRV_MODE; 245 248 246 249 for (i = 0; i < strlen(optstr); i++) { 247 250 if (opt_flags[(unsigned int)optstr[i]]) {
+4 -1
samples/bpf/xdpsock_user.c
··· 440 440 opt_xdp_bind_flags |= XDP_COPY; 441 441 break; 442 442 case 'N': 443 - opt_xdp_flags |= XDP_FLAGS_DRV_MODE; 443 + /* default, set below */ 444 444 break; 445 445 case 'n': 446 446 opt_interval = atoi(optarg); ··· 473 473 usage(basename(argv[0])); 474 474 } 475 475 } 476 + 477 + if (!(opt_xdp_flags & XDP_FLAGS_SKB_MODE)) 478 + opt_xdp_flags |= XDP_FLAGS_DRV_MODE; 476 479 477 480 opt_ifindex = if_nametoindex(opt_if); 478 481 if (!opt_ifindex) {