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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftests-bpf-convert-test_tc_tunnel-sh-to-test_progs'

Alexis Lothoré says:

====================
Hello,
this is the v3 of test_tc_tunnel conversion into test_progs framework.
This new revision:
- fixes a few issues spotted by the bot reviewer
- removes any test ensuring connection failure (and so depending on a
timout) to keep the execution time reasonable

test_tc_tunnel.sh tests a variety of tunnels based on BPF: packets are
encapsulated by a BPF program on the client egress. We then check that
those packets can be decapsulated on server ingress side, either thanks
to kernel-based or BPF-based decapsulation. Those tests are run thanks
to two veths in two dedicated namespaces.

- patches 1 and 2 are preparatory patches
- patch 3 introduce tc_tunnel test into test_progs
- patch 4 gets rid of the test_tc_tunnel.sh script

The new test has been executed both in some x86 local qemu machine, as
well as in CI:

# ./test_progs -a tc_tunnel
#454/1 tc_tunnel/ipip_none:OK
#454/2 tc_tunnel/ipip6_none:OK
#454/3 tc_tunnel/ip6tnl_none:OK
#454/4 tc_tunnel/sit_none:OK
#454/5 tc_tunnel/vxlan_eth:OK
#454/6 tc_tunnel/ip6vxlan_eth:OK
#454/7 tc_tunnel/gre_none:OK
#454/8 tc_tunnel/gre_eth:OK
#454/9 tc_tunnel/gre_mpls:OK
#454/10 tc_tunnel/ip6gre_none:OK
#454/11 tc_tunnel/ip6gre_eth:OK
#454/12 tc_tunnel/ip6gre_mpls:OK
#454/13 tc_tunnel/udp_none:OK
#454/14 tc_tunnel/udp_eth:OK
#454/15 tc_tunnel/udp_mpls:OK
#454/16 tc_tunnel/ip6udp_none:OK
#454/17 tc_tunnel/ip6udp_eth:OK
#454/18 tc_tunnel/ip6udp_mpls:OK
#454 tc_tunnel:OK
Summary: 1/18 PASSED, 0 SKIPPED, 0 FAILED
====================

Link: https://patch.msgid.link/20251027-tc_tunnel-v3-0-505c12019f9d@bootlin.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

