1 // SPDX-License-Identifier: GPL-2.0 2 3 /** 4 * Test XDP bonding support 5 * 6 * Sets up two bonded veth pairs between two fresh namespaces 7 * and verifies that XDP_TX program loaded on a bond device 8 * are correctly loaded onto the slave devices and XDP_TX'd 9 * packets are balanced using bonding. 10 */ 11 12 #define _GNU_SOURCE 13 #include <sched.h> 14 #include <net/if.h> 15 #include <linux/if_link.h> 16 #include "test_progs.h" 17 #include "network_helpers.h" 18 #include <linux/if_bonding.h> 19 #include <linux/limits.h> 20 #include <linux/udp.h> 21 #include <uapi/linux/netdev.h> 22 23 #include "xdp_dummy.skel.h" 24 #include "xdp_redirect_multi_kern.skel.h" 25 #include "xdp_tx.skel.h" 26 27 #define BOND1_MAC {0x00, 0x11, 0x22, 0x33, 0x44, 0x55} 28 #define BOND1_MAC_STR "00:11:22:33:44:55" 29 #define BOND2_MAC {0x00, 0x22, 0x33, 0x44, 0x55, 0x66} 30 #define BOND2_MAC_STR "00:22:33:44:55:66" 31 #define NPACKETS 100 32 33 static int root_netns_fd = -1; 34 35 static void restore_root_netns(void) 36 { 37 ASSERT_OK(setns(root_netns_fd, CLONE_NEWNET), "restore_root_netns"); 38 } 39 40 static int setns_by_name(char *name) 41 { 42 int nsfd, err; 43 char nspath[PATH_MAX]; 44 45 snprintf(nspath, sizeof(nspath), "%s/%s", "/var/run/netns", name); 46 nsfd = open(nspath, O_RDONLY | O_CLOEXEC); 47 if (nsfd < 0) 48 return -1; 49 50 err = setns(nsfd, CLONE_NEWNET); 51 close(nsfd); 52 return err; 53 } 54 55 static int get_rx_packets(const char *iface) 56 { 57 FILE *f; 58 char line[512]; 59 int iface_len = strlen(iface); 60 61 f = fopen("/proc/net/dev", "r"); 62 if (!f) 63 return -1; 64 65 while (fgets(line, sizeof(line), f)) { 66 char *p = line; 67 68 while (*p == ' ') 69 p++; /* skip whitespace */ 70 if (!strncmp(p, iface, iface_len)) { 71 p += iface_len; 72 if (*p++ != ':') 73 continue; 74 while (*p == ' ') 75 p++; /* skip whitespace */ 76 while (*p && *p != ' ') 77 p++; /* skip rx bytes */ 78 while (*p == ' ') 79 p++; /* skip whitespace */ 80 fclose(f); 81 return atoi(p); 82 } 83 } 84 fclose(f); 85 return -1; 86 } 87 88 #define MAX_BPF_LINKS 8 89 90 struct skeletons { 91 struct xdp_dummy *xdp_dummy; 92 struct xdp_tx *xdp_tx; 93 struct xdp_redirect_multi_kern *xdp_redirect_multi_kern; 94 95 int nlinks; 96 struct bpf_link *links[MAX_BPF_LINKS]; 97 }; 98 99 static int xdp_attach(struct skeletons *skeletons, struct bpf_program *prog, char *iface) 100 { 101 struct bpf_link *link; 102 int ifindex; 103 104 ifindex = if_nametoindex(iface); 105 if (!ASSERT_GT(ifindex, 0, "get ifindex")) 106 return -1; 107 108 if (!ASSERT_LE(skeletons->nlinks+1, MAX_BPF_LINKS, "too many XDP programs attached")) 109 return -1; 110 111 link = bpf_program__attach_xdp(prog, ifindex); 112 if (!ASSERT_OK_PTR(link, "attach xdp program")) 113 return -1; 114 115 skeletons->links[skeletons->nlinks++] = link; 116 return 0; 117 } 118 119 enum { 120 BOND_ONE_NO_ATTACH = 0, 121 BOND_BOTH_AND_ATTACH, 122 }; 123 124 static const char * const mode_names[] = { 125 [BOND_MODE_ROUNDROBIN] = "balance-rr", 126 [BOND_MODE_ACTIVEBACKUP] = "active-backup", 127 [BOND_MODE_XOR] = "balance-xor", 128 [BOND_MODE_BROADCAST] = "broadcast", 129 [BOND_MODE_8023AD] = "802.3ad", 130 [BOND_MODE_TLB] = "balance-tlb", 131 [BOND_MODE_ALB] = "balance-alb", 132 }; 133 134 static const char * const xmit_policy_names[] = { 135 [BOND_XMIT_POLICY_LAYER2] = "layer2", 136 [BOND_XMIT_POLICY_LAYER34] = "layer3+4", 137 [BOND_XMIT_POLICY_LAYER23] = "layer2+3", 138 [BOND_XMIT_POLICY_ENCAP23] = "encap2+3", 139 [BOND_XMIT_POLICY_ENCAP34] = "encap3+4", 140 }; 141 142 static int bonding_setup(struct skeletons *skeletons, int mode, int xmit_policy, 143 int bond_both_attach) 144 { 145 SYS(fail, "ip netns add ns_dst"); 146 SYS(fail, "ip link add veth1_1 type veth peer name veth2_1 netns ns_dst"); 147 SYS(fail, "ip link add veth1_2 type veth peer name veth2_2 netns ns_dst"); 148 149 SYS(fail, "ip link add bond1 type bond mode %s xmit_hash_policy %s", 150 mode_names[mode], xmit_policy_names[xmit_policy]); 151 SYS(fail, "ip link set bond1 up address " BOND1_MAC_STR " addrgenmode none"); 152 SYS(fail, "ip -netns ns_dst link add bond2 type bond mode %s xmit_hash_policy %s", 153 mode_names[mode], xmit_policy_names[xmit_policy]); 154 SYS(fail, "ip -netns ns_dst link set bond2 up address " BOND2_MAC_STR " addrgenmode none"); 155 156 SYS(fail, "ip link set veth1_1 master bond1"); 157 if (bond_both_attach == BOND_BOTH_AND_ATTACH) { 158 SYS(fail, "ip link set veth1_2 master bond1"); 159 } else { 160 SYS(fail, "ip link set veth1_2 up addrgenmode none"); 161 162 if (xdp_attach(skeletons, skeletons->xdp_dummy->progs.xdp_dummy_prog, "veth1_2")) 163 return -1; 164 } 165 166 SYS(fail, "ip -netns ns_dst link set veth2_1 master bond2"); 167 168 if (bond_both_attach == BOND_BOTH_AND_ATTACH) 169 SYS(fail, "ip -netns ns_dst link set veth2_2 master bond2"); 170 else 171 SYS(fail, "ip -netns ns_dst link set veth2_2 up addrgenmode none"); 172 173 /* Load a dummy program on sending side as with veth peer needs to have a 174 * XDP program loaded as well. 175 */ 176 if (xdp_attach(skeletons, skeletons->xdp_dummy->progs.xdp_dummy_prog, "bond1")) 177 return -1; 178 179 if (bond_both_attach == BOND_BOTH_AND_ATTACH) { 180 if (!ASSERT_OK(setns_by_name("ns_dst"), "set netns to ns_dst")) 181 return -1; 182 183 if (xdp_attach(skeletons, skeletons->xdp_tx->progs.xdp_tx, "bond2")) 184 return -1; 185 186 restore_root_netns(); 187 } 188 189 return 0; 190 fail: 191 return -1; 192 } 193 194 static void bonding_cleanup(struct skeletons *skeletons) 195 { 196 restore_root_netns(); 197 while (skeletons->nlinks) { 198 skeletons->nlinks--; 199 bpf_link__destroy(skeletons->links[skeletons->nlinks]); 200 } 201 ASSERT_OK(system("ip link delete bond1"), "delete bond1"); 202 ASSERT_OK(system("ip link delete veth1_1"), "delete veth1_1"); 203 ASSERT_OK(system("ip link delete veth1_2"), "delete veth1_2"); 204 ASSERT_OK(system("ip netns delete ns_dst"), "delete ns_dst"); 205 } 206 207 static int send_udp_packets(int vary_dst_ip) 208 { 209 struct ethhdr eh = { 210 .h_source = BOND1_MAC, 211 .h_dest = BOND2_MAC, 212 .h_proto = htons(ETH_P_IP), 213 }; 214 struct iphdr iph = {}; 215 struct udphdr uh = {}; 216 uint8_t buf[128]; 217 int i, s = -1; 218 int ifindex; 219 220 s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 221 if (!ASSERT_GE(s, 0, "socket")) 222 goto err; 223 224 ifindex = if_nametoindex("bond1"); 225 if (!ASSERT_GT(ifindex, 0, "get bond1 ifindex")) 226 goto err; 227 228 iph.ihl = 5; 229 iph.version = 4; 230 iph.tos = 16; 231 iph.id = 1; 232 iph.ttl = 64; 233 iph.protocol = IPPROTO_UDP; 234 iph.saddr = 1; 235 iph.daddr = 2; 236 iph.tot_len = htons(sizeof(buf) - ETH_HLEN); 237 iph.check = 0; 238 239 for (i = 1; i <= NPACKETS; i++) { 240 int n; 241 struct sockaddr_ll saddr_ll = { 242 .sll_ifindex = ifindex, 243 .sll_halen = ETH_ALEN, 244 .sll_addr = BOND2_MAC, 245 }; 246 247 /* vary the UDP destination port for even distribution with roundrobin/xor modes */ 248 uh.dest++; 249 250 if (vary_dst_ip) 251 iph.daddr++; 252 253 /* construct a packet */ 254 memcpy(buf, &eh, sizeof(eh)); 255 memcpy(buf + sizeof(eh), &iph, sizeof(iph)); 256 memcpy(buf + sizeof(eh) + sizeof(iph), &uh, sizeof(uh)); 257 258 n = sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&saddr_ll, sizeof(saddr_ll)); 259 if (!ASSERT_EQ(n, sizeof(buf), "sendto")) 260 goto err; 261 } 262 263 return 0; 264 265 err: 266 if (s >= 0) 267 close(s); 268 return -1; 269 } 270 271 static void test_xdp_bonding_with_mode(struct skeletons *skeletons, int mode, int xmit_policy) 272 { 273 int bond1_rx; 274 275 if (bonding_setup(skeletons, mode, xmit_policy, BOND_BOTH_AND_ATTACH)) 276 goto out; 277 278 if (send_udp_packets(xmit_policy != BOND_XMIT_POLICY_LAYER34)) 279 goto out; 280 281 bond1_rx = get_rx_packets("bond1"); 282 ASSERT_EQ(bond1_rx, NPACKETS, "expected more received packets"); 283 284 switch (mode) { 285 case BOND_MODE_ROUNDROBIN: 286 case BOND_MODE_XOR: { 287 int veth1_rx = get_rx_packets("veth1_1"); 288 int veth2_rx = get_rx_packets("veth1_2"); 289 int diff = abs(veth1_rx - veth2_rx); 290 291 ASSERT_GE(veth1_rx + veth2_rx, NPACKETS, "expected more packets"); 292 293 switch (xmit_policy) { 294 case BOND_XMIT_POLICY_LAYER2: 295 ASSERT_GE(diff, NPACKETS, 296 "expected packets on only one of the interfaces"); 297 break; 298 case BOND_XMIT_POLICY_LAYER23: 299 case BOND_XMIT_POLICY_LAYER34: 300 ASSERT_LT(diff, NPACKETS/2, 301 "expected even distribution of packets"); 302 break; 303 default: 304 PRINT_FAIL("Unimplemented xmit_policy=%d\n", xmit_policy); 305 break; 306 } 307 break; 308 } 309 case BOND_MODE_ACTIVEBACKUP: { 310 int veth1_rx = get_rx_packets("veth1_1"); 311 int veth2_rx = get_rx_packets("veth1_2"); 312 int diff = abs(veth1_rx - veth2_rx); 313 314 ASSERT_GE(diff, NPACKETS, 315 "expected packets on only one of the interfaces"); 316 break; 317 } 318 default: 319 PRINT_FAIL("Unimplemented xmit_policy=%d\n", xmit_policy); 320 break; 321 } 322 323 out: 324 bonding_cleanup(skeletons); 325 } 326 327 /* Test the broadcast redirection using xdp_redirect_map_multi_prog and adding 328 * all the interfaces to it and checking that broadcasting won't send the packet 329 * to neither the ingress bond device (bond2) or its slave (veth2_1). 330 */ 331 static void test_xdp_bonding_redirect_multi(struct skeletons *skeletons) 332 { 333 static const char * const ifaces[] = {"bond2", "veth2_1", "veth2_2"}; 334 int veth1_1_rx, veth1_2_rx; 335 int err; 336 337 if (bonding_setup(skeletons, BOND_MODE_ROUNDROBIN, BOND_XMIT_POLICY_LAYER23, 338 BOND_ONE_NO_ATTACH)) 339 goto out; 340 341 342 if (!ASSERT_OK(setns_by_name("ns_dst"), "could not set netns to ns_dst")) 343 goto out; 344 345 /* populate the devmap with the relevant interfaces */ 346 for (int i = 0; i < ARRAY_SIZE(ifaces); i++) { 347 int ifindex = if_nametoindex(ifaces[i]); 348 int map_fd = bpf_map__fd(skeletons->xdp_redirect_multi_kern->maps.map_all); 349 350 if (!ASSERT_GT(ifindex, 0, "could not get interface index")) 351 goto out; 352 353 err = bpf_map_update_elem(map_fd, &ifindex, &ifindex, 0); 354 if (!ASSERT_OK(err, "add interface to map_all")) 355 goto out; 356 } 357 358 if (xdp_attach(skeletons, 359 skeletons->xdp_redirect_multi_kern->progs.xdp_redirect_map_multi_prog, 360 "bond2")) 361 goto out; 362 363 restore_root_netns(); 364 365 if (send_udp_packets(BOND_MODE_ROUNDROBIN)) 366 goto out; 367 368 veth1_1_rx = get_rx_packets("veth1_1"); 369 veth1_2_rx = get_rx_packets("veth1_2"); 370 371 ASSERT_EQ(veth1_1_rx, 0, "expected no packets on veth1_1"); 372 ASSERT_GE(veth1_2_rx, NPACKETS, "expected packets on veth1_2"); 373 374 out: 375 restore_root_netns(); 376 bonding_cleanup(skeletons); 377 } 378 379 /* Test that XDP programs cannot be attached to both the bond master and slaves simultaneously */ 380 static void test_xdp_bonding_attach(struct skeletons *skeletons) 381 { 382 struct bpf_link *link = NULL; 383 struct bpf_link *link2 = NULL; 384 int veth, bond, err; 385 386 if (!ASSERT_OK(system("ip link add veth type veth"), "add veth")) 387 goto out; 388 if (!ASSERT_OK(system("ip link add bond type bond"), "add bond")) 389 goto out; 390 391 veth = if_nametoindex("veth"); 392 if (!ASSERT_GE(veth, 0, "if_nametoindex veth")) 393 goto out; 394 bond = if_nametoindex("bond"); 395 if (!ASSERT_GE(bond, 0, "if_nametoindex bond")) 396 goto out; 397 398 /* enslaving with a XDP program loaded is allowed */ 399 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, veth); 400 if (!ASSERT_OK_PTR(link, "attach program to veth")) 401 goto out; 402 403 err = system("ip link set veth master bond"); 404 if (!ASSERT_OK(err, "set veth master")) 405 goto out; 406 407 bpf_link__destroy(link); 408 link = NULL; 409 410 /* attaching to slave when master has no program is allowed */ 411 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, veth); 412 if (!ASSERT_OK_PTR(link, "attach program to slave when enslaved")) 413 goto out; 414 415 /* attaching to master not allowed when slave has program loaded */ 416 link2 = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, bond); 417 if (!ASSERT_ERR_PTR(link2, "attach program to master when slave has program")) 418 goto out; 419 420 bpf_link__destroy(link); 421 link = NULL; 422 423 /* attaching XDP program to master allowed when slave has no program */ 424 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, bond); 425 if (!ASSERT_OK_PTR(link, "attach program to master")) 426 goto out; 427 428 /* attaching to slave not allowed when master has program loaded */ 429 link2 = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, veth); 430 if (!ASSERT_ERR_PTR(link2, "attach program to slave when master has program")) 431 goto out; 432 433 bpf_link__destroy(link); 434 link = NULL; 435 436 /* test program unwinding with a non-XDP slave */ 437 if (!ASSERT_OK(system("ip link add vxlan type vxlan id 1 remote 1.2.3.4 dstport 0 dev lo"), 438 "add vxlan")) 439 goto out; 440 441 err = system("ip link set vxlan master bond"); 442 if (!ASSERT_OK(err, "set vxlan master")) 443 goto out; 444 445 /* attaching not allowed when one slave does not support XDP */ 446 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, bond); 447 if (!ASSERT_ERR_PTR(link, "attach program to master when slave does not support XDP")) 448 goto out; 449 450 out: 451 bpf_link__destroy(link); 452 bpf_link__destroy(link2); 453 454 system("ip link del veth"); 455 system("ip link del bond"); 456 system("ip link del vxlan"); 457 } 458 459 /* Test with nested bonding devices to catch issue with negative jump label count */ 460 static void test_xdp_bonding_nested(struct skeletons *skeletons) 461 { 462 struct bpf_link *link = NULL; 463 int bond, err; 464 465 if (!ASSERT_OK(system("ip link add bond type bond"), "add bond")) 466 goto out; 467 468 bond = if_nametoindex("bond"); 469 if (!ASSERT_GE(bond, 0, "if_nametoindex bond")) 470 goto out; 471 472 if (!ASSERT_OK(system("ip link add bond_nest1 type bond"), "add bond_nest1")) 473 goto out; 474 475 err = system("ip link set bond_nest1 master bond"); 476 if (!ASSERT_OK(err, "set bond_nest1 master")) 477 goto out; 478 479 if (!ASSERT_OK(system("ip link add bond_nest2 type bond"), "add bond_nest1")) 480 goto out; 481 482 err = system("ip link set bond_nest2 master bond_nest1"); 483 if (!ASSERT_OK(err, "set bond_nest2 master")) 484 goto out; 485 486 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, bond); 487 ASSERT_OK_PTR(link, "attach program to master"); 488 489 out: 490 bpf_link__destroy(link); 491 system("ip link del bond"); 492 system("ip link del bond_nest1"); 493 system("ip link del bond_nest2"); 494 } 495 496 static void test_xdp_bonding_features(struct skeletons *skeletons) 497 { 498 LIBBPF_OPTS(bpf_xdp_query_opts, query_opts); 499 int bond_idx, veth1_idx, err; 500 struct bpf_link *link = NULL; 501 502 if (!ASSERT_OK(system("ip link add bond type bond"), "add bond")) 503 goto out; 504 505 bond_idx = if_nametoindex("bond"); 506 if (!ASSERT_GE(bond_idx, 0, "if_nametoindex bond")) 507 goto out; 508 509 /* query default xdp-feature for bond device */ 510 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 511 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 512 goto out; 513 514 if (!ASSERT_EQ(query_opts.feature_flags, 0, 515 "bond query_opts.feature_flags")) 516 goto out; 517 518 if (!ASSERT_OK(system("ip link add veth0 type veth peer name veth1"), 519 "add veth{0,1} pair")) 520 goto out; 521 522 if (!ASSERT_OK(system("ip link add veth2 type veth peer name veth3"), 523 "add veth{2,3} pair")) 524 goto out; 525 526 if (!ASSERT_OK(system("ip link set veth0 master bond"), 527 "add veth0 to master bond")) 528 goto out; 529 530 /* xdp-feature for bond device should be obtained from the single slave 531 * device (veth0) 532 */ 533 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 534 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 535 goto out; 536 537 if (!ASSERT_EQ(query_opts.feature_flags, 538 NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 539 NETDEV_XDP_ACT_RX_SG, 540 "bond query_opts.feature_flags")) 541 goto out; 542 543 veth1_idx = if_nametoindex("veth1"); 544 if (!ASSERT_GE(veth1_idx, 0, "if_nametoindex veth1")) 545 goto out; 546 547 link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, 548 veth1_idx); 549 if (!ASSERT_OK_PTR(link, "attach program to veth1")) 550 goto out; 551 552 /* xdp-feature for veth0 are changed */ 553 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 554 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 555 goto out; 556 557 if (!ASSERT_EQ(query_opts.feature_flags, 558 NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 559 NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | 560 NETDEV_XDP_ACT_NDO_XMIT_SG, 561 "bond query_opts.feature_flags")) 562 goto out; 563 564 if (!ASSERT_OK(system("ip link set veth2 master bond"), 565 "add veth2 to master bond")) 566 goto out; 567 568 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 569 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 570 goto out; 571 572 /* xdp-feature for bond device should be set to the most restrict 573 * value obtained from attached slave devices (veth0 and veth2) 574 */ 575 if (!ASSERT_EQ(query_opts.feature_flags, 576 NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 577 NETDEV_XDP_ACT_RX_SG, 578 "bond query_opts.feature_flags")) 579 goto out; 580 581 if (!ASSERT_OK(system("ip link set veth2 nomaster"), 582 "del veth2 to master bond")) 583 goto out; 584 585 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 586 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 587 goto out; 588 589 if (!ASSERT_EQ(query_opts.feature_flags, 590 NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 591 NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | 592 NETDEV_XDP_ACT_NDO_XMIT_SG, 593 "bond query_opts.feature_flags")) 594 goto out; 595 596 if (!ASSERT_OK(system("ip link set veth0 nomaster"), 597 "del veth0 to master bond")) 598 goto out; 599 600 err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); 601 if (!ASSERT_OK(err, "bond bpf_xdp_query")) 602 goto out; 603 604 ASSERT_EQ(query_opts.feature_flags, 0, 605 "bond query_opts.feature_flags"); 606 out: 607 bpf_link__destroy(link); 608 system("ip link del veth0"); 609 system("ip link del veth2"); 610 system("ip link del bond"); 611 } 612 613 static int libbpf_debug_print(enum libbpf_print_level level, 614 const char *format, va_list args) 615 { 616 if (level != LIBBPF_WARN) 617 vprintf(format, args); 618 return 0; 619 } 620 621 struct bond_test_case { 622 char *name; 623 int mode; 624 int xmit_policy; 625 }; 626 627 static struct bond_test_case bond_test_cases[] = { 628 { "xdp_bonding_roundrobin", BOND_MODE_ROUNDROBIN, BOND_XMIT_POLICY_LAYER23, }, 629 { "xdp_bonding_activebackup", BOND_MODE_ACTIVEBACKUP, BOND_XMIT_POLICY_LAYER23 }, 630 631 { "xdp_bonding_xor_layer2", BOND_MODE_XOR, BOND_XMIT_POLICY_LAYER2, }, 632 { "xdp_bonding_xor_layer23", BOND_MODE_XOR, BOND_XMIT_POLICY_LAYER23, }, 633 { "xdp_bonding_xor_layer34", BOND_MODE_XOR, BOND_XMIT_POLICY_LAYER34, }, 634 }; 635 636 void serial_test_xdp_bonding(void) 637 { 638 libbpf_print_fn_t old_print_fn; 639 struct skeletons skeletons = {}; 640 int i; 641 642 old_print_fn = libbpf_set_print(libbpf_debug_print); 643 644 root_netns_fd = open("/proc/self/ns/net", O_RDONLY); 645 if (!ASSERT_GE(root_netns_fd, 0, "open /proc/self/ns/net")) 646 goto out; 647 648 skeletons.xdp_dummy = xdp_dummy__open_and_load(); 649 if (!ASSERT_OK_PTR(skeletons.xdp_dummy, "xdp_dummy__open_and_load")) 650 goto out; 651 652 skeletons.xdp_tx = xdp_tx__open_and_load(); 653 if (!ASSERT_OK_PTR(skeletons.xdp_tx, "xdp_tx__open_and_load")) 654 goto out; 655 656 skeletons.xdp_redirect_multi_kern = xdp_redirect_multi_kern__open_and_load(); 657 if (!ASSERT_OK_PTR(skeletons.xdp_redirect_multi_kern, 658 "xdp_redirect_multi_kern__open_and_load")) 659 goto out; 660 661 if (test__start_subtest("xdp_bonding_attach")) 662 test_xdp_bonding_attach(&skeletons); 663 664 if (test__start_subtest("xdp_bonding_nested")) 665 test_xdp_bonding_nested(&skeletons); 666 667 if (test__start_subtest("xdp_bonding_features")) 668 test_xdp_bonding_features(&skeletons); 669 670 for (i = 0; i < ARRAY_SIZE(bond_test_cases); i++) { 671 struct bond_test_case *test_case = &bond_test_cases[i]; 672 673 if (test__start_subtest(test_case->name)) 674 test_xdp_bonding_with_mode( 675 &skeletons, 676 test_case->mode, 677 test_case->xmit_policy); 678 } 679 680 if (test__start_subtest("xdp_bonding_redirect_multi")) 681 test_xdp_bonding_redirect_multi(&skeletons); 682 683 out: 684 xdp_dummy__destroy(skeletons.xdp_dummy); 685 xdp_tx__destroy(skeletons.xdp_tx); 686 xdp_redirect_multi_kern__destroy(skeletons.xdp_redirect_multi_kern); 687 688 libbpf_set_print(old_print_fn); 689 if (root_netns_fd >= 0) 690 close(root_netns_fd); 691 } 692