1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 3 /* 4 * This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link 5 * between src and dst. The netns fwd has veth links to each src and dst. The 6 * client is in src and server in dst. The test installs a TC BPF program to each 7 * host facing veth in fwd which calls into i) bpf_redirect_neigh() to perform the 8 * neigh addr population and redirect or ii) bpf_redirect_peer() for namespace 9 * switch from ingress side; it also installs a checker prog on the egress side 10 * to drop unexpected traffic. 11 */ 12 13 #define _GNU_SOURCE 14 15 #include <arpa/inet.h> 16 #include <linux/if.h> 17 #include <linux/if_tun.h> 18 #include <linux/limits.h> 19 #include <linux/sysctl.h> 20 #include <sched.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <sys/mount.h> 24 #include <sys/stat.h> 25 #include <unistd.h> 26 27 #include "test_progs.h" 28 #include "network_helpers.h" 29 #include "test_tc_neigh_fib.skel.h" 30 #include "test_tc_neigh.skel.h" 31 #include "test_tc_peer.skel.h" 32 33 #define NS_SRC "ns_src" 34 #define NS_FWD "ns_fwd" 35 #define NS_DST "ns_dst" 36 37 #define IP4_SRC "172.16.1.100" 38 #define IP4_DST "172.16.2.100" 39 #define IP4_TUN_SRC "172.17.1.100" 40 #define IP4_TUN_FWD "172.17.1.200" 41 #define IP4_PORT 9004 42 43 #define IP6_SRC "0::1:dead:beef:cafe" 44 #define IP6_DST "0::2:dead:beef:cafe" 45 #define IP6_TUN_SRC "1::1:dead:beef:cafe" 46 #define IP6_TUN_FWD "1::2:dead:beef:cafe" 47 #define IP6_PORT 9006 48 49 #define IP4_SLL "169.254.0.1" 50 #define IP4_DLL "169.254.0.2" 51 #define IP4_NET "169.254.0.0" 52 53 #define MAC_DST_FWD "00:11:22:33:44:55" 54 #define MAC_DST "00:22:33:44:55:66" 55 56 #define IFADDR_STR_LEN 18 57 #define PING_ARGS "-i 0.2 -c 3 -w 10 -q" 58 59 #define SRC_PROG_PIN_FILE "/sys/fs/bpf/test_tc_src" 60 #define DST_PROG_PIN_FILE "/sys/fs/bpf/test_tc_dst" 61 #define CHK_PROG_PIN_FILE "/sys/fs/bpf/test_tc_chk" 62 63 #define TIMEOUT_MILLIS 10000 64 65 #define log_err(MSG, ...) \ 66 fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ 67 __FILE__, __LINE__, strerror(errno), ##__VA_ARGS__) 68 69 static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST, NULL}; 70 71 static int write_file(const char *path, const char *newval) 72 { 73 FILE *f; 74 75 f = fopen(path, "r+"); 76 if (!f) 77 return -1; 78 if (fwrite(newval, strlen(newval), 1, f) != 1) { 79 log_err("writing to %s failed", path); 80 fclose(f); 81 return -1; 82 } 83 fclose(f); 84 return 0; 85 } 86 87 struct nstoken { 88 int orig_netns_fd; 89 }; 90 91 static int setns_by_fd(int nsfd) 92 { 93 int err; 94 95 err = setns(nsfd, CLONE_NEWNET); 96 close(nsfd); 97 98 if (!ASSERT_OK(err, "setns")) 99 return err; 100 101 /* Switch /sys to the new namespace so that e.g. /sys/class/net 102 * reflects the devices in the new namespace. 103 */ 104 err = unshare(CLONE_NEWNS); 105 if (!ASSERT_OK(err, "unshare")) 106 return err; 107 108 /* Make our /sys mount private, so the following umount won't 109 * trigger the global umount in case it's shared. 110 */ 111 err = mount("none", "/sys", NULL, MS_PRIVATE, NULL); 112 if (!ASSERT_OK(err, "remount private /sys")) 113 return err; 114 115 err = umount2("/sys", MNT_DETACH); 116 if (!ASSERT_OK(err, "umount2 /sys")) 117 return err; 118 119 err = mount("sysfs", "/sys", "sysfs", 0, NULL); 120 if (!ASSERT_OK(err, "mount /sys")) 121 return err; 122 123 err = mount("bpffs", "/sys/fs/bpf", "bpf", 0, NULL); 124 if (!ASSERT_OK(err, "mount /sys/fs/bpf")) 125 return err; 126 127 return 0; 128 } 129 130 /** 131 * open_netns() - Switch to specified network namespace by name. 132 * 133 * Returns token with which to restore the original namespace 134 * using close_netns(). 135 */ 136 static struct nstoken *open_netns(const char *name) 137 { 138 int nsfd; 139 char nspath[PATH_MAX]; 140 int err; 141 struct nstoken *token; 142 143 token = malloc(sizeof(struct nstoken)); 144 if (!ASSERT_OK_PTR(token, "malloc token")) 145 return NULL; 146 147 token->orig_netns_fd = open("/proc/self/ns/net", O_RDONLY); 148 if (!ASSERT_GE(token->orig_netns_fd, 0, "open /proc/self/ns/net")) 149 goto fail; 150 151 snprintf(nspath, sizeof(nspath), "%s/%s", "/var/run/netns", name); 152 nsfd = open(nspath, O_RDONLY | O_CLOEXEC); 153 if (!ASSERT_GE(nsfd, 0, "open netns fd")) 154 goto fail; 155 156 err = setns_by_fd(nsfd); 157 if (!ASSERT_OK(err, "setns_by_fd")) 158 goto fail; 159 160 return token; 161 fail: 162 free(token); 163 return NULL; 164 } 165 166 static void close_netns(struct nstoken *token) 167 { 168 ASSERT_OK(setns_by_fd(token->orig_netns_fd), "setns_by_fd"); 169 free(token); 170 } 171 172 static int netns_setup_namespaces(const char *verb) 173 { 174 const char * const *ns = namespaces; 175 char cmd[128]; 176 177 while (*ns) { 178 snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb, *ns); 179 if (!ASSERT_OK(system(cmd), cmd)) 180 return -1; 181 ns++; 182 } 183 return 0; 184 } 185 186 static void netns_setup_namespaces_nofail(const char *verb) 187 { 188 const char * const *ns = namespaces; 189 char cmd[128]; 190 191 while (*ns) { 192 snprintf(cmd, sizeof(cmd), "ip netns %s %s > /dev/null 2>&1", verb, *ns); 193 system(cmd); 194 ns++; 195 } 196 } 197 198 struct netns_setup_result { 199 int ifindex_veth_src_fwd; 200 int ifindex_veth_dst_fwd; 201 }; 202 203 static int get_ifaddr(const char *name, char *ifaddr) 204 { 205 char path[PATH_MAX]; 206 FILE *f; 207 int ret; 208 209 snprintf(path, PATH_MAX, "/sys/class/net/%s/address", name); 210 f = fopen(path, "r"); 211 if (!ASSERT_OK_PTR(f, path)) 212 return -1; 213 214 ret = fread(ifaddr, 1, IFADDR_STR_LEN, f); 215 if (!ASSERT_EQ(ret, IFADDR_STR_LEN, "fread ifaddr")) { 216 fclose(f); 217 return -1; 218 } 219 fclose(f); 220 return 0; 221 } 222 223 static int get_ifindex(const char *name) 224 { 225 char path[PATH_MAX]; 226 char buf[32]; 227 FILE *f; 228 int ret; 229 230 snprintf(path, PATH_MAX, "/sys/class/net/%s/ifindex", name); 231 f = fopen(path, "r"); 232 if (!ASSERT_OK_PTR(f, path)) 233 return -1; 234 235 ret = fread(buf, 1, sizeof(buf), f); 236 if (!ASSERT_GT(ret, 0, "fread ifindex")) { 237 fclose(f); 238 return -1; 239 } 240 fclose(f); 241 return atoi(buf); 242 } 243 244 #define SYS(fmt, ...) \ 245 ({ \ 246 char cmd[1024]; \ 247 snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ 248 if (!ASSERT_OK(system(cmd), cmd)) \ 249 goto fail; \ 250 }) 251 252 static int netns_setup_links_and_routes(struct netns_setup_result *result) 253 { 254 struct nstoken *nstoken = NULL; 255 char veth_src_fwd_addr[IFADDR_STR_LEN+1] = {}; 256 257 SYS("ip link add veth_src type veth peer name veth_src_fwd"); 258 SYS("ip link add veth_dst type veth peer name veth_dst_fwd"); 259 260 SYS("ip link set veth_dst_fwd address " MAC_DST_FWD); 261 SYS("ip link set veth_dst address " MAC_DST); 262 263 if (get_ifaddr("veth_src_fwd", veth_src_fwd_addr)) 264 goto fail; 265 266 result->ifindex_veth_src_fwd = get_ifindex("veth_src_fwd"); 267 if (result->ifindex_veth_src_fwd < 0) 268 goto fail; 269 result->ifindex_veth_dst_fwd = get_ifindex("veth_dst_fwd"); 270 if (result->ifindex_veth_dst_fwd < 0) 271 goto fail; 272 273 SYS("ip link set veth_src netns " NS_SRC); 274 SYS("ip link set veth_src_fwd netns " NS_FWD); 275 SYS("ip link set veth_dst_fwd netns " NS_FWD); 276 SYS("ip link set veth_dst netns " NS_DST); 277 278 /** setup in 'src' namespace */ 279 nstoken = open_netns(NS_SRC); 280 if (!ASSERT_OK_PTR(nstoken, "setns src")) 281 goto fail; 282 283 SYS("ip addr add " IP4_SRC "/32 dev veth_src"); 284 SYS("ip addr add " IP6_SRC "/128 dev veth_src nodad"); 285 SYS("ip link set dev veth_src up"); 286 287 SYS("ip route add " IP4_DST "/32 dev veth_src scope global"); 288 SYS("ip route add " IP4_NET "/16 dev veth_src scope global"); 289 SYS("ip route add " IP6_DST "/128 dev veth_src scope global"); 290 291 SYS("ip neigh add " IP4_DST " dev veth_src lladdr %s", 292 veth_src_fwd_addr); 293 SYS("ip neigh add " IP6_DST " dev veth_src lladdr %s", 294 veth_src_fwd_addr); 295 296 close_netns(nstoken); 297 298 /** setup in 'fwd' namespace */ 299 nstoken = open_netns(NS_FWD); 300 if (!ASSERT_OK_PTR(nstoken, "setns fwd")) 301 goto fail; 302 303 /* The fwd netns automatically gets a v6 LL address / routes, but also 304 * needs v4 one in order to start ARP probing. IP4_NET route is added 305 * to the endpoints so that the ARP processing will reply. 306 */ 307 SYS("ip addr add " IP4_SLL "/32 dev veth_src_fwd"); 308 SYS("ip addr add " IP4_DLL "/32 dev veth_dst_fwd"); 309 SYS("ip link set dev veth_src_fwd up"); 310 SYS("ip link set dev veth_dst_fwd up"); 311 312 SYS("ip route add " IP4_SRC "/32 dev veth_src_fwd scope global"); 313 SYS("ip route add " IP6_SRC "/128 dev veth_src_fwd scope global"); 314 SYS("ip route add " IP4_DST "/32 dev veth_dst_fwd scope global"); 315 SYS("ip route add " IP6_DST "/128 dev veth_dst_fwd scope global"); 316 317 close_netns(nstoken); 318 319 /** setup in 'dst' namespace */ 320 nstoken = open_netns(NS_DST); 321 if (!ASSERT_OK_PTR(nstoken, "setns dst")) 322 goto fail; 323 324 SYS("ip addr add " IP4_DST "/32 dev veth_dst"); 325 SYS("ip addr add " IP6_DST "/128 dev veth_dst nodad"); 326 SYS("ip link set dev veth_dst up"); 327 328 SYS("ip route add " IP4_SRC "/32 dev veth_dst scope global"); 329 SYS("ip route add " IP4_NET "/16 dev veth_dst scope global"); 330 SYS("ip route add " IP6_SRC "/128 dev veth_dst scope global"); 331 332 SYS("ip neigh add " IP4_SRC " dev veth_dst lladdr " MAC_DST_FWD); 333 SYS("ip neigh add " IP6_SRC " dev veth_dst lladdr " MAC_DST_FWD); 334 335 close_netns(nstoken); 336 337 return 0; 338 fail: 339 if (nstoken) 340 close_netns(nstoken); 341 return -1; 342 } 343 344 static int netns_load_bpf(void) 345 { 346 SYS("tc qdisc add dev veth_src_fwd clsact"); 347 SYS("tc filter add dev veth_src_fwd ingress bpf da object-pinned " 348 SRC_PROG_PIN_FILE); 349 SYS("tc filter add dev veth_src_fwd egress bpf da object-pinned " 350 CHK_PROG_PIN_FILE); 351 352 SYS("tc qdisc add dev veth_dst_fwd clsact"); 353 SYS("tc filter add dev veth_dst_fwd ingress bpf da object-pinned " 354 DST_PROG_PIN_FILE); 355 SYS("tc filter add dev veth_dst_fwd egress bpf da object-pinned " 356 CHK_PROG_PIN_FILE); 357 358 return 0; 359 fail: 360 return -1; 361 } 362 363 static void test_tcp(int family, const char *addr, __u16 port) 364 { 365 int listen_fd = -1, accept_fd = -1, client_fd = -1; 366 char buf[] = "testing testing"; 367 int n; 368 struct nstoken *nstoken; 369 370 nstoken = open_netns(NS_DST); 371 if (!ASSERT_OK_PTR(nstoken, "setns dst")) 372 return; 373 374 listen_fd = start_server(family, SOCK_STREAM, addr, port, 0); 375 if (!ASSERT_GE(listen_fd, 0, "listen")) 376 goto done; 377 378 close_netns(nstoken); 379 nstoken = open_netns(NS_SRC); 380 if (!ASSERT_OK_PTR(nstoken, "setns src")) 381 goto done; 382 383 client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS); 384 if (!ASSERT_GE(client_fd, 0, "connect_to_fd")) 385 goto done; 386 387 accept_fd = accept(listen_fd, NULL, NULL); 388 if (!ASSERT_GE(accept_fd, 0, "accept")) 389 goto done; 390 391 if (!ASSERT_OK(settimeo(accept_fd, TIMEOUT_MILLIS), "settimeo")) 392 goto done; 393 394 n = write(client_fd, buf, sizeof(buf)); 395 if (!ASSERT_EQ(n, sizeof(buf), "send to server")) 396 goto done; 397 398 n = read(accept_fd, buf, sizeof(buf)); 399 ASSERT_EQ(n, sizeof(buf), "recv from server"); 400 401 done: 402 if (nstoken) 403 close_netns(nstoken); 404 if (listen_fd >= 0) 405 close(listen_fd); 406 if (accept_fd >= 0) 407 close(accept_fd); 408 if (client_fd >= 0) 409 close(client_fd); 410 } 411 412 static int test_ping(int family, const char *addr) 413 { 414 SYS("ip netns exec " NS_SRC " %s " PING_ARGS " %s > /dev/null", ping_command(family), addr); 415 return 0; 416 fail: 417 return -1; 418 } 419 420 static void test_connectivity(void) 421 { 422 test_tcp(AF_INET, IP4_DST, IP4_PORT); 423 test_ping(AF_INET, IP4_DST); 424 test_tcp(AF_INET6, IP6_DST, IP6_PORT); 425 test_ping(AF_INET6, IP6_DST); 426 } 427 428 static int set_forwarding(bool enable) 429 { 430 int err; 431 432 err = write_file("/proc/sys/net/ipv4/ip_forward", enable ? "1" : "0"); 433 if (!ASSERT_OK(err, "set ipv4.ip_forward=0")) 434 return err; 435 436 err = write_file("/proc/sys/net/ipv6/conf/all/forwarding", enable ? "1" : "0"); 437 if (!ASSERT_OK(err, "set ipv6.forwarding=0")) 438 return err; 439 440 return 0; 441 } 442 443 static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result) 444 { 445 struct nstoken *nstoken = NULL; 446 struct test_tc_neigh_fib *skel = NULL; 447 int err; 448 449 nstoken = open_netns(NS_FWD); 450 if (!ASSERT_OK_PTR(nstoken, "setns fwd")) 451 return; 452 453 skel = test_tc_neigh_fib__open(); 454 if (!ASSERT_OK_PTR(skel, "test_tc_neigh_fib__open")) 455 goto done; 456 457 if (!ASSERT_OK(test_tc_neigh_fib__load(skel), "test_tc_neigh_fib__load")) 458 goto done; 459 460 err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); 461 if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) 462 goto done; 463 464 err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); 465 if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) 466 goto done; 467 468 err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); 469 if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) 470 goto done; 471 472 if (netns_load_bpf()) 473 goto done; 474 475 /* bpf_fib_lookup() checks if forwarding is enabled */ 476 if (!ASSERT_OK(set_forwarding(true), "enable forwarding")) 477 goto done; 478 479 test_connectivity(); 480 481 done: 482 if (skel) 483 test_tc_neigh_fib__destroy(skel); 484 close_netns(nstoken); 485 } 486 487 static void test_tc_redirect_neigh(struct netns_setup_result *setup_result) 488 { 489 struct nstoken *nstoken = NULL; 490 struct test_tc_neigh *skel = NULL; 491 int err; 492 493 nstoken = open_netns(NS_FWD); 494 if (!ASSERT_OK_PTR(nstoken, "setns fwd")) 495 return; 496 497 skel = test_tc_neigh__open(); 498 if (!ASSERT_OK_PTR(skel, "test_tc_neigh__open")) 499 goto done; 500 501 skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; 502 skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; 503 504 err = test_tc_neigh__load(skel); 505 if (!ASSERT_OK(err, "test_tc_neigh__load")) 506 goto done; 507 508 err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); 509 if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) 510 goto done; 511 512 err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); 513 if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) 514 goto done; 515 516 err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); 517 if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) 518 goto done; 519 520 if (netns_load_bpf()) 521 goto done; 522 523 if (!ASSERT_OK(set_forwarding(false), "disable forwarding")) 524 goto done; 525 526 test_connectivity(); 527 528 done: 529 if (skel) 530 test_tc_neigh__destroy(skel); 531 close_netns(nstoken); 532 } 533 534 static void test_tc_redirect_peer(struct netns_setup_result *setup_result) 535 { 536 struct nstoken *nstoken; 537 struct test_tc_peer *skel; 538 int err; 539 540 nstoken = open_netns(NS_FWD); 541 if (!ASSERT_OK_PTR(nstoken, "setns fwd")) 542 return; 543 544 skel = test_tc_peer__open(); 545 if (!ASSERT_OK_PTR(skel, "test_tc_peer__open")) 546 goto done; 547 548 skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; 549 skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; 550 551 err = test_tc_peer__load(skel); 552 if (!ASSERT_OK(err, "test_tc_peer__load")) 553 goto done; 554 555 err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); 556 if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) 557 goto done; 558 559 err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); 560 if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) 561 goto done; 562 563 err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); 564 if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) 565 goto done; 566 567 if (netns_load_bpf()) 568 goto done; 569 570 if (!ASSERT_OK(set_forwarding(false), "disable forwarding")) 571 goto done; 572 573 test_connectivity(); 574 575 done: 576 if (skel) 577 test_tc_peer__destroy(skel); 578 close_netns(nstoken); 579 } 580 581 static int tun_open(char *name) 582 { 583 struct ifreq ifr; 584 int fd, err; 585 586 fd = open("/dev/net/tun", O_RDWR); 587 if (!ASSERT_GE(fd, 0, "open /dev/net/tun")) 588 return -1; 589 590 memset(&ifr, 0, sizeof(ifr)); 591 592 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; 593 if (*name) 594 strncpy(ifr.ifr_name, name, IFNAMSIZ); 595 596 err = ioctl(fd, TUNSETIFF, &ifr); 597 if (!ASSERT_OK(err, "ioctl TUNSETIFF")) 598 goto fail; 599 600 SYS("ip link set dev %s up", name); 601 602 return fd; 603 fail: 604 close(fd); 605 return -1; 606 } 607 608 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 609 enum { 610 SRC_TO_TARGET = 0, 611 TARGET_TO_SRC = 1, 612 }; 613 614 static int tun_relay_loop(int src_fd, int target_fd) 615 { 616 fd_set rfds, wfds; 617 618 FD_ZERO(&rfds); 619 FD_ZERO(&wfds); 620 621 for (;;) { 622 char buf[1500]; 623 int direction, nread, nwrite; 624 625 FD_SET(src_fd, &rfds); 626 FD_SET(target_fd, &rfds); 627 628 if (select(1 + MAX(src_fd, target_fd), &rfds, NULL, NULL, NULL) < 0) { 629 log_err("select failed"); 630 return 1; 631 } 632 633 direction = FD_ISSET(src_fd, &rfds) ? SRC_TO_TARGET : TARGET_TO_SRC; 634 635 nread = read(direction == SRC_TO_TARGET ? src_fd : target_fd, buf, sizeof(buf)); 636 if (nread < 0) { 637 log_err("read failed"); 638 return 1; 639 } 640 641 nwrite = write(direction == SRC_TO_TARGET ? target_fd : src_fd, buf, nread); 642 if (nwrite != nread) { 643 log_err("write failed"); 644 return 1; 645 } 646 } 647 } 648 649 static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) 650 { 651 struct test_tc_peer *skel = NULL; 652 struct nstoken *nstoken = NULL; 653 int err; 654 int tunnel_pid = -1; 655 int src_fd, target_fd = -1; 656 int ifindex; 657 658 /* Start a L3 TUN/TAP tunnel between the src and dst namespaces. 659 * This test is using TUN/TAP instead of e.g. IPIP or GRE tunnel as those 660 * expose the L2 headers encapsulating the IP packet to BPF and hence 661 * don't have skb in suitable state for this test. Alternative to TUN/TAP 662 * would be e.g. Wireguard which would appear as a pure L3 device to BPF, 663 * but that requires much more complicated setup. 664 */ 665 nstoken = open_netns(NS_SRC); 666 if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC)) 667 return; 668 669 src_fd = tun_open("tun_src"); 670 if (!ASSERT_GE(src_fd, 0, "tun_open tun_src")) 671 goto fail; 672 673 close_netns(nstoken); 674 675 nstoken = open_netns(NS_FWD); 676 if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD)) 677 goto fail; 678 679 target_fd = tun_open("tun_fwd"); 680 if (!ASSERT_GE(target_fd, 0, "tun_open tun_fwd")) 681 goto fail; 682 683 tunnel_pid = fork(); 684 if (!ASSERT_GE(tunnel_pid, 0, "fork tun_relay_loop")) 685 goto fail; 686 687 if (tunnel_pid == 0) 688 exit(tun_relay_loop(src_fd, target_fd)); 689 690 skel = test_tc_peer__open(); 691 if (!ASSERT_OK_PTR(skel, "test_tc_peer__open")) 692 goto fail; 693 694 ifindex = get_ifindex("tun_fwd"); 695 if (!ASSERT_GE(ifindex, 0, "get_ifindex tun_fwd")) 696 goto fail; 697 698 skel->rodata->IFINDEX_SRC = ifindex; 699 skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; 700 701 err = test_tc_peer__load(skel); 702 if (!ASSERT_OK(err, "test_tc_peer__load")) 703 goto fail; 704 705 err = bpf_program__pin(skel->progs.tc_src_l3, SRC_PROG_PIN_FILE); 706 if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) 707 goto fail; 708 709 err = bpf_program__pin(skel->progs.tc_dst_l3, DST_PROG_PIN_FILE); 710 if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) 711 goto fail; 712 713 err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); 714 if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) 715 goto fail; 716 717 /* Load "tc_src_l3" to the tun_fwd interface to redirect packets 718 * towards dst, and "tc_dst" to redirect packets 719 * and "tc_chk" on veth_dst_fwd to drop non-redirected packets. 720 */ 721 SYS("tc qdisc add dev tun_fwd clsact"); 722 SYS("tc filter add dev tun_fwd ingress bpf da object-pinned " 723 SRC_PROG_PIN_FILE); 724 725 SYS("tc qdisc add dev veth_dst_fwd clsact"); 726 SYS("tc filter add dev veth_dst_fwd ingress bpf da object-pinned " 727 DST_PROG_PIN_FILE); 728 SYS("tc filter add dev veth_dst_fwd egress bpf da object-pinned " 729 CHK_PROG_PIN_FILE); 730 731 /* Setup route and neigh tables */ 732 SYS("ip -netns " NS_SRC " addr add dev tun_src " IP4_TUN_SRC "/24"); 733 SYS("ip -netns " NS_FWD " addr add dev tun_fwd " IP4_TUN_FWD "/24"); 734 735 SYS("ip -netns " NS_SRC " addr add dev tun_src " IP6_TUN_SRC "/64 nodad"); 736 SYS("ip -netns " NS_FWD " addr add dev tun_fwd " IP6_TUN_FWD "/64 nodad"); 737 738 SYS("ip -netns " NS_SRC " route del " IP4_DST "/32 dev veth_src scope global"); 739 SYS("ip -netns " NS_SRC " route add " IP4_DST "/32 via " IP4_TUN_FWD 740 " dev tun_src scope global"); 741 SYS("ip -netns " NS_DST " route add " IP4_TUN_SRC "/32 dev veth_dst scope global"); 742 SYS("ip -netns " NS_SRC " route del " IP6_DST "/128 dev veth_src scope global"); 743 SYS("ip -netns " NS_SRC " route add " IP6_DST "/128 via " IP6_TUN_FWD 744 " dev tun_src scope global"); 745 SYS("ip -netns " NS_DST " route add " IP6_TUN_SRC "/128 dev veth_dst scope global"); 746 747 SYS("ip -netns " NS_DST " neigh add " IP4_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD); 748 SYS("ip -netns " NS_DST " neigh add " IP6_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD); 749 750 if (!ASSERT_OK(set_forwarding(false), "disable forwarding")) 751 goto fail; 752 753 test_connectivity(); 754 755 fail: 756 if (tunnel_pid > 0) { 757 kill(tunnel_pid, SIGTERM); 758 waitpid(tunnel_pid, NULL, 0); 759 } 760 if (src_fd >= 0) 761 close(src_fd); 762 if (target_fd >= 0) 763 close(target_fd); 764 if (skel) 765 test_tc_peer__destroy(skel); 766 if (nstoken) 767 close_netns(nstoken); 768 } 769 770 #define RUN_TEST(name) \ 771 ({ \ 772 struct netns_setup_result setup_result; \ 773 if (test__start_subtest(#name)) \ 774 if (ASSERT_OK(netns_setup_namespaces("add"), "setup namespaces")) { \ 775 if (ASSERT_OK(netns_setup_links_and_routes(&setup_result), \ 776 "setup links and routes")) \ 777 test_ ## name(&setup_result); \ 778 netns_setup_namespaces("delete"); \ 779 } \ 780 }) 781 782 static void *test_tc_redirect_run_tests(void *arg) 783 { 784 netns_setup_namespaces_nofail("delete"); 785 786 RUN_TEST(tc_redirect_peer); 787 RUN_TEST(tc_redirect_peer_l3); 788 RUN_TEST(tc_redirect_neigh); 789 RUN_TEST(tc_redirect_neigh_fib); 790 return NULL; 791 } 792 793 void serial_test_tc_redirect(void) 794 { 795 pthread_t test_thread; 796 int err; 797 798 /* Run the tests in their own thread to isolate the namespace changes 799 * so they do not affect the environment of other tests. 800 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns()) 801 */ 802 err = pthread_create(&test_thread, NULL, &test_tc_redirect_run_tests, NULL); 803 if (ASSERT_OK(err, "pthread_create")) 804 ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join"); 805 } 806