+789 -468
-1
tools/testing/selftests/bpf/Makefile
··· 105 105 # Order correspond to 'make run_tests' order 106 106 TEST_PROGS := test_kmod.sh \ 107 107 test_lirc_mode2.sh \ 108 - test_tc_tunnel.sh \ 109 108 test_tc_edt.sh \ 110 109 test_xdping.sh \ 111 110 test_bpftool_build.sh \
+44
tools/testing/selftests/bpf/network_helpers.c
··· 766 766 return err; 767 767 } 768 768 769 + int tc_prog_attach(const char *dev, int ingress_fd, int egress_fd) 770 + { 771 + int ifindex, ret; 772 + 773 + if (!ASSERT_TRUE(ingress_fd >= 0 || egress_fd >= 0, 774 + "at least one program fd is valid")) 775 + return -1; 776 + 777 + ifindex = if_nametoindex(dev); 778 + if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) 779 + return -1; 780 + 781 + DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = ifindex, 782 + .attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS); 783 + DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1, 784 + .priority = 1, .prog_fd = ingress_fd); 785 + DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1, 786 + .priority = 1, .prog_fd = egress_fd); 787 + 788 + ret = bpf_tc_hook_create(&hook); 789 + if (!ASSERT_OK(ret, "create tc hook")) 790 + return ret; 791 + 792 + if (ingress_fd >= 0) { 793 + hook.attach_point = BPF_TC_INGRESS; 794 + ret = bpf_tc_attach(&hook, &opts1); 795 + if (!ASSERT_OK(ret, "bpf_tc_attach")) { 796 + bpf_tc_hook_destroy(&hook); 797 + return ret; 798 + } 799 + } 800 + 801 + if (egress_fd >= 0) { 802 + hook.attach_point = BPF_TC_EGRESS; 803 + ret = bpf_tc_attach(&hook, &opts2); 804 + if (!ASSERT_OK(ret, "bpf_tc_attach")) { 805 + bpf_tc_hook_destroy(&hook); 806 + return ret; 807 + } 808 + } 809 + 810 + return 0; 811 + } 812 + 769 813 #ifdef TRAFFIC_MONITOR 770 814 struct tmonitor_ctx { 771 815 pcap_t *pcap;
+16
tools/testing/selftests/bpf/network_helpers.h
··· 255 255 256 256 typedef int (*tm_print_fn_t)(const char *format, va_list args); 257 257 258 + /** 259 + * tc_prog_attach - attach BPF program(s) to an interface 260 + * 261 + * Takes file descriptors pointing to at least one, at most two BPF 262 + * programs, and attach those programs to an interface ingress, egress or 263 + * both. 264 + * 265 + * @dev: string containing the interface name 266 + * @ingress_fd: file descriptor of the program to attach to interface ingress 267 + * @egress_fd: file descriptor of the program to attach to interface egress 268 + * 269 + * Returns 0 on success, -1 if no valid file descriptor has been found, if 270 + * the interface name is invalid or if an error ocurred during attach. 271 + */ 272 + int tc_prog_attach(const char *dev, int ingress_fd, int egress_fd); 273 + 258 274 #ifdef TRAFFIC_MONITOR 259 275 struct tmonitor_ctx *traffic_monitor_start(const char *netns, const char *test_name, 260 276 const char *subtest_name);
+674
tools/testing/selftests/bpf/prog_tests/test_tc_tunnel.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 + 3 + /* 4 + * End-to-end eBPF tunnel test suite 5 + * The file tests BPF network tunnels implementation. For each tunnel 6 + * type, the test validates that: 7 + * - basic communication can first be established between the two veths 8 + * - when adding a BPF-based encapsulation on client egress, it now fails 9 + * to communicate with the server 10 + * - when adding a kernel-based decapsulation on server ingress, client 11 + * can now connect 12 + * - when replacing the kernel-based decapsulation with a BPF-based one, 13 + * the client can still connect 14 + */ 15 + 16 + #include <stdio.h> 17 + #include <unistd.h> 18 + #include <fcntl.h> 19 + #include <sys/socket.h> 20 + #include <bpf/libbpf.h> 21 + 22 + #include "test_progs.h" 23 + #include "network_helpers.h" 24 + #include "test_tc_tunnel.skel.h" 25 + 26 + #define SERVER_NS "tc-tunnel-server-ns" 27 + #define CLIENT_NS "tc-tunnel-client-ns" 28 + #define MAC_ADDR_VETH1 "00:11:22:33:44:55" 29 + #define IP4_ADDR_VETH1 "192.168.1.1" 30 + #define IP6_ADDR_VETH1 "fd::1" 31 + #define MAC_ADDR_VETH2 "66:77:88:99:AA:BB" 32 + #define IP4_ADDR_VETH2 "192.168.1.2" 33 + #define IP6_ADDR_VETH2 "fd::2" 34 + 35 + #define TEST_NAME_MAX_LEN 64 36 + #define PROG_NAME_MAX_LEN 64 37 + #define TUNNEL_ARGS_MAX_LEN 128 38 + #define BUFFER_LEN 2000 39 + #define DEFAULT_TEST_DATA_SIZE 100 40 + #define GSO_TEST_DATA_SIZE BUFFER_LEN 41 + 42 + #define TIMEOUT_MS 1000 43 + #define TEST_PORT 8000 44 + #define UDP_PORT 5555 45 + #define MPLS_UDP_PORT 6635 46 + #define FOU_MPLS_PROTO 137 47 + #define VXLAN_ID 1 48 + #define VXLAN_PORT 8472 49 + #define MPLS_TABLE_ENTRIES_COUNT 65536 50 + 51 + static char tx_buffer[BUFFER_LEN], rx_buffer[BUFFER_LEN]; 52 + 53 + struct subtest_cfg { 54 + char *ebpf_tun_type; 55 + char *iproute_tun_type; 56 + char *mac_tun_type; 57 + int ipproto; 58 + void (*extra_decap_mod_args_cb)(struct subtest_cfg *cfg, char *dst); 59 + bool tunnel_need_veth_mac; 60 + bool configure_fou_rx_port; 61 + char *tmode; 62 + bool expect_kern_decap_failure; 63 + bool configure_mpls; 64 + bool test_gso; 65 + char *tunnel_client_addr; 66 + char *tunnel_server_addr; 67 + char name[TEST_NAME_MAX_LEN]; 68 + char *server_addr; 69 + int client_egress_prog_fd; 70 + int server_ingress_prog_fd; 71 + char extra_decap_mod_args[TUNNEL_ARGS_MAX_LEN]; 72 + int *server_fd; 73 + }; 74 + 75 + struct connection { 76 + int client_fd; 77 + int server_fd; 78 + }; 79 + 80 + static int build_subtest_name(struct subtest_cfg *cfg, char *dst, size_t size) 81 + { 82 + int ret; 83 + 84 + ret = snprintf(dst, size, "%s_%s", cfg->ebpf_tun_type, 85 + cfg->mac_tun_type); 86 + 87 + return ret < 0 ? ret : 0; 88 + } 89 + 90 + static int set_subtest_progs(struct subtest_cfg *cfg, struct test_tc_tunnel *skel) 91 + { 92 + char prog_name[PROG_NAME_MAX_LEN]; 93 + struct bpf_program *prog; 94 + int ret; 95 + 96 + ret = snprintf(prog_name, PROG_NAME_MAX_LEN, "__encap_"); 97 + if (ret < 0) 98 + return ret; 99 + ret = build_subtest_name(cfg, prog_name + ret, PROG_NAME_MAX_LEN - ret); 100 + if (ret < 0) 101 + return ret; 102 + prog = bpf_object__find_program_by_name(skel->obj, prog_name); 103 + if (!prog) 104 + return -1; 105 + 106 + cfg->client_egress_prog_fd = bpf_program__fd(prog); 107 + cfg->server_ingress_prog_fd = bpf_program__fd(skel->progs.decap_f); 108 + return 0; 109 + } 110 + 111 + static void set_subtest_addresses(struct subtest_cfg *cfg) 112 + { 113 + if (cfg->ipproto == 6) 114 + cfg->server_addr = IP6_ADDR_VETH2; 115 + else 116 + cfg->server_addr = IP4_ADDR_VETH2; 117 + 118 + /* Some specific tunnel types need specific addressing, it then 119 + * has been already set in the configuration table. Otherwise, 120 + * deduce the relevant addressing from the ipproto 121 + */ 122 + if (cfg->tunnel_client_addr && cfg->tunnel_server_addr) 123 + return; 124 + 125 + if (cfg->ipproto == 6) { 126 + cfg->tunnel_client_addr = IP6_ADDR_VETH1; 127 + cfg->tunnel_server_addr = IP6_ADDR_VETH2; 128 + } else { 129 + cfg->tunnel_client_addr = IP4_ADDR_VETH1; 130 + cfg->tunnel_server_addr = IP4_ADDR_VETH2; 131 + } 132 + } 133 + 134 + static int run_server(struct subtest_cfg *cfg) 135 + { 136 + struct nstoken *nstoken = open_netns(SERVER_NS); 137 + int family = cfg->ipproto == 6 ? AF_INET6 : AF_INET; 138 + 139 + cfg->server_fd = start_reuseport_server(family, SOCK_STREAM, 140 + cfg->server_addr, TEST_PORT, 141 + TIMEOUT_MS, 1); 142 + close_netns(nstoken); 143 + if (!ASSERT_OK_PTR(cfg->server_fd, "start server")) 144 + return -1; 145 + 146 + return 0; 147 + } 148 + 149 + static void stop_server(struct subtest_cfg *cfg) 150 + { 151 + free_fds(cfg->server_fd, 1); 152 + } 153 + 154 + static int check_server_rx_data(struct subtest_cfg *cfg, 155 + struct connection *conn, int len) 156 + { 157 + int err; 158 + 159 + memset(rx_buffer, 0, BUFFER_LEN); 160 + err = recv(conn->server_fd, rx_buffer, len, 0); 161 + if (!ASSERT_EQ(err, len, "check rx data len")) 162 + return 1; 163 + if (!ASSERT_MEMEQ(tx_buffer, rx_buffer, len, "check received data")) 164 + return 1; 165 + return 0; 166 + } 167 + 168 + static struct connection *connect_client_to_server(struct subtest_cfg *cfg) 169 + { 170 + struct network_helper_opts opts = {.timeout_ms = 500}; 171 + int family = cfg->ipproto == 6 ? AF_INET6 : AF_INET; 172 + struct connection *conn = NULL; 173 + int client_fd, server_fd; 174 + 175 + conn = malloc(sizeof(struct connection)); 176 + if (!conn) 177 + return conn; 178 + 179 + client_fd = connect_to_addr_str(family, SOCK_STREAM, cfg->server_addr, 180 + TEST_PORT, &opts); 181 + 182 + if (client_fd < 0) { 183 + free(conn); 184 + return NULL; 185 + } 186 + 187 + server_fd = accept(*cfg->server_fd, NULL, NULL); 188 + if (server_fd < 0) { 189 + close(client_fd); 190 + free(conn); 191 + return NULL; 192 + } 193 + 194 + conn->server_fd = server_fd; 195 + conn->client_fd = client_fd; 196 + 197 + return conn; 198 + } 199 + 200 + static void disconnect_client_from_server(struct subtest_cfg *cfg, 201 + struct connection *conn) 202 + { 203 + close(conn->server_fd); 204 + close(conn->client_fd); 205 + free(conn); 206 + } 207 + 208 + static int send_and_test_data(struct subtest_cfg *cfg, bool must_succeed) 209 + { 210 + struct connection *conn; 211 + int err, res = -1; 212 + 213 + conn = connect_client_to_server(cfg); 214 + if (!must_succeed && !ASSERT_ERR_PTR(conn, "connection that must fail")) 215 + goto end; 216 + else if (!must_succeed) 217 + return 0; 218 + 219 + if (!ASSERT_OK_PTR(conn, "connection that must succeed")) 220 + return -1; 221 + 222 + err = send(conn->client_fd, tx_buffer, DEFAULT_TEST_DATA_SIZE, 0); 223 + if (!ASSERT_EQ(err, DEFAULT_TEST_DATA_SIZE, "send data from client")) 224 + goto end; 225 + if (check_server_rx_data(cfg, conn, DEFAULT_TEST_DATA_SIZE)) 226 + goto end; 227 + 228 + if (!cfg->test_gso) { 229 + res = 0; 230 + goto end; 231 + } 232 + 233 + err = send(conn->client_fd, tx_buffer, GSO_TEST_DATA_SIZE, 0); 234 + if (!ASSERT_EQ(err, GSO_TEST_DATA_SIZE, "send (large) data from client")) 235 + goto end; 236 + if (check_server_rx_data(cfg, conn, DEFAULT_TEST_DATA_SIZE)) 237 + goto end; 238 + 239 + res = 0; 240 + end: 241 + disconnect_client_from_server(cfg, conn); 242 + return res; 243 + } 244 + 245 + static void vxlan_decap_mod_args_cb(struct subtest_cfg *cfg, char *dst) 246 + { 247 + snprintf(dst, TUNNEL_ARGS_MAX_LEN, "id %d dstport %d udp6zerocsumrx", 248 + VXLAN_ID, VXLAN_PORT); 249 + } 250 + 251 + static void udp_decap_mod_args_cb(struct subtest_cfg *cfg, char *dst) 252 + { 253 + bool is_mpls = !strcmp(cfg->mac_tun_type, "mpls"); 254 + 255 + snprintf(dst, TUNNEL_ARGS_MAX_LEN, 256 + "encap fou encap-sport auto encap-dport %d", 257 + is_mpls ? MPLS_UDP_PORT : UDP_PORT); 258 + } 259 + 260 + static int configure_fou_rx_port(struct subtest_cfg *cfg, bool add) 261 + { 262 + bool is_mpls = strcmp(cfg->mac_tun_type, "mpls") == 0; 263 + int fou_proto; 264 + 265 + if (is_mpls) 266 + fou_proto = FOU_MPLS_PROTO; 267 + else 268 + fou_proto = cfg->ipproto == 6 ? 41 : 4; 269 + 270 + SYS(fail, "ip fou %s port %d ipproto %d%s", add ? "add" : "del", 271 + is_mpls ? MPLS_UDP_PORT : UDP_PORT, fou_proto, 272 + cfg->ipproto == 6 ? " -6" : ""); 273 + 274 + return 0; 275 + fail: 276 + return 1; 277 + } 278 + 279 + static int add_fou_rx_port(struct subtest_cfg *cfg) 280 + { 281 + return configure_fou_rx_port(cfg, true); 282 + } 283 + 284 + static int del_fou_rx_port(struct subtest_cfg *cfg) 285 + { 286 + return configure_fou_rx_port(cfg, false); 287 + } 288 + 289 + static int update_tunnel_intf_addr(struct subtest_cfg *cfg) 290 + { 291 + SYS(fail, "ip link set dev testtun0 address " MAC_ADDR_VETH2); 292 + return 0; 293 + fail: 294 + return -1; 295 + } 296 + 297 + static int configure_kernel_for_mpls(struct subtest_cfg *cfg) 298 + { 299 + SYS(fail, "sysctl -qw net.mpls.platform_labels=%d", 300 + MPLS_TABLE_ENTRIES_COUNT); 301 + SYS(fail, "ip -f mpls route add 1000 dev lo"); 302 + SYS(fail, "ip link set lo up"); 303 + SYS(fail, "sysctl -qw net.mpls.conf.testtun0.input=1"); 304 + SYS(fail, "sysctl -qw net.ipv4.conf.lo.rp_filter=0"); 305 + return 0; 306 + fail: 307 + return -1; 308 + } 309 + 310 + static int configure_encapsulation(struct subtest_cfg *cfg) 311 + { 312 + int ret; 313 + 314 + ret = tc_prog_attach("veth1", -1, cfg->client_egress_prog_fd); 315 + 316 + return ret; 317 + } 318 + 319 + static int configure_kernel_decapsulation(struct subtest_cfg *cfg) 320 + { 321 + struct nstoken *nstoken = open_netns(SERVER_NS); 322 + 323 + if (cfg->configure_fou_rx_port && 324 + !ASSERT_OK(add_fou_rx_port(cfg), "configure FOU RX port")) 325 + goto fail; 326 + SYS(fail, "ip link add name testtun0 type %s %s remote %s local %s %s", 327 + cfg->iproute_tun_type, cfg->tmode ? cfg->tmode : "", 328 + cfg->tunnel_client_addr, cfg->tunnel_server_addr, 329 + cfg->extra_decap_mod_args); 330 + if (cfg->tunnel_need_veth_mac && 331 + !ASSERT_OK(update_tunnel_intf_addr(cfg), "update testtun0 mac")) 332 + goto fail; 333 + if (cfg->configure_mpls && 334 + (!ASSERT_OK(configure_kernel_for_mpls(cfg), 335 + "configure MPLS decap"))) 336 + goto fail; 337 + SYS(fail, "sysctl -qw net.ipv4.conf.all.rp_filter=0"); 338 + SYS(fail, "sysctl -qw net.ipv4.conf.testtun0.rp_filter=0"); 339 + SYS(fail, "ip link set dev testtun0 up"); 340 + close_netns(nstoken); 341 + return 0; 342 + fail: 343 + close_netns(nstoken); 344 + return -1; 345 + } 346 + 347 + static void remove_kernel_decapsulation(struct subtest_cfg *cfg) 348 + { 349 + SYS_NOFAIL("ip link del testtun0"); 350 + if (cfg->configure_mpls) 351 + SYS_NOFAIL("ip -f mpls route del 1000 dev lo"); 352 + if (cfg->configure_fou_rx_port) 353 + del_fou_rx_port(cfg); 354 + } 355 + 356 + static int configure_ebpf_decapsulation(struct subtest_cfg *cfg) 357 + { 358 + struct nstoken *nstoken = open_netns(SERVER_NS); 359 + 360 + if (!cfg->expect_kern_decap_failure) 361 + SYS(fail, "ip link del testtun0"); 362 + 363 + if (!ASSERT_OK(tc_prog_attach("veth2", cfg->server_ingress_prog_fd, -1), 364 + "attach_program")) 365 + goto fail; 366 + close_netns(nstoken); 367 + return 0; 368 + fail: 369 + close_netns(nstoken); 370 + return -1; 371 + } 372 + 373 + static void run_test(struct subtest_cfg *cfg) 374 + { 375 + struct nstoken *nstoken = open_netns(CLIENT_NS); 376 + 377 + if (!ASSERT_OK(run_server(cfg), "run server")) 378 + goto fail; 379 + 380 + /* Basic communication must work */ 381 + if (!ASSERT_OK(send_and_test_data(cfg, true), "connect without any encap")) 382 + goto fail; 383 + 384 + /* Attach encapsulation program to client */ 385 + if (!ASSERT_OK(configure_encapsulation(cfg), "configure encapsulation")) 386 + goto fail; 387 + 388 + /* If supported, insert kernel decap module, connection must succeed */ 389 + if (!cfg->expect_kern_decap_failure) { 390 + if (!ASSERT_OK(configure_kernel_decapsulation(cfg), 391 + "configure kernel decapsulation")) 392 + goto fail; 393 + if (!ASSERT_OK(send_and_test_data(cfg, true), 394 + "connect with encap prog and kern decap")) 395 + goto fail; 396 + } 397 + 398 + /* Replace kernel decapsulation with BPF decapsulation, test must pass */ 399 + if (!ASSERT_OK(configure_ebpf_decapsulation(cfg), "configure ebpf decapsulation")) 400 + goto fail; 401 + ASSERT_OK(send_and_test_data(cfg, true), "connect with encap and decap progs"); 402 + 403 + fail: 404 + stop_server(cfg); 405 + close_netns(nstoken); 406 + } 407 + 408 + static int setup(void) 409 + { 410 + struct nstoken *nstoken = NULL; 411 + int fd, err; 412 + 413 + fd = open("/dev/urandom", O_RDONLY); 414 + if (!ASSERT_OK_FD(fd, "open urandom")) 415 + goto fail; 416 + err = read(fd, tx_buffer, BUFFER_LEN); 417 + close(fd); 418 + 419 + if (!ASSERT_EQ(err, BUFFER_LEN, "read random bytes")) 420 + goto fail; 421 + 422 + /* Configure the testing network */ 423 + if (!ASSERT_OK(make_netns(CLIENT_NS), "create client ns") || 424 + !ASSERT_OK(make_netns(SERVER_NS), "create server ns")) 425 + goto fail; 426 + 427 + nstoken = open_netns(CLIENT_NS); 428 + SYS(fail, "ip link add %s type veth peer name %s", 429 + "veth1 mtu 1500 netns " CLIENT_NS " address " MAC_ADDR_VETH1, 430 + "veth2 mtu 1500 netns " SERVER_NS " address " MAC_ADDR_VETH2); 431 + SYS(fail, "ethtool -K veth1 tso off"); 432 + SYS(fail, "ip link set veth1 up"); 433 + close_netns(nstoken); 434 + nstoken = open_netns(SERVER_NS); 435 + SYS(fail, "ip link set veth2 up"); 436 + close_netns(nstoken); 437 + 438 + return 0; 439 + fail: 440 + close_netns(nstoken); 441 + return 1; 442 + } 443 + 444 + static int subtest_setup(struct test_tc_tunnel *skel, struct subtest_cfg *cfg) 445 + { 446 + struct nstoken *nstoken; 447 + 448 + set_subtest_addresses(cfg); 449 + if (!ASSERT_OK(set_subtest_progs(cfg, skel), 450 + "find subtest progs")) 451 + return -1; 452 + if (cfg->extra_decap_mod_args_cb) 453 + cfg->extra_decap_mod_args_cb(cfg, cfg->extra_decap_mod_args); 454 + 455 + nstoken = open_netns(CLIENT_NS); 456 + SYS(fail, "ip -4 addr add " IP4_ADDR_VETH1 "/24 dev veth1"); 457 + SYS(fail, "ip -4 route flush table main"); 458 + SYS(fail, "ip -4 route add " IP4_ADDR_VETH2 " mtu 1450 dev veth1"); 459 + SYS(fail, "ip -6 addr add " IP6_ADDR_VETH1 "/64 dev veth1 nodad"); 460 + SYS(fail, "ip -6 route flush table main"); 461 + SYS(fail, "ip -6 route add " IP6_ADDR_VETH2 " mtu 1430 dev veth1"); 462 + close_netns(nstoken); 463 + 464 + nstoken = open_netns(SERVER_NS); 465 + SYS(fail, "ip -4 addr add " IP4_ADDR_VETH2 "/24 dev veth2"); 466 + SYS(fail, "ip -6 addr add " IP6_ADDR_VETH2 "/64 dev veth2 nodad"); 467 + close_netns(nstoken); 468 + 469 + return 0; 470 + fail: 471 + close_netns(nstoken); 472 + return -1; 473 + } 474 + 475 + 476 + static void subtest_cleanup(struct subtest_cfg *cfg) 477 + { 478 + struct nstoken *nstoken; 479 + 480 + nstoken = open_netns(CLIENT_NS); 481 + SYS_NOFAIL("tc qdisc delete dev veth1 parent ffff:fff1"); 482 + SYS_NOFAIL("ip a flush veth1"); 483 + close_netns(nstoken); 484 + nstoken = open_netns(SERVER_NS); 485 + SYS_NOFAIL("tc qdisc delete dev veth2 parent ffff:fff1"); 486 + SYS_NOFAIL("ip a flush veth2"); 487 + if (!cfg->expect_kern_decap_failure) 488 + remove_kernel_decapsulation(cfg); 489 + close_netns(nstoken); 490 + } 491 + 492 + static void cleanup(void) 493 + { 494 + remove_netns(CLIENT_NS); 495 + remove_netns(SERVER_NS); 496 + } 497 + 498 + static struct subtest_cfg subtests_cfg[] = { 499 + { 500 + .ebpf_tun_type = "ipip", 501 + .mac_tun_type = "none", 502 + .iproute_tun_type = "ipip", 503 + .ipproto = 4, 504 + }, 505 + { 506 + .ebpf_tun_type = "ipip6", 507 + .mac_tun_type = "none", 508 + .iproute_tun_type = "ip6tnl", 509 + .ipproto = 4, 510 + .tunnel_client_addr = IP6_ADDR_VETH1, 511 + .tunnel_server_addr = IP6_ADDR_VETH2, 512 + }, 513 + { 514 + .ebpf_tun_type = "ip6tnl", 515 + .iproute_tun_type = "ip6tnl", 516 + .mac_tun_type = "none", 517 + .ipproto = 6, 518 + }, 519 + { 520 + .mac_tun_type = "none", 521 + .ebpf_tun_type = "sit", 522 + .iproute_tun_type = "sit", 523 + .ipproto = 6, 524 + .tunnel_client_addr = IP4_ADDR_VETH1, 525 + .tunnel_server_addr = IP4_ADDR_VETH2, 526 + }, 527 + { 528 + .ebpf_tun_type = "vxlan", 529 + .mac_tun_type = "eth", 530 + .iproute_tun_type = "vxlan", 531 + .ipproto = 4, 532 + .extra_decap_mod_args_cb = vxlan_decap_mod_args_cb, 533 + .tunnel_need_veth_mac = true 534 + }, 535 + { 536 + .ebpf_tun_type = "ip6vxlan", 537 + .mac_tun_type = "eth", 538 + .iproute_tun_type = "vxlan", 539 + .ipproto = 6, 540 + .extra_decap_mod_args_cb = vxlan_decap_mod_args_cb, 541 + .tunnel_need_veth_mac = true 542 + }, 543 + { 544 + .ebpf_tun_type = "gre", 545 + .mac_tun_type = "none", 546 + .iproute_tun_type = "gre", 547 + .ipproto = 4, 548 + .test_gso = true 549 + }, 550 + { 551 + .ebpf_tun_type = "gre", 552 + .mac_tun_type = "eth", 553 + .iproute_tun_type = "gretap", 554 + .ipproto = 4, 555 + .tunnel_need_veth_mac = true, 556 + .test_gso = true 557 + }, 558 + { 559 + .ebpf_tun_type = "gre", 560 + .mac_tun_type = "mpls", 561 + .iproute_tun_type = "gre", 562 + .ipproto = 4, 563 + .configure_mpls = true, 564 + .test_gso = true 565 + }, 566 + { 567 + .ebpf_tun_type = "ip6gre", 568 + .mac_tun_type = "none", 569 + .iproute_tun_type = "ip6gre", 570 + .ipproto = 6, 571 + .test_gso = true, 572 + }, 573 + { 574 + .ebpf_tun_type = "ip6gre", 575 + .mac_tun_type = "eth", 576 + .iproute_tun_type = "ip6gretap", 577 + .ipproto = 6, 578 + .tunnel_need_veth_mac = true, 579 + .test_gso = true 580 + }, 581 + { 582 + .ebpf_tun_type = "ip6gre", 583 + .mac_tun_type = "mpls", 584 + .iproute_tun_type = "ip6gre", 585 + .ipproto = 6, 586 + .configure_mpls = true, 587 + .test_gso = true 588 + }, 589 + { 590 + .ebpf_tun_type = "udp", 591 + .mac_tun_type = "none", 592 + .iproute_tun_type = "ipip", 593 + .ipproto = 4, 594 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 595 + .configure_fou_rx_port = true, 596 + .test_gso = true 597 + }, 598 + { 599 + .ebpf_tun_type = "udp", 600 + .mac_tun_type = "eth", 601 + .iproute_tun_type = "ipip", 602 + .ipproto = 4, 603 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 604 + .configure_fou_rx_port = true, 605 + .expect_kern_decap_failure = true, 606 + .test_gso = true 607 + }, 608 + { 609 + .ebpf_tun_type = "udp", 610 + .mac_tun_type = "mpls", 611 + .iproute_tun_type = "ipip", 612 + .ipproto = 4, 613 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 614 + .configure_fou_rx_port = true, 615 + .tmode = "mode any ttl 255", 616 + .configure_mpls = true, 617 + .test_gso = true 618 + }, 619 + { 620 + .ebpf_tun_type = "ip6udp", 621 + .mac_tun_type = "none", 622 + .iproute_tun_type = "ip6tnl", 623 + .ipproto = 6, 624 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 625 + .configure_fou_rx_port = true, 626 + .test_gso = true 627 + }, 628 + { 629 + .ebpf_tun_type = "ip6udp", 630 + .mac_tun_type = "eth", 631 + .iproute_tun_type = "ip6tnl", 632 + .ipproto = 6, 633 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 634 + .configure_fou_rx_port = true, 635 + .expect_kern_decap_failure = true, 636 + .test_gso = true 637 + }, 638 + { 639 + .ebpf_tun_type = "ip6udp", 640 + .mac_tun_type = "mpls", 641 + .iproute_tun_type = "ip6tnl", 642 + .ipproto = 6, 643 + .extra_decap_mod_args_cb = udp_decap_mod_args_cb, 644 + .configure_fou_rx_port = true, 645 + .tmode = "mode any ttl 255", 646 + .expect_kern_decap_failure = true, 647 + .test_gso = true 648 + }, 649 + }; 650 + 651 + void test_tc_tunnel(void) 652 + { 653 + struct test_tc_tunnel *skel; 654 + struct subtest_cfg *cfg; 655 + int i, ret; 656 + 657 + skel = test_tc_tunnel__open_and_load(); 658 + if (!ASSERT_OK_PTR(skel, "skel open and load")) 659 + return; 660 + 661 + if (!ASSERT_OK(setup(), "global setup")) 662 + return; 663 + 664 + for (i = 0; i < ARRAY_SIZE(subtests_cfg); i++) { 665 + cfg = &subtests_cfg[i]; 666 + ret = build_subtest_name(cfg, cfg->name, TEST_NAME_MAX_LEN); 667 + if (ret < 0 || !test__start_subtest(cfg->name)) 668 + continue; 669 + subtest_setup(skel, cfg); 670 + run_test(cfg); 671 + subtest_cleanup(cfg); 672 + } 673 + cleanup(); 674 + }
+14 -93
tools/testing/selftests/bpf/prog_tests/test_tunnel.c
··· 534 534 close_netns(nstoken); 535 535 } 536 536 537 - static int attach_tc_prog(int ifindex, int igr_fd, int egr_fd) 538 - { 539 - DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = ifindex, 540 - .attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS); 541 - DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1, 542 - .priority = 1, .prog_fd = igr_fd); 543 - DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1, 544 - .priority = 1, .prog_fd = egr_fd); 545 - int ret; 546 - 547 - ret = bpf_tc_hook_create(&hook); 548 - if (!ASSERT_OK(ret, "create tc hook")) 549 - return ret; 550 - 551 - if (igr_fd >= 0) { 552 - hook.attach_point = BPF_TC_INGRESS; 553 - ret = bpf_tc_attach(&hook, &opts1); 554 - if (!ASSERT_OK(ret, "bpf_tc_attach")) { 555 - bpf_tc_hook_destroy(&hook); 556 - return ret; 557 - } 558 - } 559 - 560 - if (egr_fd >= 0) { 561 - hook.attach_point = BPF_TC_EGRESS; 562 - ret = bpf_tc_attach(&hook, &opts2); 563 - if (!ASSERT_OK(ret, "bpf_tc_attach")) { 564 - bpf_tc_hook_destroy(&hook); 565 - return ret; 566 - } 567 - } 568 - 569 - return 0; 570 - } 571 - 572 - static int generic_attach(const char *dev, int igr_fd, int egr_fd) 573 - { 574 - int ifindex; 575 - 576 - if (!ASSERT_OK_FD(igr_fd, "check ingress fd")) 577 - return -1; 578 - if (!ASSERT_OK_FD(egr_fd, "check egress fd")) 579 - return -1; 580 - 581 - ifindex = if_nametoindex(dev); 582 - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) 583 - return -1; 584 - 585 - return attach_tc_prog(ifindex, igr_fd, egr_fd); 586 - } 587 - 588 - static int generic_attach_igr(const char *dev, int igr_fd) 589 - { 590 - int ifindex; 591 - 592 - if (!ASSERT_OK_FD(igr_fd, "check ingress fd")) 593 - return -1; 594 - 595 - ifindex = if_nametoindex(dev); 596 - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) 597 - return -1; 598 - 599 - return attach_tc_prog(ifindex, igr_fd, -1); 600 - } 601 - 602 - static int generic_attach_egr(const char *dev, int egr_fd) 603 - { 604 - int ifindex; 605 - 606 - if (!ASSERT_OK_FD(egr_fd, "check egress fd")) 607 - return -1; 608 - 609 - ifindex = if_nametoindex(dev); 610 - if (!ASSERT_NEQ(ifindex, 0, "get ifindex")) 611 - return -1; 612 - 613 - return attach_tc_prog(ifindex, -1, egr_fd); 614 - } 615 - 616 537 static void test_vxlan_tunnel(void) 617 538 { 618 539 struct test_tunnel_kern *skel = NULL; ··· 556 635 goto done; 557 636 get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src); 558 637 set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src); 559 - if (generic_attach(VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 638 + if (tc_prog_attach(VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 560 639 goto done; 561 640 562 641 /* load and attach bpf prog to veth dev tc hook point */ 563 642 set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst); 564 - if (generic_attach_igr("veth1", set_dst_prog_fd)) 643 + if (tc_prog_attach("veth1", set_dst_prog_fd, -1)) 565 644 goto done; 566 645 567 646 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ ··· 569 648 if (!ASSERT_OK_PTR(nstoken, "setns src")) 570 649 goto done; 571 650 set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst); 572 - if (generic_attach_egr(VXLAN_TUNL_DEV0, set_dst_prog_fd)) 651 + if (tc_prog_attach(VXLAN_TUNL_DEV0, -1, set_dst_prog_fd)) 573 652 goto done; 574 653 close_netns(nstoken); 575 654 ··· 616 695 goto done; 617 696 get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src); 618 697 set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src); 619 - if (generic_attach(IP6VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 698 + if (tc_prog_attach(IP6VXLAN_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 620 699 goto done; 621 700 622 701 /* load and attach prog set_md to tunnel dev tc hook point at_ns0 */ ··· 624 703 if (!ASSERT_OK_PTR(nstoken, "setns src")) 625 704 goto done; 626 705 set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst); 627 - if (generic_attach_egr(IP6VXLAN_TUNL_DEV0, set_dst_prog_fd)) 706 + if (tc_prog_attach(IP6VXLAN_TUNL_DEV0, -1, set_dst_prog_fd)) 628 707 goto done; 629 708 close_netns(nstoken); 630 709 ··· 685 764 skel->progs.ipip_set_tunnel); 686 765 } 687 766 688 - if (generic_attach(IPIP_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 767 + if (tc_prog_attach(IPIP_TUNL_DEV1, get_src_prog_fd, set_src_prog_fd)) 689 768 goto done; 690 769 691 770 ping_dev0(); ··· 718 797 719 798 /* attach tc prog to tunnel dev */ 720 799 tc_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state); 721 - if (generic_attach_igr("veth1", tc_prog_fd)) 800 + if (tc_prog_attach("veth1", tc_prog_fd, -1)) 722 801 goto done; 723 802 724 803 /* attach xdp prog to tunnel dev */ ··· 791 870 if (!ASSERT_OK(err, "add tunnel")) 792 871 goto done; 793 872 794 - if (generic_attach(GRE_TUNL_DEV1, get_fd, set_fd)) 873 + if (tc_prog_attach(GRE_TUNL_DEV1, get_fd, set_fd)) 795 874 goto done; 796 875 797 876 ping_dev0(); ··· 832 911 833 912 set_fd = bpf_program__fd(skel->progs.ip6gretap_set_tunnel); 834 913 get_fd = bpf_program__fd(skel->progs.ip6gretap_get_tunnel); 835 - if (generic_attach(IP6GRE_TUNL_DEV1, get_fd, set_fd)) 914 + if (tc_prog_attach(IP6GRE_TUNL_DEV1, get_fd, set_fd)) 836 915 goto done; 837 916 838 917 ping6_veth0(); ··· 875 954 876 955 set_fd = bpf_program__fd(skel->progs.erspan_set_tunnel); 877 956 get_fd = bpf_program__fd(skel->progs.erspan_get_tunnel); 878 - if (generic_attach(ERSPAN_TUNL_DEV1, get_fd, set_fd)) 957 + if (tc_prog_attach(ERSPAN_TUNL_DEV1, get_fd, set_fd)) 879 958 goto done; 880 959 881 960 ping_dev0(); ··· 911 990 912 991 set_fd = bpf_program__fd(skel->progs.ip4ip6erspan_set_tunnel); 913 992 get_fd = bpf_program__fd(skel->progs.ip4ip6erspan_get_tunnel); 914 - if (generic_attach(IP6ERSPAN_TUNL_DEV1, get_fd, set_fd)) 993 + if (tc_prog_attach(IP6ERSPAN_TUNL_DEV1, get_fd, set_fd)) 915 994 goto done; 916 995 917 996 ping6_veth0(); ··· 938 1017 939 1018 set_fd = bpf_program__fd(skel->progs.geneve_set_tunnel); 940 1019 get_fd = bpf_program__fd(skel->progs.geneve_get_tunnel); 941 - if (generic_attach(GENEVE_TUNL_DEV1, get_fd, set_fd)) 1020 + if (tc_prog_attach(GENEVE_TUNL_DEV1, get_fd, set_fd)) 942 1021 goto done; 943 1022 944 1023 ping_dev0(); ··· 965 1044 966 1045 set_fd = bpf_program__fd(skel->progs.ip6geneve_set_tunnel); 967 1046 get_fd = bpf_program__fd(skel->progs.ip6geneve_get_tunnel); 968 - if (generic_attach(IP6GENEVE_TUNL_DEV1, get_fd, set_fd)) 1047 + if (tc_prog_attach(IP6GENEVE_TUNL_DEV1, get_fd, set_fd)) 969 1048 goto done; 970 1049 971 1050 ping_dev0(); ··· 1004 1083 get_fd = bpf_program__fd(skel->progs.ip6ip6_get_tunnel); 1005 1084 break; 1006 1085 } 1007 - if (generic_attach(IP6TNL_TUNL_DEV1, get_fd, set_fd)) 1086 + if (tc_prog_attach(IP6TNL_TUNL_DEV1, get_fd, set_fd)) 1008 1087 goto done; 1009 1088 1010 1089 ping6_veth0();
+41 -54
tools/testing/selftests/bpf/progs/test_tc_tunnel.c
··· 2 2 3 3 /* In-place tunneling */ 4 4 5 - #include <stdbool.h> 6 - #include <string.h> 5 + #include <vmlinux.h> 7 6 8 - #include <linux/stddef.h> 9 - #include <linux/bpf.h> 10 - #include <linux/if_ether.h> 11 - #include <linux/in.h> 12 - #include <linux/ip.h> 13 - #include <linux/ipv6.h> 14 - #include <linux/mpls.h> 15 - #include <linux/tcp.h> 16 - #include <linux/udp.h> 17 - #include <linux/pkt_cls.h> 18 - #include <linux/types.h> 19 - 20 - #include <bpf/bpf_endian.h> 21 7 #include <bpf/bpf_helpers.h> 8 + #include <bpf/bpf_endian.h> 9 + #include "bpf_tracing_net.h" 22 10 #include "bpf_compiler.h" 23 11 24 12 #pragma GCC diagnostic ignored "-Waddress-of-packed-member" ··· 14 26 static const int cfg_port = 8000; 15 27 16 28 static const int cfg_udp_src = 20000; 29 + 30 + #define ETH_P_MPLS_UC 0x8847 31 + #define ETH_P_TEB 0x6558 32 + 33 + #define MPLS_LS_S_MASK 0x00000100 34 + #define BPF_F_ADJ_ROOM_ENCAP_L2(len) \ 35 + (((__u64)len & BPF_ADJ_ROOM_ENCAP_L2_MASK) \ 36 + << BPF_ADJ_ROOM_ENCAP_L2_SHIFT) 17 37 18 38 #define L2_PAD_SZ (sizeof(struct vxlanhdr) + ETH_HLEN) 19 39 ··· 32 36 33 37 #define EXTPROTO_VXLAN 0x1 34 38 35 - #define VXLAN_N_VID (1u << 24) 36 - #define VXLAN_VNI_MASK bpf_htonl((VXLAN_N_VID - 1) << 8) 37 - #define VXLAN_FLAGS 0x8 38 - #define VXLAN_VNI 1 39 + #define VXLAN_FLAGS bpf_htonl(1<<27) 40 + #define VNI_ID 1 41 + #define VXLAN_VNI bpf_htonl(VNI_ID << 8) 39 42 40 43 #ifndef NEXTHDR_DEST 41 44 #define NEXTHDR_DEST 60 ··· 43 48 /* MPLS label 1000 with S bit (last label) set and ttl of 255. */ 44 49 static const __u32 mpls_label = __bpf_constant_htonl(1000 << 12 | 45 50 MPLS_LS_S_MASK | 0xff); 46 - 47 - struct vxlanhdr { 48 - __be32 vx_flags; 49 - __be32 vx_vni; 50 - } __attribute__((packed)); 51 - 52 51 struct gre_hdr { 53 52 __be16 flags; 54 53 __be16 protocol; ··· 83 94 static __always_inline int __encap_ipv4(struct __sk_buff *skb, __u8 encap_proto, 84 95 __u16 l2_proto, __u16 ext_proto) 85 96 { 97 + struct iphdr iph_inner = {0}; 86 98 __u16 udp_dst = UDP_PORT; 87 - struct iphdr iph_inner; 88 99 struct v4hdr h_outer; 89 100 struct tcphdr tcph; 90 101 int olen, l2_len; ··· 111 122 return TC_ACT_OK; 112 123 113 124 /* Derive the IPv4 header fields from the IPv6 header */ 114 - memset(&iph_inner, 0, sizeof(iph_inner)); 115 125 iph_inner.version = 4; 116 126 iph_inner.ihl = 5; 117 127 iph_inner.tot_len = bpf_htons(sizeof(iph6_inner) + ··· 198 210 struct vxlanhdr *vxlan_hdr = (struct vxlanhdr *)l2_hdr; 199 211 200 212 vxlan_hdr->vx_flags = VXLAN_FLAGS; 201 - vxlan_hdr->vx_vni = bpf_htonl((VXLAN_VNI & VXLAN_VNI_MASK) << 8); 213 + vxlan_hdr->vx_vni = VXLAN_VNI; 202 214 203 215 l2_hdr += sizeof(struct vxlanhdr); 204 216 } ··· 328 340 struct vxlanhdr *vxlan_hdr = (struct vxlanhdr *)l2_hdr; 329 341 330 342 vxlan_hdr->vx_flags = VXLAN_FLAGS; 331 - vxlan_hdr->vx_vni = bpf_htonl((VXLAN_VNI & VXLAN_VNI_MASK) << 8); 343 + vxlan_hdr->vx_vni = VXLAN_VNI; 332 344 333 345 l2_hdr += sizeof(struct vxlanhdr); 334 346 } ··· 360 372 361 373 static int encap_ipv6_ipip6(struct __sk_buff *skb) 362 374 { 375 + struct v6hdr h_outer = {0}; 363 376 struct iphdr iph_inner; 364 - struct v6hdr h_outer; 365 377 struct tcphdr tcph; 366 378 struct ethhdr eth; 367 379 __u64 flags; ··· 388 400 return TC_ACT_SHOT; 389 401 390 402 /* prepare new outer network header */ 391 - memset(&h_outer.ip, 0, sizeof(h_outer.ip)); 392 403 h_outer.ip.version = 6; 393 404 h_outer.ip.hop_limit = iph_inner.ttl; 394 - h_outer.ip.saddr.s6_addr[1] = 0xfd; 395 - h_outer.ip.saddr.s6_addr[15] = 1; 396 - h_outer.ip.daddr.s6_addr[1] = 0xfd; 397 - h_outer.ip.daddr.s6_addr[15] = 2; 405 + h_outer.ip.saddr.in6_u.u6_addr8[1] = 0xfd; 406 + h_outer.ip.saddr.in6_u.u6_addr8[15] = 1; 407 + h_outer.ip.daddr.in6_u.u6_addr8[1] = 0xfd; 408 + h_outer.ip.daddr.in6_u.u6_addr8[15] = 2; 398 409 h_outer.ip.payload_len = iph_inner.tot_len; 399 410 h_outer.ip.nexthdr = IPPROTO_IPIP; 400 411 ··· 418 431 return __encap_ipv6(skb, encap_proto, l2_proto, 0); 419 432 } 420 433 421 - SEC("encap_ipip_none") 434 + SEC("tc") 422 435 int __encap_ipip_none(struct __sk_buff *skb) 423 436 { 424 437 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 427 440 return TC_ACT_OK; 428 441 } 429 442 430 - SEC("encap_gre_none") 443 + SEC("tc") 431 444 int __encap_gre_none(struct __sk_buff *skb) 432 445 { 433 446 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 436 449 return TC_ACT_OK; 437 450 } 438 451 439 - SEC("encap_gre_mpls") 452 + SEC("tc") 440 453 int __encap_gre_mpls(struct __sk_buff *skb) 441 454 { 442 455 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 445 458 return TC_ACT_OK; 446 459 } 447 460 448 - SEC("encap_gre_eth") 461 + SEC("tc") 449 462 int __encap_gre_eth(struct __sk_buff *skb) 450 463 { 451 464 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 454 467 return TC_ACT_OK; 455 468 } 456 469 457 - SEC("encap_udp_none") 470 + SEC("tc") 458 471 int __encap_udp_none(struct __sk_buff *skb) 459 472 { 460 473 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 463 476 return TC_ACT_OK; 464 477 } 465 478 466 - SEC("encap_udp_mpls") 479 + SEC("tc") 467 480 int __encap_udp_mpls(struct __sk_buff *skb) 468 481 { 469 482 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 472 485 return TC_ACT_OK; 473 486 } 474 487 475 - SEC("encap_udp_eth") 488 + SEC("tc") 476 489 int __encap_udp_eth(struct __sk_buff *skb) 477 490 { 478 491 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 481 494 return TC_ACT_OK; 482 495 } 483 496 484 - SEC("encap_vxlan_eth") 497 + SEC("tc") 485 498 int __encap_vxlan_eth(struct __sk_buff *skb) 486 499 { 487 500 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 492 505 return TC_ACT_OK; 493 506 } 494 507 495 - SEC("encap_sit_none") 508 + SEC("tc") 496 509 int __encap_sit_none(struct __sk_buff *skb) 497 510 { 498 511 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 501 514 return TC_ACT_OK; 502 515 } 503 516 504 - SEC("encap_ip6tnl_none") 517 + SEC("tc") 505 518 int __encap_ip6tnl_none(struct __sk_buff *skb) 506 519 { 507 520 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 510 523 return TC_ACT_OK; 511 524 } 512 525 513 - SEC("encap_ipip6_none") 526 + SEC("tc") 514 527 int __encap_ipip6_none(struct __sk_buff *skb) 515 528 { 516 529 if (skb->protocol == __bpf_constant_htons(ETH_P_IP)) ··· 519 532 return TC_ACT_OK; 520 533 } 521 534 522 - SEC("encap_ip6gre_none") 535 + SEC("tc") 523 536 int __encap_ip6gre_none(struct __sk_buff *skb) 524 537 { 525 538 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 528 541 return TC_ACT_OK; 529 542 } 530 543 531 - SEC("encap_ip6gre_mpls") 544 + SEC("tc") 532 545 int __encap_ip6gre_mpls(struct __sk_buff *skb) 533 546 { 534 547 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 537 550 return TC_ACT_OK; 538 551 } 539 552 540 - SEC("encap_ip6gre_eth") 553 + SEC("tc") 541 554 int __encap_ip6gre_eth(struct __sk_buff *skb) 542 555 { 543 556 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 546 559 return TC_ACT_OK; 547 560 } 548 561 549 - SEC("encap_ip6udp_none") 562 + SEC("tc") 550 563 int __encap_ip6udp_none(struct __sk_buff *skb) 551 564 { 552 565 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 555 568 return TC_ACT_OK; 556 569 } 557 570 558 - SEC("encap_ip6udp_mpls") 571 + SEC("tc") 559 572 int __encap_ip6udp_mpls(struct __sk_buff *skb) 560 573 { 561 574 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 564 577 return TC_ACT_OK; 565 578 } 566 579 567 - SEC("encap_ip6udp_eth") 580 + SEC("tc") 568 581 int __encap_ip6udp_eth(struct __sk_buff *skb) 569 582 { 570 583 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 573 586 return TC_ACT_OK; 574 587 } 575 588 576 - SEC("encap_ip6vxlan_eth") 589 + SEC("tc") 577 590 int __encap_ip6vxlan_eth(struct __sk_buff *skb) 578 591 { 579 592 if (skb->protocol == __bpf_constant_htons(ETH_P_IPV6)) ··· 680 693 iph_outer.nexthdr); 681 694 } 682 695 683 - SEC("decap") 696 + SEC("tc") 684 697 int decap_f(struct __sk_buff *skb) 685 698 { 686 699 switch (skb->protocol) {
-320
tools/testing/selftests/bpf/test_tc_tunnel.sh
··· 1 - #!/bin/bash 2 - # SPDX-License-Identifier: GPL-2.0 3 - # 4 - # In-place tunneling 5 - 6 - BPF_FILE="test_tc_tunnel.bpf.o" 7 - # must match the port that the bpf program filters on 8 - readonly port=8000 9 - 10 - readonly ns_prefix="ns-$$-" 11 - readonly ns1="${ns_prefix}1" 12 - readonly ns2="${ns_prefix}2" 13 - 14 - readonly ns1_v4=192.168.1.1 15 - readonly ns2_v4=192.168.1.2 16 - readonly ns1_v6=fd::1 17 - readonly ns2_v6=fd::2 18 - 19 - # Must match port used by bpf program 20 - readonly udpport=5555 21 - # MPLSoverUDP 22 - readonly mplsudpport=6635 23 - readonly mplsproto=137 24 - 25 - readonly infile="$(mktemp)" 26 - readonly outfile="$(mktemp)" 27 - 28 - setup() { 29 - ip netns add "${ns1}" 30 - ip netns add "${ns2}" 31 - 32 - ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \ 33 - peer name veth2 mtu 1500 netns "${ns2}" 34 - 35 - ip netns exec "${ns1}" ethtool -K veth1 tso off 36 - 37 - ip -netns "${ns1}" link set veth1 up 38 - ip -netns "${ns2}" link set veth2 up 39 - 40 - ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1 41 - ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2 42 - ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad 43 - ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad 44 - 45 - # clamp route to reserve room for tunnel headers 46 - ip -netns "${ns1}" -4 route flush table main 47 - ip -netns "${ns1}" -6 route flush table main 48 - ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1450 dev veth1 49 - ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1430 dev veth1 50 - 51 - sleep 1 52 - 53 - dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none 54 - } 55 - 56 - cleanup() { 57 - ip netns del "${ns2}" 58 - ip netns del "${ns1}" 59 - 60 - if [[ -f "${outfile}" ]]; then 61 - rm "${outfile}" 62 - fi 63 - if [[ -f "${infile}" ]]; then 64 - rm "${infile}" 65 - fi 66 - 67 - if [[ -n $server_pid ]]; then 68 - kill $server_pid 2> /dev/null 69 - fi 70 - } 71 - 72 - server_listen() { 73 - ip netns exec "${ns2}" nc "${netcat_opt}" -l "${port}" > "${outfile}" & 74 - server_pid=$! 75 - } 76 - 77 - client_connect() { 78 - ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}" 79 - echo $? 80 - } 81 - 82 - verify_data() { 83 - wait "${server_pid}" 84 - server_pid= 85 - # sha1sum returns two fields [sha1] [filepath] 86 - # convert to bash array and access first elem 87 - insum=($(sha1sum ${infile})) 88 - outsum=($(sha1sum ${outfile})) 89 - if [[ "${insum[0]}" != "${outsum[0]}" ]]; then 90 - echo "data mismatch" 91 - exit 1 92 - fi 93 - } 94 - 95 - wait_for_port() { 96 - for i in $(seq 20); do 97 - if ip netns exec "${ns2}" ss ${2:--4}OHntl | grep -q "$1"; then 98 - return 0 99 - fi 100 - sleep 0.1 101 - done 102 - return 1 103 - } 104 - 105 - set -e 106 - 107 - # no arguments: automated test, run all 108 - if [[ "$#" -eq "0" ]]; then 109 - echo "ipip" 110 - $0 ipv4 ipip none 100 111 - 112 - echo "ipip6" 113 - $0 ipv4 ipip6 none 100 114 - 115 - echo "ip6ip6" 116 - $0 ipv6 ip6tnl none 100 117 - 118 - echo "sit" 119 - $0 ipv6 sit none 100 120 - 121 - echo "ip4 vxlan" 122 - $0 ipv4 vxlan eth 2000 123 - 124 - echo "ip6 vxlan" 125 - $0 ipv6 ip6vxlan eth 2000 126 - 127 - for mac in none mpls eth ; do 128 - echo "ip gre $mac" 129 - $0 ipv4 gre $mac 100 130 - 131 - echo "ip6 gre $mac" 132 - $0 ipv6 ip6gre $mac 100 133 - 134 - echo "ip gre $mac gso" 135 - $0 ipv4 gre $mac 2000 136 - 137 - echo "ip6 gre $mac gso" 138 - $0 ipv6 ip6gre $mac 2000 139 - 140 - echo "ip udp $mac" 141 - $0 ipv4 udp $mac 100 142 - 143 - echo "ip6 udp $mac" 144 - $0 ipv6 ip6udp $mac 100 145 - 146 - echo "ip udp $mac gso" 147 - $0 ipv4 udp $mac 2000 148 - 149 - echo "ip6 udp $mac gso" 150 - $0 ipv6 ip6udp $mac 2000 151 - done 152 - 153 - echo "OK. All tests passed" 154 - exit 0 155 - fi 156 - 157 - if [[ "$#" -ne "4" ]]; then 158 - echo "Usage: $0" 159 - echo " or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>" 160 - exit 1 161 - fi 162 - 163 - case "$1" in 164 - "ipv4") 165 - readonly addr1="${ns1_v4}" 166 - readonly addr2="${ns2_v4}" 167 - readonly ipproto=4 168 - readonly netcat_opt=-${ipproto} 169 - readonly foumod=fou 170 - readonly foutype=ipip 171 - readonly fouproto=4 172 - readonly fouproto_mpls=${mplsproto} 173 - readonly gretaptype=gretap 174 - ;; 175 - "ipv6") 176 - readonly addr1="${ns1_v6}" 177 - readonly addr2="${ns2_v6}" 178 - readonly ipproto=6 179 - readonly netcat_opt=-${ipproto} 180 - readonly foumod=fou6 181 - readonly foutype=ip6tnl 182 - readonly fouproto="41 -6" 183 - readonly fouproto_mpls="${mplsproto} -6" 184 - readonly gretaptype=ip6gretap 185 - ;; 186 - *) 187 - echo "unknown arg: $1" 188 - exit 1 189 - ;; 190 - esac 191 - 192 - readonly tuntype=$2 193 - readonly mac=$3 194 - readonly datalen=$4 195 - 196 - echo "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}" 197 - 198 - trap cleanup EXIT 199 - 200 - setup 201 - 202 - # basic communication works 203 - echo "test basic connectivity" 204 - server_listen 205 - wait_for_port ${port} ${netcat_opt} 206 - client_connect 207 - verify_data 208 - 209 - # clientside, insert bpf program to encap all TCP to port ${port} 210 - # client can no longer connect 211 - ip netns exec "${ns1}" tc qdisc add dev veth1 clsact 212 - ip netns exec "${ns1}" tc filter add dev veth1 egress \ 213 - bpf direct-action object-file ${BPF_FILE} \ 214 - section "encap_${tuntype}_${mac}" 215 - echo "test bpf encap without decap (expect failure)" 216 - server_listen 217 - wait_for_port ${port} ${netcat_opt} 218 - ! client_connect 219 - 220 - if [[ "$tuntype" =~ "udp" ]]; then 221 - # Set up fou tunnel. 222 - ttype="${foutype}" 223 - targs="encap fou encap-sport auto encap-dport $udpport" 224 - # fou may be a module; allow this to fail. 225 - modprobe "${foumod}" ||true 226 - if [[ "$mac" == "mpls" ]]; then 227 - dport=${mplsudpport} 228 - dproto=${fouproto_mpls} 229 - tmode="mode any ttl 255" 230 - else 231 - dport=${udpport} 232 - dproto=${fouproto} 233 - fi 234 - ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto} 235 - targs="encap fou encap-sport auto encap-dport $dport" 236 - elif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then 237 - ttype=$gretaptype 238 - elif [[ "$tuntype" =~ "vxlan" && "$mac" == "eth" ]]; then 239 - ttype="vxlan" 240 - targs="id 1 dstport 8472 udp6zerocsumrx" 241 - elif [[ "$tuntype" == "ipip6" ]]; then 242 - ttype="ip6tnl" 243 - targs="" 244 - else 245 - ttype=$tuntype 246 - targs="" 247 - fi 248 - 249 - # tunnel address family differs from inner for SIT 250 - if [[ "${tuntype}" == "sit" ]]; then 251 - link_addr1="${ns1_v4}" 252 - link_addr2="${ns2_v4}" 253 - elif [[ "${tuntype}" == "ipip6" ]]; then 254 - link_addr1="${ns1_v6}" 255 - link_addr2="${ns2_v6}" 256 - else 257 - link_addr1="${addr1}" 258 - link_addr2="${addr2}" 259 - fi 260 - 261 - # serverside, insert decap module 262 - # server is still running 263 - # client can connect again 264 - ip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \ 265 - ${tmode} remote "${link_addr1}" local "${link_addr2}" $targs 266 - 267 - expect_tun_fail=0 268 - 269 - if [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then 270 - # No support for MPLS IPv6 fou tunnel; expect failure. 271 - expect_tun_fail=1 272 - elif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then 273 - # No support for TEB fou tunnel; expect failure. 274 - expect_tun_fail=1 275 - elif [[ "$tuntype" =~ (gre|vxlan) && "$mac" == "eth" ]]; then 276 - # Share ethernet address between tunnel/veth2 so L2 decap works. 277 - ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \ 278 - awk '/ether/ { print $2 }') 279 - ip netns exec "${ns2}" ip link set testtun0 address $ethaddr 280 - elif [[ "$mac" == "mpls" ]]; then 281 - modprobe mpls_iptunnel ||true 282 - modprobe mpls_gso ||true 283 - ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536 284 - ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo 285 - ip netns exec "${ns2}" ip link set lo up 286 - ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1 287 - ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0 288 - fi 289 - 290 - # Because packets are decapped by the tunnel they arrive on testtun0 from 291 - # the IP stack perspective. Ensure reverse path filtering is disabled 292 - # otherwise we drop the TCP SYN as arriving on testtun0 instead of the 293 - # expected veth2 (veth2 is where 192.168.1.2 is configured). 294 - ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0 295 - # rp needs to be disabled for both all and testtun0 as the rp value is 296 - # selected as the max of the "all" and device-specific values. 297 - ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0 298 - ip netns exec "${ns2}" ip link set dev testtun0 up 299 - if [[ "$expect_tun_fail" == 1 ]]; then 300 - # This tunnel mode is not supported, so we expect failure. 301 - echo "test bpf encap with tunnel device decap (expect failure)" 302 - ! client_connect 303 - else 304 - echo "test bpf encap with tunnel device decap" 305 - client_connect 306 - verify_data 307 - server_listen 308 - wait_for_port ${port} ${netcat_opt} 309 - fi 310 - 311 - # serverside, use BPF for decap 312 - ip netns exec "${ns2}" ip link del dev testtun0 313 - ip netns exec "${ns2}" tc qdisc add dev veth2 clsact 314 - ip netns exec "${ns2}" tc filter add dev veth2 ingress \ 315 - bpf direct-action object-file ${BPF_FILE} section decap 316 - echo "test bpf encap with bpf decap" 317 - client_connect 318 - verify_data 319 - 320 - echo OK