1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Isovalent */ 3 #include <uapi/linux/if_link.h> 4 #include <net/if.h> 5 #include <test_progs.h> 6 7 #define netkit_peer "nk0" 8 #define netkit_name "nk1" 9 10 #define ping_addr_neigh 0x0a000002 /* 10.0.0.2 */ 11 #define ping_addr_noneigh 0x0a000003 /* 10.0.0.3 */ 12 13 #include "test_tc_link.skel.h" 14 #include "netlink_helpers.h" 15 #include "tc_helpers.h" 16 17 #define NETKIT_HEADROOM 32 18 #define NETKIT_TAILROOM 8 19 20 #define MARK 42 21 #define PRIO 0xeb9f 22 #define ICMP_ECHO 8 23 24 #define FLAG_ADJUST_ROOM (1 << 0) 25 #define FLAG_SAME_NETNS (1 << 1) 26 27 struct icmphdr { 28 __u8 type; 29 __u8 code; 30 __sum16 checksum; 31 struct { 32 __be16 id; 33 __be16 sequence; 34 } echo; 35 }; 36 37 struct iplink_req { 38 struct nlmsghdr n; 39 struct ifinfomsg i; 40 char buf[1024]; 41 }; 42 43 static int create_netkit(int mode, int policy, int peer_policy, int *ifindex, 44 int scrub, int peer_scrub, __u32 flags) 45 { 46 struct rtnl_handle rth = { .fd = -1 }; 47 struct iplink_req req = {}; 48 struct rtattr *linkinfo, *data; 49 const char *type = "netkit"; 50 int err; 51 52 err = rtnl_open(&rth, 0); 53 if (!ASSERT_OK(err, "open_rtnetlink")) 54 return err; 55 56 memset(&req, 0, sizeof(req)); 57 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 58 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; 59 req.n.nlmsg_type = RTM_NEWLINK; 60 req.i.ifi_family = AF_UNSPEC; 61 62 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, netkit_name, 63 strlen(netkit_name)); 64 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO); 65 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type)); 66 data = addattr_nest(&req.n, sizeof(req), IFLA_INFO_DATA); 67 addattr32(&req.n, sizeof(req), IFLA_NETKIT_POLICY, policy); 68 addattr32(&req.n, sizeof(req), IFLA_NETKIT_PEER_POLICY, peer_policy); 69 addattr32(&req.n, sizeof(req), IFLA_NETKIT_SCRUB, scrub); 70 addattr32(&req.n, sizeof(req), IFLA_NETKIT_PEER_SCRUB, peer_scrub); 71 addattr32(&req.n, sizeof(req), IFLA_NETKIT_MODE, mode); 72 if (flags & FLAG_ADJUST_ROOM) { 73 addattr16(&req.n, sizeof(req), IFLA_NETKIT_HEADROOM, NETKIT_HEADROOM); 74 addattr16(&req.n, sizeof(req), IFLA_NETKIT_TAILROOM, NETKIT_TAILROOM); 75 } 76 addattr_nest_end(&req.n, data); 77 addattr_nest_end(&req.n, linkinfo); 78 79 err = rtnl_talk(&rth, &req.n, NULL); 80 ASSERT_OK(err, "talk_rtnetlink"); 81 rtnl_close(&rth); 82 *ifindex = if_nametoindex(netkit_name); 83 84 ASSERT_GT(*ifindex, 0, "retrieve_ifindex"); 85 ASSERT_OK(system("ip netns add foo"), "create netns"); 86 ASSERT_OK(system("ip link set dev " netkit_name " up"), 87 "up primary"); 88 ASSERT_OK(system("ip addr add dev " netkit_name " 10.0.0.1/24"), 89 "addr primary"); 90 91 if (mode == NETKIT_L3) { 92 ASSERT_EQ(system("ip link set dev " netkit_name 93 " addr ee:ff:bb:cc:aa:dd 2> /dev/null"), 512, 94 "set hwaddress"); 95 } else { 96 ASSERT_OK(system("ip link set dev " netkit_name 97 " addr ee:ff:bb:cc:aa:dd"), 98 "set hwaddress"); 99 } 100 if (flags & FLAG_SAME_NETNS) { 101 ASSERT_OK(system("ip link set dev " netkit_peer " up"), 102 "up peer"); 103 ASSERT_OK(system("ip addr add dev " netkit_peer " 10.0.0.2/24"), 104 "addr peer"); 105 } else { 106 ASSERT_OK(system("ip link set " netkit_peer " netns foo"), 107 "move peer"); 108 ASSERT_OK(system("ip netns exec foo ip link set dev " 109 netkit_peer " up"), "up peer"); 110 ASSERT_OK(system("ip netns exec foo ip addr add dev " 111 netkit_peer " 10.0.0.2/24"), "addr peer"); 112 } 113 return err; 114 } 115 116 static void move_netkit(void) 117 { 118 ASSERT_OK(system("ip link set " netkit_peer " netns foo"), 119 "move peer"); 120 ASSERT_OK(system("ip netns exec foo ip link set dev " 121 netkit_peer " up"), "up peer"); 122 ASSERT_OK(system("ip netns exec foo ip addr add dev " 123 netkit_peer " 10.0.0.2/24"), "addr peer"); 124 } 125 126 static void destroy_netkit(void) 127 { 128 ASSERT_OK(system("ip link del dev " netkit_name), "del primary"); 129 ASSERT_OK(system("ip netns del foo"), "delete netns"); 130 ASSERT_EQ(if_nametoindex(netkit_name), 0, netkit_name "_ifindex"); 131 } 132 133 static int __send_icmp(__u32 dest) 134 { 135 int sock, ret, mark = MARK, prio = PRIO; 136 struct sockaddr_in addr; 137 struct icmphdr icmp; 138 139 ret = write_sysctl("/proc/sys/net/ipv4/ping_group_range", "0 0"); 140 if (!ASSERT_OK(ret, "write_sysctl(net.ipv4.ping_group_range)")) 141 return ret; 142 143 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 144 if (!ASSERT_GE(sock, 0, "icmp_socket")) 145 return -errno; 146 147 ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, 148 netkit_name, strlen(netkit_name) + 1); 149 if (!ASSERT_OK(ret, "setsockopt(SO_BINDTODEVICE)")) 150 goto out; 151 152 ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); 153 if (!ASSERT_OK(ret, "setsockopt(SO_MARK)")) 154 goto out; 155 156 ret = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, 157 &prio, sizeof(prio)); 158 if (!ASSERT_OK(ret, "setsockopt(SO_PRIORITY)")) 159 goto out; 160 161 memset(&addr, 0, sizeof(addr)); 162 addr.sin_family = AF_INET; 163 addr.sin_addr.s_addr = htonl(dest); 164 165 memset(&icmp, 0, sizeof(icmp)); 166 icmp.type = ICMP_ECHO; 167 icmp.echo.id = 1234; 168 icmp.echo.sequence = 1; 169 170 ret = sendto(sock, &icmp, sizeof(icmp), 0, 171 (struct sockaddr *)&addr, sizeof(addr)); 172 if (!ASSERT_GE(ret, 0, "icmp_sendto")) 173 ret = -errno; 174 else 175 ret = 0; 176 out: 177 close(sock); 178 return ret; 179 } 180 181 static int send_icmp(void) 182 { 183 return __send_icmp(ping_addr_neigh); 184 } 185 186 void serial_test_tc_netkit_basic(void) 187 { 188 LIBBPF_OPTS(bpf_prog_query_opts, optq); 189 LIBBPF_OPTS(bpf_netkit_opts, optl); 190 __u32 prog_ids[2], link_ids[2]; 191 __u32 pid1, pid2, lid1, lid2; 192 struct test_tc_link *skel; 193 struct bpf_link *link; 194 int err, ifindex; 195 196 err = create_netkit(NETKIT_L2, NETKIT_PASS, NETKIT_PASS, 197 &ifindex, NETKIT_SCRUB_DEFAULT, 198 NETKIT_SCRUB_DEFAULT, 0); 199 if (err) 200 return; 201 202 skel = test_tc_link__open(); 203 if (!ASSERT_OK_PTR(skel, "skel_open")) 204 goto cleanup; 205 206 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, 207 BPF_NETKIT_PRIMARY), 0, "tc1_attach_type"); 208 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, 209 BPF_NETKIT_PEER), 0, "tc2_attach_type"); 210 211 err = test_tc_link__load(skel); 212 if (!ASSERT_OK(err, "skel_load")) 213 goto cleanup; 214 215 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 216 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 217 218 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 219 220 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 221 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 222 223 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 224 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 225 226 link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl); 227 if (!ASSERT_OK_PTR(link, "link_attach")) 228 goto cleanup; 229 230 skel->links.tc1 = link; 231 232 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 233 234 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 235 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 236 237 optq.prog_ids = prog_ids; 238 optq.link_ids = link_ids; 239 240 memset(prog_ids, 0, sizeof(prog_ids)); 241 memset(link_ids, 0, sizeof(link_ids)); 242 optq.count = ARRAY_SIZE(prog_ids); 243 244 err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq); 245 if (!ASSERT_OK(err, "prog_query")) 246 goto cleanup; 247 248 ASSERT_EQ(optq.count, 1, "count"); 249 ASSERT_EQ(optq.revision, 2, "revision"); 250 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 251 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 252 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 253 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 254 255 tc_skel_reset_all_seen(skel); 256 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 257 258 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 259 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 260 261 link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl); 262 if (!ASSERT_OK_PTR(link, "link_attach")) 263 goto cleanup; 264 265 skel->links.tc2 = link; 266 267 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 268 ASSERT_NEQ(lid1, lid2, "link_ids_1_2"); 269 270 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 271 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 1); 272 273 memset(prog_ids, 0, sizeof(prog_ids)); 274 memset(link_ids, 0, sizeof(link_ids)); 275 optq.count = ARRAY_SIZE(prog_ids); 276 277 err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PEER, &optq); 278 if (!ASSERT_OK(err, "prog_query")) 279 goto cleanup; 280 281 ASSERT_EQ(optq.count, 1, "count"); 282 ASSERT_EQ(optq.revision, 2, "revision"); 283 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 284 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 285 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 286 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 287 288 tc_skel_reset_all_seen(skel); 289 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 290 291 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 292 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 293 cleanup: 294 test_tc_link__destroy(skel); 295 296 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 297 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 298 destroy_netkit(); 299 } 300 301 static void serial_test_tc_netkit_multi_links_target(int mode, int target) 302 { 303 LIBBPF_OPTS(bpf_prog_query_opts, optq); 304 LIBBPF_OPTS(bpf_netkit_opts, optl); 305 __u32 prog_ids[3], link_ids[3]; 306 __u32 pid1, pid2, lid1, lid2; 307 struct test_tc_link *skel; 308 struct bpf_link *link; 309 int err, ifindex; 310 311 err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS, 312 &ifindex, NETKIT_SCRUB_DEFAULT, 313 NETKIT_SCRUB_DEFAULT, 0); 314 if (err) 315 return; 316 317 skel = test_tc_link__open(); 318 if (!ASSERT_OK_PTR(skel, "skel_open")) 319 goto cleanup; 320 321 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, 322 target), 0, "tc1_attach_type"); 323 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, 324 target), 0, "tc2_attach_type"); 325 326 err = test_tc_link__load(skel); 327 if (!ASSERT_OK(err, "skel_load")) 328 goto cleanup; 329 330 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 331 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 332 333 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 334 335 assert_mprog_count_ifindex(ifindex, target, 0); 336 337 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 338 ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth"); 339 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 340 341 link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl); 342 if (!ASSERT_OK_PTR(link, "link_attach")) 343 goto cleanup; 344 345 skel->links.tc1 = link; 346 347 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 348 349 assert_mprog_count_ifindex(ifindex, target, 1); 350 351 optq.prog_ids = prog_ids; 352 optq.link_ids = link_ids; 353 354 memset(prog_ids, 0, sizeof(prog_ids)); 355 memset(link_ids, 0, sizeof(link_ids)); 356 optq.count = ARRAY_SIZE(prog_ids); 357 358 err = bpf_prog_query_opts(ifindex, target, &optq); 359 if (!ASSERT_OK(err, "prog_query")) 360 goto cleanup; 361 362 ASSERT_EQ(optq.count, 1, "count"); 363 ASSERT_EQ(optq.revision, 2, "revision"); 364 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 365 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 366 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 367 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 368 369 tc_skel_reset_all_seen(skel); 370 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 371 372 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 373 ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth"); 374 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 375 376 LIBBPF_OPTS_RESET(optl, 377 .flags = BPF_F_BEFORE, 378 .relative_fd = bpf_program__fd(skel->progs.tc1), 379 ); 380 381 link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl); 382 if (!ASSERT_OK_PTR(link, "link_attach")) 383 goto cleanup; 384 385 skel->links.tc2 = link; 386 387 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 388 ASSERT_NEQ(lid1, lid2, "link_ids_1_2"); 389 390 assert_mprog_count_ifindex(ifindex, target, 2); 391 392 memset(prog_ids, 0, sizeof(prog_ids)); 393 memset(link_ids, 0, sizeof(link_ids)); 394 optq.count = ARRAY_SIZE(prog_ids); 395 396 err = bpf_prog_query_opts(ifindex, target, &optq); 397 if (!ASSERT_OK(err, "prog_query")) 398 goto cleanup; 399 400 ASSERT_EQ(optq.count, 2, "count"); 401 ASSERT_EQ(optq.revision, 3, "revision"); 402 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 403 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 404 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 405 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 406 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 407 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 408 409 tc_skel_reset_all_seen(skel); 410 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 411 412 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 413 ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth"); 414 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 415 cleanup: 416 test_tc_link__destroy(skel); 417 418 assert_mprog_count_ifindex(ifindex, target, 0); 419 destroy_netkit(); 420 } 421 422 void serial_test_tc_netkit_multi_links(void) 423 { 424 serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY); 425 serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY); 426 serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PEER); 427 serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PEER); 428 } 429 430 static void serial_test_tc_netkit_multi_opts_target(int mode, int target) 431 { 432 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 433 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 434 LIBBPF_OPTS(bpf_prog_query_opts, optq); 435 __u32 pid1, pid2, fd1, fd2; 436 __u32 prog_ids[3]; 437 struct test_tc_link *skel; 438 int err, ifindex; 439 440 err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS, 441 &ifindex, NETKIT_SCRUB_DEFAULT, 442 NETKIT_SCRUB_DEFAULT, 0); 443 if (err) 444 return; 445 446 skel = test_tc_link__open_and_load(); 447 if (!ASSERT_OK_PTR(skel, "skel_load")) 448 goto cleanup; 449 450 fd1 = bpf_program__fd(skel->progs.tc1); 451 fd2 = bpf_program__fd(skel->progs.tc2); 452 453 pid1 = id_from_prog_fd(fd1); 454 pid2 = id_from_prog_fd(fd2); 455 456 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 457 458 assert_mprog_count_ifindex(ifindex, target, 0); 459 460 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 461 ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth"); 462 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 463 464 err = bpf_prog_attach_opts(fd1, ifindex, target, &opta); 465 if (!ASSERT_EQ(err, 0, "prog_attach")) 466 goto cleanup; 467 468 assert_mprog_count_ifindex(ifindex, target, 1); 469 470 optq.prog_ids = prog_ids; 471 472 memset(prog_ids, 0, sizeof(prog_ids)); 473 optq.count = ARRAY_SIZE(prog_ids); 474 475 err = bpf_prog_query_opts(ifindex, target, &optq); 476 if (!ASSERT_OK(err, "prog_query")) 477 goto cleanup_fd1; 478 479 ASSERT_EQ(optq.count, 1, "count"); 480 ASSERT_EQ(optq.revision, 2, "revision"); 481 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 482 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 483 484 tc_skel_reset_all_seen(skel); 485 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 486 487 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 488 ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth"); 489 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 490 491 LIBBPF_OPTS_RESET(opta, 492 .flags = BPF_F_BEFORE, 493 .relative_fd = fd1, 494 ); 495 496 err = bpf_prog_attach_opts(fd2, ifindex, target, &opta); 497 if (!ASSERT_EQ(err, 0, "prog_attach")) 498 goto cleanup_fd1; 499 500 assert_mprog_count_ifindex(ifindex, target, 2); 501 502 memset(prog_ids, 0, sizeof(prog_ids)); 503 optq.count = ARRAY_SIZE(prog_ids); 504 505 err = bpf_prog_query_opts(ifindex, target, &optq); 506 if (!ASSERT_OK(err, "prog_query")) 507 goto cleanup_fd2; 508 509 ASSERT_EQ(optq.count, 2, "count"); 510 ASSERT_EQ(optq.revision, 3, "revision"); 511 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 512 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 513 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 514 515 tc_skel_reset_all_seen(skel); 516 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 517 518 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 519 ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth"); 520 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 521 522 cleanup_fd2: 523 err = bpf_prog_detach_opts(fd2, ifindex, target, &optd); 524 ASSERT_OK(err, "prog_detach"); 525 assert_mprog_count_ifindex(ifindex, target, 1); 526 cleanup_fd1: 527 err = bpf_prog_detach_opts(fd1, ifindex, target, &optd); 528 ASSERT_OK(err, "prog_detach"); 529 assert_mprog_count_ifindex(ifindex, target, 0); 530 cleanup: 531 test_tc_link__destroy(skel); 532 533 assert_mprog_count_ifindex(ifindex, target, 0); 534 destroy_netkit(); 535 } 536 537 void serial_test_tc_netkit_multi_opts(void) 538 { 539 serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PRIMARY); 540 serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PRIMARY); 541 serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PEER); 542 serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PEER); 543 } 544 545 void serial_test_tc_netkit_device(void) 546 { 547 LIBBPF_OPTS(bpf_prog_query_opts, optq); 548 LIBBPF_OPTS(bpf_netkit_opts, optl); 549 __u32 prog_ids[2], link_ids[2]; 550 __u32 pid1, pid2, lid1; 551 struct test_tc_link *skel; 552 struct bpf_link *link; 553 int err, ifindex, ifindex2; 554 555 err = create_netkit(NETKIT_L3, NETKIT_PASS, NETKIT_PASS, 556 &ifindex, NETKIT_SCRUB_DEFAULT, 557 NETKIT_SCRUB_DEFAULT, FLAG_SAME_NETNS); 558 if (err) 559 return; 560 561 ifindex2 = if_nametoindex(netkit_peer); 562 ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2"); 563 564 skel = test_tc_link__open(); 565 if (!ASSERT_OK_PTR(skel, "skel_open")) 566 goto cleanup; 567 568 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, 569 BPF_NETKIT_PRIMARY), 0, "tc1_attach_type"); 570 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, 571 BPF_NETKIT_PEER), 0, "tc2_attach_type"); 572 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, 573 BPF_NETKIT_PRIMARY), 0, "tc3_attach_type"); 574 575 err = test_tc_link__load(skel); 576 if (!ASSERT_OK(err, "skel_load")) 577 goto cleanup; 578 579 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 580 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 581 582 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 583 584 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 585 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 586 587 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 588 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 589 590 link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl); 591 if (!ASSERT_OK_PTR(link, "link_attach")) 592 goto cleanup; 593 594 skel->links.tc1 = link; 595 596 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 597 598 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 599 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 600 601 optq.prog_ids = prog_ids; 602 optq.link_ids = link_ids; 603 604 memset(prog_ids, 0, sizeof(prog_ids)); 605 memset(link_ids, 0, sizeof(link_ids)); 606 optq.count = ARRAY_SIZE(prog_ids); 607 608 err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq); 609 if (!ASSERT_OK(err, "prog_query")) 610 goto cleanup; 611 612 ASSERT_EQ(optq.count, 1, "count"); 613 ASSERT_EQ(optq.revision, 2, "revision"); 614 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 615 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 616 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 617 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 618 619 tc_skel_reset_all_seen(skel); 620 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 621 622 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 623 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 624 625 memset(prog_ids, 0, sizeof(prog_ids)); 626 memset(link_ids, 0, sizeof(link_ids)); 627 optq.count = ARRAY_SIZE(prog_ids); 628 629 err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PRIMARY, &optq); 630 ASSERT_EQ(err, -EACCES, "prog_query_should_fail"); 631 632 err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PEER, &optq); 633 ASSERT_EQ(err, -EACCES, "prog_query_should_fail"); 634 635 link = bpf_program__attach_netkit(skel->progs.tc2, ifindex2, &optl); 636 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 637 bpf_link__destroy(link); 638 goto cleanup; 639 } 640 641 link = bpf_program__attach_netkit(skel->progs.tc3, ifindex2, &optl); 642 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 643 bpf_link__destroy(link); 644 goto cleanup; 645 } 646 647 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 648 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 649 cleanup: 650 test_tc_link__destroy(skel); 651 652 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 653 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 654 destroy_netkit(); 655 } 656 657 static void serial_test_tc_netkit_neigh_links_target(int mode, int target) 658 { 659 LIBBPF_OPTS(bpf_prog_query_opts, optq); 660 LIBBPF_OPTS(bpf_netkit_opts, optl); 661 __u32 prog_ids[2], link_ids[2]; 662 __u32 pid1, lid1; 663 struct test_tc_link *skel; 664 struct bpf_link *link; 665 int err, ifindex; 666 667 err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS, 668 &ifindex, NETKIT_SCRUB_DEFAULT, 669 NETKIT_SCRUB_DEFAULT, 0); 670 if (err) 671 return; 672 673 skel = test_tc_link__open(); 674 if (!ASSERT_OK_PTR(skel, "skel_open")) 675 goto cleanup; 676 677 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, 678 BPF_NETKIT_PRIMARY), 0, "tc1_attach_type"); 679 680 err = test_tc_link__load(skel); 681 if (!ASSERT_OK(err, "skel_load")) 682 goto cleanup; 683 684 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 685 686 assert_mprog_count_ifindex(ifindex, target, 0); 687 688 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 689 ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth"); 690 691 link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl); 692 if (!ASSERT_OK_PTR(link, "link_attach")) 693 goto cleanup; 694 695 skel->links.tc1 = link; 696 697 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 698 699 assert_mprog_count_ifindex(ifindex, target, 1); 700 701 optq.prog_ids = prog_ids; 702 optq.link_ids = link_ids; 703 704 memset(prog_ids, 0, sizeof(prog_ids)); 705 memset(link_ids, 0, sizeof(link_ids)); 706 optq.count = ARRAY_SIZE(prog_ids); 707 708 err = bpf_prog_query_opts(ifindex, target, &optq); 709 if (!ASSERT_OK(err, "prog_query")) 710 goto cleanup; 711 712 ASSERT_EQ(optq.count, 1, "count"); 713 ASSERT_EQ(optq.revision, 2, "revision"); 714 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 715 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 716 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 717 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 718 719 tc_skel_reset_all_seen(skel); 720 ASSERT_EQ(__send_icmp(ping_addr_noneigh), 0, "icmp_pkt"); 721 722 ASSERT_EQ(skel->bss->seen_tc1, true /* L2: ARP */, "seen_tc1"); 723 ASSERT_EQ(skel->bss->seen_eth, mode == NETKIT_L3, "seen_eth"); 724 cleanup: 725 test_tc_link__destroy(skel); 726 727 assert_mprog_count_ifindex(ifindex, target, 0); 728 destroy_netkit(); 729 } 730 731 void serial_test_tc_netkit_neigh_links(void) 732 { 733 serial_test_tc_netkit_neigh_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY); 734 serial_test_tc_netkit_neigh_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY); 735 } 736 737 static void serial_test_tc_netkit_pkt_type_mode(int mode) 738 { 739 LIBBPF_OPTS(bpf_netkit_opts, optl_nk); 740 LIBBPF_OPTS(bpf_tcx_opts, optl_tcx); 741 int err, ifindex, ifindex2; 742 struct test_tc_link *skel; 743 struct bpf_link *link; 744 745 err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS, 746 &ifindex, NETKIT_SCRUB_DEFAULT, 747 NETKIT_SCRUB_DEFAULT, FLAG_SAME_NETNS); 748 if (err) 749 return; 750 751 ifindex2 = if_nametoindex(netkit_peer); 752 ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2"); 753 754 skel = test_tc_link__open(); 755 if (!ASSERT_OK_PTR(skel, "skel_open")) 756 goto cleanup; 757 758 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, 759 BPF_NETKIT_PRIMARY), 0, "tc1_attach_type"); 760 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc7, 761 BPF_TCX_INGRESS), 0, "tc7_attach_type"); 762 763 err = test_tc_link__load(skel); 764 if (!ASSERT_OK(err, "skel_load")) 765 goto cleanup; 766 767 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 768 assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0); 769 770 link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl_nk); 771 if (!ASSERT_OK_PTR(link, "link_attach")) 772 goto cleanup; 773 774 skel->links.tc1 = link; 775 776 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 777 assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0); 778 779 link = bpf_program__attach_tcx(skel->progs.tc7, ifindex2, &optl_tcx); 780 if (!ASSERT_OK_PTR(link, "link_attach")) 781 goto cleanup; 782 783 skel->links.tc7 = link; 784 785 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 786 assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 1); 787 788 move_netkit(); 789 790 tc_skel_reset_all_seen(skel); 791 skel->bss->set_type = true; 792 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 793 794 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 795 ASSERT_EQ(skel->bss->seen_tc7, true, "seen_tc7"); 796 797 ASSERT_EQ(skel->bss->seen_host, true, "seen_host"); 798 ASSERT_EQ(skel->bss->seen_mcast, true, "seen_mcast"); 799 cleanup: 800 test_tc_link__destroy(skel); 801 802 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 803 destroy_netkit(); 804 } 805 806 void serial_test_tc_netkit_pkt_type(void) 807 { 808 serial_test_tc_netkit_pkt_type_mode(NETKIT_L2); 809 serial_test_tc_netkit_pkt_type_mode(NETKIT_L3); 810 } 811 812 static void serial_test_tc_netkit_scrub_type(int scrub, bool room) 813 { 814 LIBBPF_OPTS(bpf_netkit_opts, optl); 815 struct test_tc_link *skel; 816 struct bpf_link *link; 817 int err, ifindex; 818 819 err = create_netkit(NETKIT_L2, NETKIT_PASS, NETKIT_PASS, 820 &ifindex, scrub, scrub, 821 room ? FLAG_ADJUST_ROOM : 0); 822 if (err) 823 return; 824 825 skel = test_tc_link__open(); 826 if (!ASSERT_OK_PTR(skel, "skel_open")) 827 goto cleanup; 828 829 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc8, 830 BPF_NETKIT_PRIMARY), 0, "tc8_attach_type"); 831 832 err = test_tc_link__load(skel); 833 if (!ASSERT_OK(err, "skel_load")) 834 goto cleanup; 835 836 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 837 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 838 839 ASSERT_EQ(skel->bss->seen_tc8, false, "seen_tc8"); 840 841 link = bpf_program__attach_netkit(skel->progs.tc8, ifindex, &optl); 842 if (!ASSERT_OK_PTR(link, "link_attach")) 843 goto cleanup; 844 845 skel->links.tc8 = link; 846 847 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1); 848 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 849 850 tc_skel_reset_all_seen(skel); 851 ASSERT_EQ(send_icmp(), 0, "icmp_pkt"); 852 853 ASSERT_EQ(skel->bss->seen_tc8, true, "seen_tc8"); 854 ASSERT_EQ(skel->bss->mark, scrub == NETKIT_SCRUB_NONE ? MARK : 0, "mark"); 855 ASSERT_EQ(skel->bss->prio, scrub == NETKIT_SCRUB_NONE ? PRIO : 0, "prio"); 856 ASSERT_EQ(skel->bss->headroom, room ? NETKIT_HEADROOM : 0, "headroom"); 857 ASSERT_EQ(skel->bss->tailroom, room ? NETKIT_TAILROOM : 0, "tailroom"); 858 cleanup: 859 test_tc_link__destroy(skel); 860 861 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0); 862 assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0); 863 destroy_netkit(); 864 } 865 866 void serial_test_tc_netkit_scrub(void) 867 { 868 serial_test_tc_netkit_scrub_type(NETKIT_SCRUB_DEFAULT, false); 869 serial_test_tc_netkit_scrub_type(NETKIT_SCRUB_NONE, true); 870 } 871