1963 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3#include <uapi/linux/if_link.h>4#include <uapi/linux/pkt_sched.h>5#include <net/if.h>6#include <test_progs.h>7 8#define loopback 19#define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"10 11#include "test_tc_link.skel.h"12 13#include "netlink_helpers.h"14#include "tc_helpers.h"15 16void serial_test_tc_links_basic(void)17{18 LIBBPF_OPTS(bpf_prog_query_opts, optq);19 LIBBPF_OPTS(bpf_tcx_opts, optl);20 __u32 prog_ids[2], link_ids[2];21 __u32 pid1, pid2, lid1, lid2;22 struct test_tc_link *skel;23 struct bpf_link *link;24 int err;25 26 skel = test_tc_link__open_and_load();27 if (!ASSERT_OK_PTR(skel, "skel_load"))28 goto cleanup;29 30 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));31 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));32 33 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");34 35 assert_mprog_count(BPF_TCX_INGRESS, 0);36 assert_mprog_count(BPF_TCX_EGRESS, 0);37 38 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");39 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");40 41 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);42 if (!ASSERT_OK_PTR(link, "link_attach"))43 goto cleanup;44 45 skel->links.tc1 = link;46 47 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));48 49 assert_mprog_count(BPF_TCX_INGRESS, 1);50 assert_mprog_count(BPF_TCX_EGRESS, 0);51 52 optq.prog_ids = prog_ids;53 optq.link_ids = link_ids;54 55 memset(prog_ids, 0, sizeof(prog_ids));56 memset(link_ids, 0, sizeof(link_ids));57 optq.count = ARRAY_SIZE(prog_ids);58 59 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);60 if (!ASSERT_OK(err, "prog_query"))61 goto cleanup;62 63 ASSERT_EQ(optq.count, 1, "count");64 ASSERT_EQ(optq.revision, 2, "revision");65 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");66 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");67 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");68 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");69 70 tc_skel_reset_all_seen(skel);71 ASSERT_OK(system(ping_cmd), ping_cmd);72 73 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");74 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");75 76 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);77 if (!ASSERT_OK_PTR(link, "link_attach"))78 goto cleanup;79 80 skel->links.tc2 = link;81 82 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));83 ASSERT_NEQ(lid1, lid2, "link_ids_1_2");84 85 assert_mprog_count(BPF_TCX_INGRESS, 1);86 assert_mprog_count(BPF_TCX_EGRESS, 1);87 88 memset(prog_ids, 0, sizeof(prog_ids));89 memset(link_ids, 0, sizeof(link_ids));90 optq.count = ARRAY_SIZE(prog_ids);91 92 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);93 if (!ASSERT_OK(err, "prog_query"))94 goto cleanup;95 96 ASSERT_EQ(optq.count, 1, "count");97 ASSERT_EQ(optq.revision, 2, "revision");98 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");99 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");100 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");101 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");102 103 tc_skel_reset_all_seen(skel);104 ASSERT_OK(system(ping_cmd), ping_cmd);105 106 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");107 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");108cleanup:109 test_tc_link__destroy(skel);110 111 assert_mprog_count(BPF_TCX_INGRESS, 0);112 assert_mprog_count(BPF_TCX_EGRESS, 0);113}114 115static void test_tc_links_before_target(int target)116{117 LIBBPF_OPTS(bpf_prog_query_opts, optq);118 LIBBPF_OPTS(bpf_tcx_opts, optl);119 __u32 prog_ids[5], link_ids[5];120 __u32 pid1, pid2, pid3, pid4;121 __u32 lid1, lid2, lid3, lid4;122 struct test_tc_link *skel;123 struct bpf_link *link;124 int err;125 126 skel = test_tc_link__open();127 if (!ASSERT_OK_PTR(skel, "skel_open"))128 goto cleanup;129 130 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),131 0, "tc1_attach_type");132 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),133 0, "tc2_attach_type");134 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),135 0, "tc3_attach_type");136 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),137 0, "tc4_attach_type");138 139 err = test_tc_link__load(skel);140 if (!ASSERT_OK(err, "skel_load"))141 goto cleanup;142 143 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));144 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));145 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));146 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));147 148 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");149 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");150 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");151 152 assert_mprog_count(target, 0);153 154 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);155 if (!ASSERT_OK_PTR(link, "link_attach"))156 goto cleanup;157 158 skel->links.tc1 = link;159 160 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));161 162 assert_mprog_count(target, 1);163 164 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);165 if (!ASSERT_OK_PTR(link, "link_attach"))166 goto cleanup;167 168 skel->links.tc2 = link;169 170 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));171 172 assert_mprog_count(target, 2);173 174 optq.prog_ids = prog_ids;175 optq.link_ids = link_ids;176 177 memset(prog_ids, 0, sizeof(prog_ids));178 memset(link_ids, 0, sizeof(link_ids));179 optq.count = ARRAY_SIZE(prog_ids);180 181 err = bpf_prog_query_opts(loopback, target, &optq);182 if (!ASSERT_OK(err, "prog_query"))183 goto cleanup;184 185 ASSERT_EQ(optq.count, 2, "count");186 ASSERT_EQ(optq.revision, 3, "revision");187 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");188 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");189 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");190 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");191 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");192 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");193 194 tc_skel_reset_all_seen(skel);195 ASSERT_OK(system(ping_cmd), ping_cmd);196 197 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");198 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");199 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");200 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");201 202 LIBBPF_OPTS_RESET(optl,203 .flags = BPF_F_BEFORE,204 .relative_fd = bpf_program__fd(skel->progs.tc2),205 );206 207 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);208 if (!ASSERT_OK_PTR(link, "link_attach"))209 goto cleanup;210 211 skel->links.tc3 = link;212 213 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));214 215 LIBBPF_OPTS_RESET(optl,216 .flags = BPF_F_BEFORE | BPF_F_LINK,217 .relative_id = lid1,218 );219 220 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);221 if (!ASSERT_OK_PTR(link, "link_attach"))222 goto cleanup;223 224 skel->links.tc4 = link;225 226 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));227 228 assert_mprog_count(target, 4);229 230 memset(prog_ids, 0, sizeof(prog_ids));231 memset(link_ids, 0, sizeof(link_ids));232 optq.count = ARRAY_SIZE(prog_ids);233 234 err = bpf_prog_query_opts(loopback, target, &optq);235 if (!ASSERT_OK(err, "prog_query"))236 goto cleanup;237 238 ASSERT_EQ(optq.count, 4, "count");239 ASSERT_EQ(optq.revision, 5, "revision");240 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");241 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");242 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");243 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");244 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");245 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");246 ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]");247 ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]");248 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");249 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");250 251 tc_skel_reset_all_seen(skel);252 ASSERT_OK(system(ping_cmd), ping_cmd);253 254 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");255 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");256 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");257 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");258cleanup:259 test_tc_link__destroy(skel);260 assert_mprog_count(target, 0);261}262 263void serial_test_tc_links_before(void)264{265 test_tc_links_before_target(BPF_TCX_INGRESS);266 test_tc_links_before_target(BPF_TCX_EGRESS);267}268 269static void test_tc_links_after_target(int target)270{271 LIBBPF_OPTS(bpf_prog_query_opts, optq);272 LIBBPF_OPTS(bpf_tcx_opts, optl);273 __u32 prog_ids[5], link_ids[5];274 __u32 pid1, pid2, pid3, pid4;275 __u32 lid1, lid2, lid3, lid4;276 struct test_tc_link *skel;277 struct bpf_link *link;278 int err;279 280 skel = test_tc_link__open();281 if (!ASSERT_OK_PTR(skel, "skel_open"))282 goto cleanup;283 284 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),285 0, "tc1_attach_type");286 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),287 0, "tc2_attach_type");288 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),289 0, "tc3_attach_type");290 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),291 0, "tc4_attach_type");292 293 err = test_tc_link__load(skel);294 if (!ASSERT_OK(err, "skel_load"))295 goto cleanup;296 297 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));298 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));299 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));300 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));301 302 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");303 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");304 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");305 306 assert_mprog_count(target, 0);307 308 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);309 if (!ASSERT_OK_PTR(link, "link_attach"))310 goto cleanup;311 312 skel->links.tc1 = link;313 314 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));315 316 assert_mprog_count(target, 1);317 318 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);319 if (!ASSERT_OK_PTR(link, "link_attach"))320 goto cleanup;321 322 skel->links.tc2 = link;323 324 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));325 326 assert_mprog_count(target, 2);327 328 optq.prog_ids = prog_ids;329 optq.link_ids = link_ids;330 331 memset(prog_ids, 0, sizeof(prog_ids));332 memset(link_ids, 0, sizeof(link_ids));333 optq.count = ARRAY_SIZE(prog_ids);334 335 err = bpf_prog_query_opts(loopback, target, &optq);336 if (!ASSERT_OK(err, "prog_query"))337 goto cleanup;338 339 ASSERT_EQ(optq.count, 2, "count");340 ASSERT_EQ(optq.revision, 3, "revision");341 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");342 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");343 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");344 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");345 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");346 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");347 348 tc_skel_reset_all_seen(skel);349 ASSERT_OK(system(ping_cmd), ping_cmd);350 351 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");352 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");353 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");354 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");355 356 LIBBPF_OPTS_RESET(optl,357 .flags = BPF_F_AFTER,358 .relative_fd = bpf_program__fd(skel->progs.tc1),359 );360 361 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);362 if (!ASSERT_OK_PTR(link, "link_attach"))363 goto cleanup;364 365 skel->links.tc3 = link;366 367 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));368 369 LIBBPF_OPTS_RESET(optl,370 .flags = BPF_F_AFTER | BPF_F_LINK,371 .relative_fd = bpf_link__fd(skel->links.tc2),372 );373 374 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);375 if (!ASSERT_OK_PTR(link, "link_attach"))376 goto cleanup;377 378 skel->links.tc4 = link;379 380 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));381 382 assert_mprog_count(target, 4);383 384 memset(prog_ids, 0, sizeof(prog_ids));385 memset(link_ids, 0, sizeof(link_ids));386 optq.count = ARRAY_SIZE(prog_ids);387 388 err = bpf_prog_query_opts(loopback, target, &optq);389 if (!ASSERT_OK(err, "prog_query"))390 goto cleanup;391 392 ASSERT_EQ(optq.count, 4, "count");393 ASSERT_EQ(optq.revision, 5, "revision");394 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");395 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");396 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");397 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");398 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");399 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");400 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");401 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");402 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");403 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");404 405 tc_skel_reset_all_seen(skel);406 ASSERT_OK(system(ping_cmd), ping_cmd);407 408 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");409 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");410 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");411 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");412cleanup:413 test_tc_link__destroy(skel);414 assert_mprog_count(target, 0);415}416 417void serial_test_tc_links_after(void)418{419 test_tc_links_after_target(BPF_TCX_INGRESS);420 test_tc_links_after_target(BPF_TCX_EGRESS);421}422 423static void test_tc_links_revision_target(int target)424{425 LIBBPF_OPTS(bpf_prog_query_opts, optq);426 LIBBPF_OPTS(bpf_tcx_opts, optl);427 __u32 prog_ids[3], link_ids[3];428 __u32 pid1, pid2, lid1, lid2;429 struct test_tc_link *skel;430 struct bpf_link *link;431 int err;432 433 skel = test_tc_link__open();434 if (!ASSERT_OK_PTR(skel, "skel_open"))435 goto cleanup;436 437 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),438 0, "tc1_attach_type");439 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),440 0, "tc2_attach_type");441 442 err = test_tc_link__load(skel);443 if (!ASSERT_OK(err, "skel_load"))444 goto cleanup;445 446 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));447 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));448 449 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");450 451 assert_mprog_count(target, 0);452 453 optl.expected_revision = 1;454 455 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);456 if (!ASSERT_OK_PTR(link, "link_attach"))457 goto cleanup;458 459 skel->links.tc1 = link;460 461 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));462 463 assert_mprog_count(target, 1);464 465 optl.expected_revision = 1;466 467 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);468 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {469 bpf_link__destroy(link);470 goto cleanup;471 }472 473 assert_mprog_count(target, 1);474 475 optl.expected_revision = 2;476 477 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);478 if (!ASSERT_OK_PTR(link, "link_attach"))479 goto cleanup;480 481 skel->links.tc2 = link;482 483 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));484 485 assert_mprog_count(target, 2);486 487 optq.prog_ids = prog_ids;488 optq.link_ids = link_ids;489 490 memset(prog_ids, 0, sizeof(prog_ids));491 memset(link_ids, 0, sizeof(link_ids));492 optq.count = ARRAY_SIZE(prog_ids);493 494 err = bpf_prog_query_opts(loopback, target, &optq);495 if (!ASSERT_OK(err, "prog_query"))496 goto cleanup;497 498 ASSERT_EQ(optq.count, 2, "count");499 ASSERT_EQ(optq.revision, 3, "revision");500 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");501 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");502 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");503 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");504 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");505 ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");506 507 tc_skel_reset_all_seen(skel);508 ASSERT_OK(system(ping_cmd), ping_cmd);509 510 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");511 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");512cleanup:513 test_tc_link__destroy(skel);514 assert_mprog_count(target, 0);515}516 517void serial_test_tc_links_revision(void)518{519 test_tc_links_revision_target(BPF_TCX_INGRESS);520 test_tc_links_revision_target(BPF_TCX_EGRESS);521}522 523static void test_tc_chain_classic(int target, bool chain_tc_old)524{525 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);526 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);527 bool hook_created = false, tc_attached = false;528 LIBBPF_OPTS(bpf_tcx_opts, optl);529 __u32 pid1, pid2, pid3;530 struct test_tc_link *skel;531 struct bpf_link *link;532 int err;533 534 skel = test_tc_link__open();535 if (!ASSERT_OK_PTR(skel, "skel_open"))536 goto cleanup;537 538 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),539 0, "tc1_attach_type");540 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),541 0, "tc2_attach_type");542 543 err = test_tc_link__load(skel);544 if (!ASSERT_OK(err, "skel_load"))545 goto cleanup;546 547 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));548 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));549 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));550 551 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");552 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");553 554 assert_mprog_count(target, 0);555 556 if (chain_tc_old) {557 tc_hook.attach_point = target == BPF_TCX_INGRESS ?558 BPF_TC_INGRESS : BPF_TC_EGRESS;559 err = bpf_tc_hook_create(&tc_hook);560 if (err == 0)561 hook_created = true;562 err = err == -EEXIST ? 0 : err;563 if (!ASSERT_OK(err, "bpf_tc_hook_create"))564 goto cleanup;565 566 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);567 err = bpf_tc_attach(&tc_hook, &tc_opts);568 if (!ASSERT_OK(err, "bpf_tc_attach"))569 goto cleanup;570 tc_attached = true;571 }572 573 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);574 if (!ASSERT_OK_PTR(link, "link_attach"))575 goto cleanup;576 577 skel->links.tc1 = link;578 579 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);580 if (!ASSERT_OK_PTR(link, "link_attach"))581 goto cleanup;582 583 skel->links.tc2 = link;584 585 assert_mprog_count(target, 2);586 587 tc_skel_reset_all_seen(skel);588 ASSERT_OK(system(ping_cmd), ping_cmd);589 590 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");591 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");592 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");593 594 err = bpf_link__detach(skel->links.tc2);595 if (!ASSERT_OK(err, "prog_detach"))596 goto cleanup;597 598 assert_mprog_count(target, 1);599 600 tc_skel_reset_all_seen(skel);601 ASSERT_OK(system(ping_cmd), ping_cmd);602 603 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");604 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");605 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");606cleanup:607 if (tc_attached) {608 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;609 err = bpf_tc_detach(&tc_hook, &tc_opts);610 ASSERT_OK(err, "bpf_tc_detach");611 }612 if (hook_created) {613 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;614 bpf_tc_hook_destroy(&tc_hook);615 }616 assert_mprog_count(target, 1);617 test_tc_link__destroy(skel);618 assert_mprog_count(target, 0);619}620 621void serial_test_tc_links_chain_classic(void)622{623 test_tc_chain_classic(BPF_TCX_INGRESS, false);624 test_tc_chain_classic(BPF_TCX_EGRESS, false);625 test_tc_chain_classic(BPF_TCX_INGRESS, true);626 test_tc_chain_classic(BPF_TCX_EGRESS, true);627}628 629static void test_tc_links_replace_target(int target)630{631 LIBBPF_OPTS(bpf_prog_query_opts, optq);632 LIBBPF_OPTS(bpf_tcx_opts, optl);633 __u32 pid1, pid2, pid3, lid1, lid2;634 __u32 prog_ids[4], link_ids[4];635 struct test_tc_link *skel;636 struct bpf_link *link;637 int err;638 639 skel = test_tc_link__open();640 if (!ASSERT_OK_PTR(skel, "skel_open"))641 goto cleanup;642 643 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),644 0, "tc1_attach_type");645 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),646 0, "tc2_attach_type");647 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),648 0, "tc3_attach_type");649 650 err = test_tc_link__load(skel);651 if (!ASSERT_OK(err, "skel_load"))652 goto cleanup;653 654 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));655 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));656 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));657 658 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");659 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");660 661 assert_mprog_count(target, 0);662 663 optl.expected_revision = 1;664 665 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);666 if (!ASSERT_OK_PTR(link, "link_attach"))667 goto cleanup;668 669 skel->links.tc1 = link;670 671 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));672 673 assert_mprog_count(target, 1);674 675 LIBBPF_OPTS_RESET(optl,676 .flags = BPF_F_BEFORE,677 .relative_id = pid1,678 .expected_revision = 2,679 );680 681 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);682 if (!ASSERT_OK_PTR(link, "link_attach"))683 goto cleanup;684 685 skel->links.tc2 = link;686 687 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));688 689 assert_mprog_count(target, 2);690 691 optq.prog_ids = prog_ids;692 optq.link_ids = link_ids;693 694 memset(prog_ids, 0, sizeof(prog_ids));695 memset(link_ids, 0, sizeof(link_ids));696 optq.count = ARRAY_SIZE(prog_ids);697 698 err = bpf_prog_query_opts(loopback, target, &optq);699 if (!ASSERT_OK(err, "prog_query"))700 goto cleanup;701 702 ASSERT_EQ(optq.count, 2, "count");703 ASSERT_EQ(optq.revision, 3, "revision");704 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");705 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");706 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");707 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");708 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");709 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");710 711 tc_skel_reset_all_seen(skel);712 ASSERT_OK(system(ping_cmd), ping_cmd);713 714 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");715 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");716 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");717 718 LIBBPF_OPTS_RESET(optl,719 .flags = BPF_F_REPLACE,720 .relative_fd = bpf_program__fd(skel->progs.tc2),721 .expected_revision = 3,722 );723 724 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);725 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {726 bpf_link__destroy(link);727 goto cleanup;728 }729 730 assert_mprog_count(target, 2);731 732 LIBBPF_OPTS_RESET(optl,733 .flags = BPF_F_REPLACE | BPF_F_LINK,734 .relative_fd = bpf_link__fd(skel->links.tc2),735 .expected_revision = 3,736 );737 738 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);739 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {740 bpf_link__destroy(link);741 goto cleanup;742 }743 744 assert_mprog_count(target, 2);745 746 LIBBPF_OPTS_RESET(optl,747 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,748 .relative_id = lid2,749 );750 751 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);752 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {753 bpf_link__destroy(link);754 goto cleanup;755 }756 757 assert_mprog_count(target, 2);758 759 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);760 if (!ASSERT_OK(err, "link_update"))761 goto cleanup;762 763 assert_mprog_count(target, 2);764 765 memset(prog_ids, 0, sizeof(prog_ids));766 memset(link_ids, 0, sizeof(link_ids));767 optq.count = ARRAY_SIZE(prog_ids);768 769 err = bpf_prog_query_opts(loopback, target, &optq);770 if (!ASSERT_OK(err, "prog_query"))771 goto cleanup;772 773 ASSERT_EQ(optq.count, 2, "count");774 ASSERT_EQ(optq.revision, 4, "revision");775 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");776 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");777 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");778 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");779 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");780 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");781 782 tc_skel_reset_all_seen(skel);783 ASSERT_OK(system(ping_cmd), ping_cmd);784 785 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");786 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");787 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");788 789 err = bpf_link__detach(skel->links.tc2);790 if (!ASSERT_OK(err, "link_detach"))791 goto cleanup;792 793 assert_mprog_count(target, 1);794 795 memset(prog_ids, 0, sizeof(prog_ids));796 memset(link_ids, 0, sizeof(link_ids));797 optq.count = ARRAY_SIZE(prog_ids);798 799 err = bpf_prog_query_opts(loopback, target, &optq);800 if (!ASSERT_OK(err, "prog_query"))801 goto cleanup;802 803 ASSERT_EQ(optq.count, 1, "count");804 ASSERT_EQ(optq.revision, 5, "revision");805 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");806 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");807 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");808 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");809 810 tc_skel_reset_all_seen(skel);811 ASSERT_OK(system(ping_cmd), ping_cmd);812 813 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");814 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");815 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");816 817 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);818 if (!ASSERT_OK(err, "link_update_self"))819 goto cleanup;820 821 assert_mprog_count(target, 1);822 823 memset(prog_ids, 0, sizeof(prog_ids));824 memset(link_ids, 0, sizeof(link_ids));825 optq.count = ARRAY_SIZE(prog_ids);826 827 err = bpf_prog_query_opts(loopback, target, &optq);828 if (!ASSERT_OK(err, "prog_query"))829 goto cleanup;830 831 ASSERT_EQ(optq.count, 1, "count");832 ASSERT_EQ(optq.revision, 5, "revision");833 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");834 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");835 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");836 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");837 838 tc_skel_reset_all_seen(skel);839 ASSERT_OK(system(ping_cmd), ping_cmd);840 841 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");842 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");843 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");844cleanup:845 test_tc_link__destroy(skel);846 assert_mprog_count(target, 0);847}848 849void serial_test_tc_links_replace(void)850{851 test_tc_links_replace_target(BPF_TCX_INGRESS);852 test_tc_links_replace_target(BPF_TCX_EGRESS);853}854 855static void test_tc_links_invalid_target(int target)856{857 LIBBPF_OPTS(bpf_prog_query_opts, optq);858 LIBBPF_OPTS(bpf_tcx_opts, optl);859 __u32 pid1, pid2, lid1;860 struct test_tc_link *skel;861 struct bpf_link *link;862 int err;863 864 skel = test_tc_link__open();865 if (!ASSERT_OK_PTR(skel, "skel_open"))866 goto cleanup;867 868 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),869 0, "tc1_attach_type");870 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),871 0, "tc2_attach_type");872 873 err = test_tc_link__load(skel);874 if (!ASSERT_OK(err, "skel_load"))875 goto cleanup;876 877 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));878 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));879 880 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");881 882 assert_mprog_count(target, 0);883 884 optl.flags = BPF_F_BEFORE | BPF_F_AFTER;885 886 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);887 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {888 bpf_link__destroy(link);889 goto cleanup;890 }891 892 assert_mprog_count(target, 0);893 894 LIBBPF_OPTS_RESET(optl,895 .flags = BPF_F_BEFORE | BPF_F_ID,896 );897 898 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);899 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {900 bpf_link__destroy(link);901 goto cleanup;902 }903 904 assert_mprog_count(target, 0);905 906 LIBBPF_OPTS_RESET(optl,907 .flags = BPF_F_AFTER | BPF_F_ID,908 );909 910 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);911 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {912 bpf_link__destroy(link);913 goto cleanup;914 }915 916 assert_mprog_count(target, 0);917 918 LIBBPF_OPTS_RESET(optl,919 .flags = BPF_F_ID,920 );921 922 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);923 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {924 bpf_link__destroy(link);925 goto cleanup;926 }927 928 assert_mprog_count(target, 0);929 930 LIBBPF_OPTS_RESET(optl,931 .flags = BPF_F_LINK,932 .relative_fd = bpf_program__fd(skel->progs.tc2),933 );934 935 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);936 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {937 bpf_link__destroy(link);938 goto cleanup;939 }940 941 assert_mprog_count(target, 0);942 943 LIBBPF_OPTS_RESET(optl,944 .flags = BPF_F_LINK,945 );946 947 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);948 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {949 bpf_link__destroy(link);950 goto cleanup;951 }952 953 assert_mprog_count(target, 0);954 955 LIBBPF_OPTS_RESET(optl,956 .relative_fd = bpf_program__fd(skel->progs.tc2),957 );958 959 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);960 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {961 bpf_link__destroy(link);962 goto cleanup;963 }964 965 assert_mprog_count(target, 0);966 967 LIBBPF_OPTS_RESET(optl,968 .flags = BPF_F_BEFORE | BPF_F_AFTER,969 .relative_fd = bpf_program__fd(skel->progs.tc2),970 );971 972 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);973 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {974 bpf_link__destroy(link);975 goto cleanup;976 }977 978 assert_mprog_count(target, 0);979 980 LIBBPF_OPTS_RESET(optl,981 .flags = BPF_F_BEFORE,982 .relative_fd = bpf_program__fd(skel->progs.tc1),983 );984 985 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);986 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {987 bpf_link__destroy(link);988 goto cleanup;989 }990 991 assert_mprog_count(target, 0);992 993 LIBBPF_OPTS_RESET(optl,994 .flags = BPF_F_ID,995 .relative_id = pid2,996 );997 998 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);999 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1000 bpf_link__destroy(link);1001 goto cleanup;1002 }1003 1004 assert_mprog_count(target, 0);1005 1006 LIBBPF_OPTS_RESET(optl,1007 .flags = BPF_F_ID,1008 .relative_id = 42,1009 );1010 1011 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1012 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1013 bpf_link__destroy(link);1014 goto cleanup;1015 }1016 1017 assert_mprog_count(target, 0);1018 1019 LIBBPF_OPTS_RESET(optl,1020 .flags = BPF_F_BEFORE,1021 .relative_fd = bpf_program__fd(skel->progs.tc1),1022 );1023 1024 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1025 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1026 bpf_link__destroy(link);1027 goto cleanup;1028 }1029 1030 assert_mprog_count(target, 0);1031 1032 LIBBPF_OPTS_RESET(optl,1033 .flags = BPF_F_BEFORE | BPF_F_LINK,1034 .relative_fd = bpf_program__fd(skel->progs.tc1),1035 );1036 1037 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1038 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1039 bpf_link__destroy(link);1040 goto cleanup;1041 }1042 1043 assert_mprog_count(target, 0);1044 1045 LIBBPF_OPTS_RESET(optl,1046 .flags = BPF_F_AFTER,1047 .relative_fd = bpf_program__fd(skel->progs.tc1),1048 );1049 1050 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1051 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1052 bpf_link__destroy(link);1053 goto cleanup;1054 }1055 1056 assert_mprog_count(target, 0);1057 1058 LIBBPF_OPTS_RESET(optl);1059 1060 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl);1061 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1062 bpf_link__destroy(link);1063 goto cleanup;1064 }1065 1066 assert_mprog_count(target, 0);1067 1068 LIBBPF_OPTS_RESET(optl,1069 .flags = BPF_F_AFTER | BPF_F_LINK,1070 .relative_fd = bpf_program__fd(skel->progs.tc1),1071 );1072 1073 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1074 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1075 bpf_link__destroy(link);1076 goto cleanup;1077 }1078 1079 assert_mprog_count(target, 0);1080 1081 LIBBPF_OPTS_RESET(optl);1082 1083 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1084 if (!ASSERT_OK_PTR(link, "link_attach"))1085 goto cleanup;1086 1087 skel->links.tc1 = link;1088 1089 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1090 1091 assert_mprog_count(target, 1);1092 1093 LIBBPF_OPTS_RESET(optl,1094 .flags = BPF_F_AFTER | BPF_F_LINK,1095 .relative_fd = bpf_program__fd(skel->progs.tc1),1096 );1097 1098 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1099 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1100 bpf_link__destroy(link);1101 goto cleanup;1102 }1103 1104 assert_mprog_count(target, 1);1105 1106 LIBBPF_OPTS_RESET(optl,1107 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1108 .relative_id = ~0,1109 );1110 1111 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1112 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1113 bpf_link__destroy(link);1114 goto cleanup;1115 }1116 1117 assert_mprog_count(target, 1);1118 1119 LIBBPF_OPTS_RESET(optl,1120 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1121 .relative_id = lid1,1122 );1123 1124 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1125 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1126 bpf_link__destroy(link);1127 goto cleanup;1128 }1129 1130 assert_mprog_count(target, 1);1131 1132 LIBBPF_OPTS_RESET(optl,1133 .flags = BPF_F_BEFORE | BPF_F_ID,1134 .relative_id = pid1,1135 );1136 1137 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1138 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1139 bpf_link__destroy(link);1140 goto cleanup;1141 }1142 assert_mprog_count(target, 1);1143 1144 LIBBPF_OPTS_RESET(optl,1145 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1146 .relative_id = lid1,1147 );1148 1149 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1150 if (!ASSERT_OK_PTR(link, "link_attach"))1151 goto cleanup;1152 1153 skel->links.tc2 = link;1154 1155 assert_mprog_count(target, 2);1156cleanup:1157 test_tc_link__destroy(skel);1158 assert_mprog_count(target, 0);1159}1160 1161void serial_test_tc_links_invalid(void)1162{1163 test_tc_links_invalid_target(BPF_TCX_INGRESS);1164 test_tc_links_invalid_target(BPF_TCX_EGRESS);1165}1166 1167static void test_tc_links_prepend_target(int target)1168{1169 LIBBPF_OPTS(bpf_prog_query_opts, optq);1170 LIBBPF_OPTS(bpf_tcx_opts, optl);1171 __u32 prog_ids[5], link_ids[5];1172 __u32 pid1, pid2, pid3, pid4;1173 __u32 lid1, lid2, lid3, lid4;1174 struct test_tc_link *skel;1175 struct bpf_link *link;1176 int err;1177 1178 skel = test_tc_link__open();1179 if (!ASSERT_OK_PTR(skel, "skel_open"))1180 goto cleanup;1181 1182 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1183 0, "tc1_attach_type");1184 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1185 0, "tc2_attach_type");1186 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1187 0, "tc3_attach_type");1188 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1189 0, "tc4_attach_type");1190 1191 err = test_tc_link__load(skel);1192 if (!ASSERT_OK(err, "skel_load"))1193 goto cleanup;1194 1195 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1196 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1197 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1198 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1199 1200 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1201 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1202 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1203 1204 assert_mprog_count(target, 0);1205 1206 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1207 if (!ASSERT_OK_PTR(link, "link_attach"))1208 goto cleanup;1209 1210 skel->links.tc1 = link;1211 1212 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1213 1214 assert_mprog_count(target, 1);1215 1216 LIBBPF_OPTS_RESET(optl,1217 .flags = BPF_F_BEFORE,1218 );1219 1220 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1221 if (!ASSERT_OK_PTR(link, "link_attach"))1222 goto cleanup;1223 1224 skel->links.tc2 = link;1225 1226 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1227 1228 assert_mprog_count(target, 2);1229 1230 optq.prog_ids = prog_ids;1231 optq.link_ids = link_ids;1232 1233 memset(prog_ids, 0, sizeof(prog_ids));1234 memset(link_ids, 0, sizeof(link_ids));1235 optq.count = ARRAY_SIZE(prog_ids);1236 1237 err = bpf_prog_query_opts(loopback, target, &optq);1238 if (!ASSERT_OK(err, "prog_query"))1239 goto cleanup;1240 1241 ASSERT_EQ(optq.count, 2, "count");1242 ASSERT_EQ(optq.revision, 3, "revision");1243 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");1244 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");1245 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");1246 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");1247 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1248 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");1249 1250 tc_skel_reset_all_seen(skel);1251 ASSERT_OK(system(ping_cmd), ping_cmd);1252 1253 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1254 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1255 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1256 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1257 1258 LIBBPF_OPTS_RESET(optl,1259 .flags = BPF_F_BEFORE,1260 );1261 1262 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);1263 if (!ASSERT_OK_PTR(link, "link_attach"))1264 goto cleanup;1265 1266 skel->links.tc3 = link;1267 1268 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));1269 1270 LIBBPF_OPTS_RESET(optl,1271 .flags = BPF_F_BEFORE,1272 );1273 1274 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1275 if (!ASSERT_OK_PTR(link, "link_attach"))1276 goto cleanup;1277 1278 skel->links.tc4 = link;1279 1280 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1281 1282 assert_mprog_count(target, 4);1283 1284 memset(prog_ids, 0, sizeof(prog_ids));1285 memset(link_ids, 0, sizeof(link_ids));1286 optq.count = ARRAY_SIZE(prog_ids);1287 1288 err = bpf_prog_query_opts(loopback, target, &optq);1289 if (!ASSERT_OK(err, "prog_query"))1290 goto cleanup;1291 1292 ASSERT_EQ(optq.count, 4, "count");1293 ASSERT_EQ(optq.revision, 5, "revision");1294 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");1295 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");1296 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");1297 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");1298 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");1299 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");1300 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]");1301 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]");1302 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1303 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");1304 1305 tc_skel_reset_all_seen(skel);1306 ASSERT_OK(system(ping_cmd), ping_cmd);1307 1308 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1309 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1310 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1311 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1312cleanup:1313 test_tc_link__destroy(skel);1314 assert_mprog_count(target, 0);1315}1316 1317void serial_test_tc_links_prepend(void)1318{1319 test_tc_links_prepend_target(BPF_TCX_INGRESS);1320 test_tc_links_prepend_target(BPF_TCX_EGRESS);1321}1322 1323static void test_tc_links_append_target(int target)1324{1325 LIBBPF_OPTS(bpf_prog_query_opts, optq);1326 LIBBPF_OPTS(bpf_tcx_opts, optl);1327 __u32 prog_ids[5], link_ids[5];1328 __u32 pid1, pid2, pid3, pid4;1329 __u32 lid1, lid2, lid3, lid4;1330 struct test_tc_link *skel;1331 struct bpf_link *link;1332 int err;1333 1334 skel = test_tc_link__open();1335 if (!ASSERT_OK_PTR(skel, "skel_open"))1336 goto cleanup;1337 1338 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1339 0, "tc1_attach_type");1340 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1341 0, "tc2_attach_type");1342 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1343 0, "tc3_attach_type");1344 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1345 0, "tc4_attach_type");1346 1347 err = test_tc_link__load(skel);1348 if (!ASSERT_OK(err, "skel_load"))1349 goto cleanup;1350 1351 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1352 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1353 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1354 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1355 1356 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1357 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1358 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1359 1360 assert_mprog_count(target, 0);1361 1362 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1363 if (!ASSERT_OK_PTR(link, "link_attach"))1364 goto cleanup;1365 1366 skel->links.tc1 = link;1367 1368 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1369 1370 assert_mprog_count(target, 1);1371 1372 LIBBPF_OPTS_RESET(optl,1373 .flags = BPF_F_AFTER,1374 );1375 1376 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1377 if (!ASSERT_OK_PTR(link, "link_attach"))1378 goto cleanup;1379 1380 skel->links.tc2 = link;1381 1382 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1383 1384 assert_mprog_count(target, 2);1385 1386 optq.prog_ids = prog_ids;1387 optq.link_ids = link_ids;1388 1389 memset(prog_ids, 0, sizeof(prog_ids));1390 memset(link_ids, 0, sizeof(link_ids));1391 optq.count = ARRAY_SIZE(prog_ids);1392 1393 err = bpf_prog_query_opts(loopback, target, &optq);1394 if (!ASSERT_OK(err, "prog_query"))1395 goto cleanup;1396 1397 ASSERT_EQ(optq.count, 2, "count");1398 ASSERT_EQ(optq.revision, 3, "revision");1399 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");1400 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");1401 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1402 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1403 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1404 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");1405 1406 tc_skel_reset_all_seen(skel);1407 ASSERT_OK(system(ping_cmd), ping_cmd);1408 1409 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1410 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1411 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1412 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1413 1414 LIBBPF_OPTS_RESET(optl,1415 .flags = BPF_F_AFTER,1416 );1417 1418 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);1419 if (!ASSERT_OK_PTR(link, "link_attach"))1420 goto cleanup;1421 1422 skel->links.tc3 = link;1423 1424 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));1425 1426 LIBBPF_OPTS_RESET(optl,1427 .flags = BPF_F_AFTER,1428 );1429 1430 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1431 if (!ASSERT_OK_PTR(link, "link_attach"))1432 goto cleanup;1433 1434 skel->links.tc4 = link;1435 1436 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1437 1438 assert_mprog_count(target, 4);1439 1440 memset(prog_ids, 0, sizeof(prog_ids));1441 memset(link_ids, 0, sizeof(link_ids));1442 optq.count = ARRAY_SIZE(prog_ids);1443 1444 err = bpf_prog_query_opts(loopback, target, &optq);1445 if (!ASSERT_OK(err, "prog_query"))1446 goto cleanup;1447 1448 ASSERT_EQ(optq.count, 4, "count");1449 ASSERT_EQ(optq.revision, 5, "revision");1450 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");1451 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");1452 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1453 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1454 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");1455 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");1456 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");1457 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");1458 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1459 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");1460 1461 tc_skel_reset_all_seen(skel);1462 ASSERT_OK(system(ping_cmd), ping_cmd);1463 1464 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1465 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1466 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1467 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1468cleanup:1469 test_tc_link__destroy(skel);1470 assert_mprog_count(target, 0);1471}1472 1473void serial_test_tc_links_append(void)1474{1475 test_tc_links_append_target(BPF_TCX_INGRESS);1476 test_tc_links_append_target(BPF_TCX_EGRESS);1477}1478 1479static void test_tc_links_dev_cleanup_target(int target)1480{1481 LIBBPF_OPTS(bpf_tcx_opts, optl);1482 LIBBPF_OPTS(bpf_prog_query_opts, optq);1483 __u32 pid1, pid2, pid3, pid4;1484 struct test_tc_link *skel;1485 struct bpf_link *link;1486 int err, ifindex;1487 1488 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1489 ifindex = if_nametoindex("tcx_opts1");1490 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1491 1492 skel = test_tc_link__open();1493 if (!ASSERT_OK_PTR(skel, "skel_open"))1494 goto cleanup;1495 1496 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1497 0, "tc1_attach_type");1498 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1499 0, "tc2_attach_type");1500 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1501 0, "tc3_attach_type");1502 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1503 0, "tc4_attach_type");1504 1505 err = test_tc_link__load(skel);1506 if (!ASSERT_OK(err, "skel_load"))1507 goto cleanup;1508 1509 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1510 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1511 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1512 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1513 1514 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1515 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1516 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1517 1518 assert_mprog_count(target, 0);1519 1520 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);1521 if (!ASSERT_OK_PTR(link, "link_attach"))1522 goto cleanup;1523 1524 skel->links.tc1 = link;1525 1526 assert_mprog_count_ifindex(ifindex, target, 1);1527 1528 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);1529 if (!ASSERT_OK_PTR(link, "link_attach"))1530 goto cleanup;1531 1532 skel->links.tc2 = link;1533 1534 assert_mprog_count_ifindex(ifindex, target, 2);1535 1536 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);1537 if (!ASSERT_OK_PTR(link, "link_attach"))1538 goto cleanup;1539 1540 skel->links.tc3 = link;1541 1542 assert_mprog_count_ifindex(ifindex, target, 3);1543 1544 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);1545 if (!ASSERT_OK_PTR(link, "link_attach"))1546 goto cleanup;1547 1548 skel->links.tc4 = link;1549 1550 assert_mprog_count_ifindex(ifindex, target, 4);1551 1552 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1553 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1554 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1555 1556 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");1557 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");1558 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");1559 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");1560 1561 test_tc_link__destroy(skel);1562 return;1563cleanup:1564 test_tc_link__destroy(skel);1565 1566 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1567 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1568 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1569}1570 1571void serial_test_tc_links_dev_cleanup(void)1572{1573 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);1574 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);1575}1576 1577static void test_tc_chain_mixed(int target)1578{1579 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);1580 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);1581 LIBBPF_OPTS(bpf_tcx_opts, optl);1582 struct test_tc_link *skel;1583 struct bpf_link *link;1584 __u32 pid1, pid2, pid3;1585 int err;1586 1587 skel = test_tc_link__open();1588 if (!ASSERT_OK_PTR(skel, "skel_open"))1589 goto cleanup;1590 1591 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1592 0, "tc4_attach_type");1593 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),1594 0, "tc5_attach_type");1595 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),1596 0, "tc6_attach_type");1597 1598 err = test_tc_link__load(skel);1599 if (!ASSERT_OK(err, "skel_load"))1600 goto cleanup;1601 1602 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1603 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));1604 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));1605 1606 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1607 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1608 1609 assert_mprog_count(target, 0);1610 1611 tc_hook.attach_point = target == BPF_TCX_INGRESS ?1612 BPF_TC_INGRESS : BPF_TC_EGRESS;1613 err = bpf_tc_hook_create(&tc_hook);1614 err = err == -EEXIST ? 0 : err;1615 if (!ASSERT_OK(err, "bpf_tc_hook_create"))1616 goto cleanup;1617 1618 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);1619 err = bpf_tc_attach(&tc_hook, &tc_opts);1620 if (!ASSERT_OK(err, "bpf_tc_attach"))1621 goto cleanup;1622 1623 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);1624 if (!ASSERT_OK_PTR(link, "link_attach"))1625 goto cleanup;1626 1627 skel->links.tc6 = link;1628 1629 assert_mprog_count(target, 1);1630 1631 tc_skel_reset_all_seen(skel);1632 ASSERT_OK(system(ping_cmd), ping_cmd);1633 1634 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1635 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");1636 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");1637 1638 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);1639 if (!ASSERT_OK(err, "link_update"))1640 goto cleanup;1641 1642 assert_mprog_count(target, 1);1643 1644 tc_skel_reset_all_seen(skel);1645 ASSERT_OK(system(ping_cmd), ping_cmd);1646 1647 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1648 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");1649 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");1650 1651 err = bpf_link__detach(skel->links.tc6);1652 if (!ASSERT_OK(err, "prog_detach"))1653 goto cleanup;1654 1655 assert_mprog_count(target, 0);1656 1657 tc_skel_reset_all_seen(skel);1658 ASSERT_OK(system(ping_cmd), ping_cmd);1659 1660 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1661 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");1662 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");1663 1664cleanup:1665 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;1666 err = bpf_tc_detach(&tc_hook, &tc_opts);1667 ASSERT_OK(err, "bpf_tc_detach");1668 1669 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;1670 bpf_tc_hook_destroy(&tc_hook);1671 1672 test_tc_link__destroy(skel);1673}1674 1675void serial_test_tc_links_chain_mixed(void)1676{1677 test_tc_chain_mixed(BPF_TCX_INGRESS);1678 test_tc_chain_mixed(BPF_TCX_EGRESS);1679}1680 1681static void test_tc_links_ingress(int target, bool chain_tc_old,1682 bool tcx_teardown_first)1683{1684 LIBBPF_OPTS(bpf_tc_opts, tc_opts,1685 .handle = 1,1686 .priority = 1,1687 );1688 LIBBPF_OPTS(bpf_tc_hook, tc_hook,1689 .ifindex = loopback,1690 .attach_point = BPF_TC_CUSTOM,1691 .parent = TC_H_INGRESS,1692 );1693 bool hook_created = false, tc_attached = false;1694 LIBBPF_OPTS(bpf_tcx_opts, optl);1695 __u32 pid1, pid2, pid3;1696 struct test_tc_link *skel;1697 struct bpf_link *link;1698 int err;1699 1700 skel = test_tc_link__open();1701 if (!ASSERT_OK_PTR(skel, "skel_open"))1702 goto cleanup;1703 1704 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1705 0, "tc1_attach_type");1706 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1707 0, "tc2_attach_type");1708 1709 err = test_tc_link__load(skel);1710 if (!ASSERT_OK(err, "skel_load"))1711 goto cleanup;1712 1713 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1714 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1715 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1716 1717 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1718 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1719 1720 assert_mprog_count(target, 0);1721 1722 if (chain_tc_old) {1723 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");1724 hook_created = true;1725 1726 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);1727 err = bpf_tc_attach(&tc_hook, &tc_opts);1728 if (!ASSERT_OK(err, "bpf_tc_attach"))1729 goto cleanup;1730 tc_attached = true;1731 }1732 1733 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1734 if (!ASSERT_OK_PTR(link, "link_attach"))1735 goto cleanup;1736 1737 skel->links.tc1 = link;1738 1739 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1740 if (!ASSERT_OK_PTR(link, "link_attach"))1741 goto cleanup;1742 1743 skel->links.tc2 = link;1744 1745 assert_mprog_count(target, 2);1746 1747 tc_skel_reset_all_seen(skel);1748 ASSERT_OK(system(ping_cmd), ping_cmd);1749 1750 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1751 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1752 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");1753 1754 err = bpf_link__detach(skel->links.tc2);1755 if (!ASSERT_OK(err, "prog_detach"))1756 goto cleanup;1757 1758 assert_mprog_count(target, 1);1759 1760 tc_skel_reset_all_seen(skel);1761 ASSERT_OK(system(ping_cmd), ping_cmd);1762 1763 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1764 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");1765 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");1766cleanup:1767 if (tc_attached) {1768 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;1769 err = bpf_tc_detach(&tc_hook, &tc_opts);1770 ASSERT_OK(err, "bpf_tc_detach");1771 }1772 ASSERT_OK(system(ping_cmd), ping_cmd);1773 assert_mprog_count(target, 1);1774 if (hook_created && tcx_teardown_first)1775 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");1776 ASSERT_OK(system(ping_cmd), ping_cmd);1777 test_tc_link__destroy(skel);1778 ASSERT_OK(system(ping_cmd), ping_cmd);1779 if (hook_created && !tcx_teardown_first)1780 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");1781 ASSERT_OK(system(ping_cmd), ping_cmd);1782 assert_mprog_count(target, 0);1783}1784 1785void serial_test_tc_links_ingress(void)1786{1787 test_tc_links_ingress(BPF_TCX_INGRESS, true, true);1788 test_tc_links_ingress(BPF_TCX_INGRESS, true, false);1789 test_tc_links_ingress(BPF_TCX_INGRESS, false, false);1790}1791 1792struct qdisc_req {1793 struct nlmsghdr n;1794 struct tcmsg t;1795 char buf[1024];1796};1797 1798static int qdisc_replace(int ifindex, const char *kind, bool block)1799{1800 struct rtnl_handle rth = { .fd = -1 };1801 struct qdisc_req req;1802 int err;1803 1804 err = rtnl_open(&rth, 0);1805 if (!ASSERT_OK(err, "open_rtnetlink"))1806 return err;1807 1808 memset(&req, 0, sizeof(req));1809 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));1810 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST;1811 req.n.nlmsg_type = RTM_NEWQDISC;1812 req.t.tcm_family = AF_UNSPEC;1813 req.t.tcm_ifindex = ifindex;1814 req.t.tcm_parent = 0xfffffff1;1815 1816 addattr_l(&req.n, sizeof(req), TCA_KIND, kind, strlen(kind) + 1);1817 if (block)1818 addattr32(&req.n, sizeof(req), TCA_INGRESS_BLOCK, 1);1819 1820 err = rtnl_talk(&rth, &req.n, NULL);1821 ASSERT_OK(err, "talk_rtnetlink");1822 rtnl_close(&rth);1823 return err;1824}1825 1826void serial_test_tc_links_dev_chain0(void)1827{1828 int err, ifindex;1829 1830 ASSERT_OK(system("ip link add dev foo type veth peer name bar"), "add veth");1831 ifindex = if_nametoindex("foo");1832 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1833 err = qdisc_replace(ifindex, "ingress", true);1834 if (!ASSERT_OK(err, "attaching ingress"))1835 goto cleanup;1836 ASSERT_OK(system("tc filter add block 1 matchall action skbmod swap mac"), "add block");1837 err = qdisc_replace(ifindex, "clsact", false);1838 if (!ASSERT_OK(err, "attaching clsact"))1839 goto cleanup;1840 /* Heuristic: kern_sync_rcu() alone does not work; a wait-time of ~5s1841 * triggered the issue without the fix reliably 100% of the time.1842 */1843 sleep(5);1844 ASSERT_OK(system("tc filter add dev foo ingress matchall action skbmod swap mac"), "add filter");1845cleanup:1846 ASSERT_OK(system("ip link del dev foo"), "del veth");1847 ASSERT_EQ(if_nametoindex("foo"), 0, "foo removed");1848 ASSERT_EQ(if_nametoindex("bar"), 0, "bar removed");1849}1850 1851static void test_tc_links_dev_mixed(int target)1852{1853 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);1854 LIBBPF_OPTS(bpf_tc_hook, tc_hook);1855 LIBBPF_OPTS(bpf_tcx_opts, optl);1856 __u32 pid1, pid2, pid3, pid4;1857 struct test_tc_link *skel;1858 struct bpf_link *link;1859 int err, ifindex;1860 1861 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1862 ifindex = if_nametoindex("tcx_opts1");1863 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1864 1865 skel = test_tc_link__open();1866 if (!ASSERT_OK_PTR(skel, "skel_open"))1867 goto cleanup;1868 1869 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1870 0, "tc1_attach_type");1871 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1872 0, "tc2_attach_type");1873 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1874 0, "tc3_attach_type");1875 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1876 0, "tc4_attach_type");1877 1878 err = test_tc_link__load(skel);1879 if (!ASSERT_OK(err, "skel_load"))1880 goto cleanup;1881 1882 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1883 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1884 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1885 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1886 1887 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1888 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1889 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1890 1891 assert_mprog_count(target, 0);1892 1893 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);1894 if (!ASSERT_OK_PTR(link, "link_attach"))1895 goto cleanup;1896 1897 skel->links.tc1 = link;1898 1899 assert_mprog_count_ifindex(ifindex, target, 1);1900 1901 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);1902 if (!ASSERT_OK_PTR(link, "link_attach"))1903 goto cleanup;1904 1905 skel->links.tc2 = link;1906 1907 assert_mprog_count_ifindex(ifindex, target, 2);1908 1909 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);1910 if (!ASSERT_OK_PTR(link, "link_attach"))1911 goto cleanup;1912 1913 skel->links.tc3 = link;1914 1915 assert_mprog_count_ifindex(ifindex, target, 3);1916 1917 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);1918 if (!ASSERT_OK_PTR(link, "link_attach"))1919 goto cleanup;1920 1921 skel->links.tc4 = link;1922 1923 assert_mprog_count_ifindex(ifindex, target, 4);1924 1925 tc_hook.ifindex = ifindex;1926 tc_hook.attach_point = target == BPF_TCX_INGRESS ?1927 BPF_TC_INGRESS : BPF_TC_EGRESS;1928 1929 err = bpf_tc_hook_create(&tc_hook);1930 err = err == -EEXIST ? 0 : err;1931 if (!ASSERT_OK(err, "bpf_tc_hook_create"))1932 goto cleanup;1933 1934 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);1935 err = bpf_tc_attach(&tc_hook, &tc_opts);1936 if (!ASSERT_OK(err, "bpf_tc_attach"))1937 goto cleanup;1938 1939 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1940 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1941 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1942 1943 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");1944 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");1945 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");1946 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");1947 1948 test_tc_link__destroy(skel);1949 return;1950cleanup:1951 test_tc_link__destroy(skel);1952 1953 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1954 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1955 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1956}1957 1958void serial_test_tc_links_dev_mixed(void)1959{1960 test_tc_links_dev_mixed(BPF_TCX_INGRESS);1961 test_tc_links_dev_mixed(BPF_TCX_EGRESS);1962}1963