2815 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3#include <uapi/linux/if_link.h>4#include <net/if.h>5#include <test_progs.h>6 7#define loopback 18#define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"9 10#include "test_tc_link.skel.h"11#include "tc_helpers.h"12 13void serial_test_tc_opts_basic(void)14{15 LIBBPF_OPTS(bpf_prog_attach_opts, opta);16 LIBBPF_OPTS(bpf_prog_detach_opts, optd);17 LIBBPF_OPTS(bpf_prog_query_opts, optq);18 __u32 fd1, fd2, id1, id2;19 struct test_tc_link *skel;20 __u32 prog_ids[2];21 int err;22 23 skel = test_tc_link__open_and_load();24 if (!ASSERT_OK_PTR(skel, "skel_load"))25 goto cleanup;26 27 fd1 = bpf_program__fd(skel->progs.tc1);28 fd2 = bpf_program__fd(skel->progs.tc2);29 30 id1 = id_from_prog_fd(fd1);31 id2 = id_from_prog_fd(fd2);32 33 ASSERT_NEQ(id1, id2, "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 err = bpf_prog_attach_opts(fd1, loopback, BPF_TCX_INGRESS, &opta);42 if (!ASSERT_EQ(err, 0, "prog_attach"))43 goto cleanup;44 45 assert_mprog_count(BPF_TCX_INGRESS, 1);46 assert_mprog_count(BPF_TCX_EGRESS, 0);47 48 optq.prog_ids = prog_ids;49 50 memset(prog_ids, 0, sizeof(prog_ids));51 optq.count = ARRAY_SIZE(prog_ids);52 53 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);54 if (!ASSERT_OK(err, "prog_query"))55 goto cleanup_in;56 57 ASSERT_EQ(optq.count, 1, "count");58 ASSERT_EQ(optq.revision, 2, "revision");59 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");60 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");61 62 tc_skel_reset_all_seen(skel);63 ASSERT_OK(system(ping_cmd), ping_cmd);64 65 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");66 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");67 68 err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta);69 if (!ASSERT_EQ(err, 0, "prog_attach"))70 goto cleanup_in;71 72 assert_mprog_count(BPF_TCX_INGRESS, 1);73 assert_mprog_count(BPF_TCX_EGRESS, 1);74 75 memset(prog_ids, 0, sizeof(prog_ids));76 optq.count = ARRAY_SIZE(prog_ids);77 78 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);79 if (!ASSERT_OK(err, "prog_query"))80 goto cleanup_eg;81 82 ASSERT_EQ(optq.count, 1, "count");83 ASSERT_EQ(optq.revision, 2, "revision");84 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");85 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");86 87 tc_skel_reset_all_seen(skel);88 ASSERT_OK(system(ping_cmd), ping_cmd);89 90 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");91 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");92 93cleanup_eg:94 err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd);95 ASSERT_OK(err, "prog_detach_eg");96 97 assert_mprog_count(BPF_TCX_INGRESS, 1);98 assert_mprog_count(BPF_TCX_EGRESS, 0);99 100cleanup_in:101 err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd);102 ASSERT_OK(err, "prog_detach_in");103 104 assert_mprog_count(BPF_TCX_INGRESS, 0);105 assert_mprog_count(BPF_TCX_EGRESS, 0);106 107cleanup:108 test_tc_link__destroy(skel);109}110 111static void test_tc_opts_before_target(int target)112{113 LIBBPF_OPTS(bpf_prog_attach_opts, opta);114 LIBBPF_OPTS(bpf_prog_detach_opts, optd);115 LIBBPF_OPTS(bpf_prog_query_opts, optq);116 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;117 struct test_tc_link *skel;118 __u32 prog_ids[5];119 int err;120 121 skel = test_tc_link__open_and_load();122 if (!ASSERT_OK_PTR(skel, "skel_load"))123 goto cleanup;124 125 fd1 = bpf_program__fd(skel->progs.tc1);126 fd2 = bpf_program__fd(skel->progs.tc2);127 fd3 = bpf_program__fd(skel->progs.tc3);128 fd4 = bpf_program__fd(skel->progs.tc4);129 130 id1 = id_from_prog_fd(fd1);131 id2 = id_from_prog_fd(fd2);132 id3 = id_from_prog_fd(fd3);133 id4 = id_from_prog_fd(fd4);134 135 ASSERT_NEQ(id1, id2, "prog_ids_1_2");136 ASSERT_NEQ(id3, id4, "prog_ids_3_4");137 ASSERT_NEQ(id2, id3, "prog_ids_2_3");138 139 assert_mprog_count(target, 0);140 141 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);142 if (!ASSERT_EQ(err, 0, "prog_attach"))143 goto cleanup;144 145 assert_mprog_count(target, 1);146 147 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);148 if (!ASSERT_EQ(err, 0, "prog_attach"))149 goto cleanup_target;150 151 assert_mprog_count(target, 2);152 153 optq.prog_ids = prog_ids;154 155 memset(prog_ids, 0, sizeof(prog_ids));156 optq.count = ARRAY_SIZE(prog_ids);157 158 err = bpf_prog_query_opts(loopback, target, &optq);159 if (!ASSERT_OK(err, "prog_query"))160 goto cleanup_target2;161 162 ASSERT_EQ(optq.count, 2, "count");163 ASSERT_EQ(optq.revision, 3, "revision");164 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");165 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");166 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");167 168 tc_skel_reset_all_seen(skel);169 ASSERT_OK(system(ping_cmd), ping_cmd);170 171 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");172 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");173 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");174 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");175 176 LIBBPF_OPTS_RESET(opta,177 .flags = BPF_F_BEFORE,178 .relative_fd = fd2,179 );180 181 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);182 if (!ASSERT_EQ(err, 0, "prog_attach"))183 goto cleanup_target2;184 185 memset(prog_ids, 0, sizeof(prog_ids));186 optq.count = ARRAY_SIZE(prog_ids);187 188 err = bpf_prog_query_opts(loopback, target, &optq);189 if (!ASSERT_OK(err, "prog_query"))190 goto cleanup_target3;191 192 ASSERT_EQ(optq.count, 3, "count");193 ASSERT_EQ(optq.revision, 4, "revision");194 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");195 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");196 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");197 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");198 199 LIBBPF_OPTS_RESET(opta,200 .flags = BPF_F_BEFORE,201 .relative_id = id1,202 );203 204 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);205 if (!ASSERT_EQ(err, 0, "prog_attach"))206 goto cleanup_target3;207 208 assert_mprog_count(target, 4);209 210 memset(prog_ids, 0, sizeof(prog_ids));211 optq.count = ARRAY_SIZE(prog_ids);212 213 err = bpf_prog_query_opts(loopback, target, &optq);214 if (!ASSERT_OK(err, "prog_query"))215 goto cleanup_target4;216 217 ASSERT_EQ(optq.count, 4, "count");218 ASSERT_EQ(optq.revision, 5, "revision");219 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");220 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");221 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");222 ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");223 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");224 225 tc_skel_reset_all_seen(skel);226 ASSERT_OK(system(ping_cmd), ping_cmd);227 228 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");229 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");230 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");231 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");232 233cleanup_target4:234 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);235 ASSERT_OK(err, "prog_detach");236 assert_mprog_count(target, 3);237 238cleanup_target3:239 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);240 ASSERT_OK(err, "prog_detach");241 assert_mprog_count(target, 2);242 243cleanup_target2:244 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);245 ASSERT_OK(err, "prog_detach");246 assert_mprog_count(target, 1);247 248cleanup_target:249 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);250 ASSERT_OK(err, "prog_detach");251 assert_mprog_count(target, 0);252 253cleanup:254 test_tc_link__destroy(skel);255}256 257void serial_test_tc_opts_before(void)258{259 test_tc_opts_before_target(BPF_TCX_INGRESS);260 test_tc_opts_before_target(BPF_TCX_EGRESS);261}262 263static void test_tc_opts_after_target(int target)264{265 LIBBPF_OPTS(bpf_prog_attach_opts, opta);266 LIBBPF_OPTS(bpf_prog_detach_opts, optd);267 LIBBPF_OPTS(bpf_prog_query_opts, optq);268 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;269 struct test_tc_link *skel;270 __u32 prog_ids[5];271 int err;272 273 skel = test_tc_link__open_and_load();274 if (!ASSERT_OK_PTR(skel, "skel_load"))275 goto cleanup;276 277 fd1 = bpf_program__fd(skel->progs.tc1);278 fd2 = bpf_program__fd(skel->progs.tc2);279 fd3 = bpf_program__fd(skel->progs.tc3);280 fd4 = bpf_program__fd(skel->progs.tc4);281 282 id1 = id_from_prog_fd(fd1);283 id2 = id_from_prog_fd(fd2);284 id3 = id_from_prog_fd(fd3);285 id4 = id_from_prog_fd(fd4);286 287 ASSERT_NEQ(id1, id2, "prog_ids_1_2");288 ASSERT_NEQ(id3, id4, "prog_ids_3_4");289 ASSERT_NEQ(id2, id3, "prog_ids_2_3");290 291 assert_mprog_count(target, 0);292 293 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);294 if (!ASSERT_EQ(err, 0, "prog_attach"))295 goto cleanup;296 297 assert_mprog_count(target, 1);298 299 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);300 if (!ASSERT_EQ(err, 0, "prog_attach"))301 goto cleanup_target;302 303 assert_mprog_count(target, 2);304 305 optq.prog_ids = prog_ids;306 307 memset(prog_ids, 0, sizeof(prog_ids));308 optq.count = ARRAY_SIZE(prog_ids);309 310 err = bpf_prog_query_opts(loopback, target, &optq);311 if (!ASSERT_OK(err, "prog_query"))312 goto cleanup_target2;313 314 ASSERT_EQ(optq.count, 2, "count");315 ASSERT_EQ(optq.revision, 3, "revision");316 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");317 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");318 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");319 320 tc_skel_reset_all_seen(skel);321 ASSERT_OK(system(ping_cmd), ping_cmd);322 323 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");324 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");325 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");326 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");327 328 LIBBPF_OPTS_RESET(opta,329 .flags = BPF_F_AFTER,330 .relative_fd = fd1,331 );332 333 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);334 if (!ASSERT_EQ(err, 0, "prog_attach"))335 goto cleanup_target2;336 337 memset(prog_ids, 0, sizeof(prog_ids));338 optq.count = ARRAY_SIZE(prog_ids);339 340 err = bpf_prog_query_opts(loopback, target, &optq);341 if (!ASSERT_OK(err, "prog_query"))342 goto cleanup_target3;343 344 ASSERT_EQ(optq.count, 3, "count");345 ASSERT_EQ(optq.revision, 4, "revision");346 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");347 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");348 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");349 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");350 351 LIBBPF_OPTS_RESET(opta,352 .flags = BPF_F_AFTER,353 .relative_id = id2,354 );355 356 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);357 if (!ASSERT_EQ(err, 0, "prog_attach"))358 goto cleanup_target3;359 360 assert_mprog_count(target, 4);361 362 memset(prog_ids, 0, sizeof(prog_ids));363 optq.count = ARRAY_SIZE(prog_ids);364 365 err = bpf_prog_query_opts(loopback, target, &optq);366 if (!ASSERT_OK(err, "prog_query"))367 goto cleanup_target4;368 369 ASSERT_EQ(optq.count, 4, "count");370 ASSERT_EQ(optq.revision, 5, "revision");371 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");372 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");373 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");374 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");375 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");376 377 tc_skel_reset_all_seen(skel);378 ASSERT_OK(system(ping_cmd), ping_cmd);379 380 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");381 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");382 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");383 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");384 385cleanup_target4:386 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);387 ASSERT_OK(err, "prog_detach");388 assert_mprog_count(target, 3);389 390 memset(prog_ids, 0, sizeof(prog_ids));391 optq.count = ARRAY_SIZE(prog_ids);392 393 err = bpf_prog_query_opts(loopback, target, &optq);394 if (!ASSERT_OK(err, "prog_query"))395 goto cleanup_target3;396 397 ASSERT_EQ(optq.count, 3, "count");398 ASSERT_EQ(optq.revision, 6, "revision");399 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");400 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");401 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");402 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");403 404cleanup_target3:405 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);406 ASSERT_OK(err, "prog_detach");407 assert_mprog_count(target, 2);408 409 memset(prog_ids, 0, sizeof(prog_ids));410 optq.count = ARRAY_SIZE(prog_ids);411 412 err = bpf_prog_query_opts(loopback, target, &optq);413 if (!ASSERT_OK(err, "prog_query"))414 goto cleanup_target2;415 416 ASSERT_EQ(optq.count, 2, "count");417 ASSERT_EQ(optq.revision, 7, "revision");418 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");419 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");420 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");421 422cleanup_target2:423 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);424 ASSERT_OK(err, "prog_detach");425 assert_mprog_count(target, 1);426 427 memset(prog_ids, 0, sizeof(prog_ids));428 optq.count = ARRAY_SIZE(prog_ids);429 430 err = bpf_prog_query_opts(loopback, target, &optq);431 if (!ASSERT_OK(err, "prog_query"))432 goto cleanup_target;433 434 ASSERT_EQ(optq.count, 1, "count");435 ASSERT_EQ(optq.revision, 8, "revision");436 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");437 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");438 439cleanup_target:440 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);441 ASSERT_OK(err, "prog_detach");442 assert_mprog_count(target, 0);443 444cleanup:445 test_tc_link__destroy(skel);446}447 448void serial_test_tc_opts_after(void)449{450 test_tc_opts_after_target(BPF_TCX_INGRESS);451 test_tc_opts_after_target(BPF_TCX_EGRESS);452}453 454static void test_tc_opts_revision_target(int target)455{456 LIBBPF_OPTS(bpf_prog_attach_opts, opta);457 LIBBPF_OPTS(bpf_prog_detach_opts, optd);458 LIBBPF_OPTS(bpf_prog_query_opts, optq);459 __u32 fd1, fd2, id1, id2;460 struct test_tc_link *skel;461 __u32 prog_ids[3];462 int err;463 464 skel = test_tc_link__open_and_load();465 if (!ASSERT_OK_PTR(skel, "skel_load"))466 goto cleanup;467 468 fd1 = bpf_program__fd(skel->progs.tc1);469 fd2 = bpf_program__fd(skel->progs.tc2);470 471 id1 = id_from_prog_fd(fd1);472 id2 = id_from_prog_fd(fd2);473 474 ASSERT_NEQ(id1, id2, "prog_ids_1_2");475 476 assert_mprog_count(target, 0);477 478 LIBBPF_OPTS_RESET(opta,479 .expected_revision = 1,480 );481 482 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);483 if (!ASSERT_EQ(err, 0, "prog_attach"))484 goto cleanup;485 486 assert_mprog_count(target, 1);487 488 LIBBPF_OPTS_RESET(opta,489 .expected_revision = 1,490 );491 492 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);493 if (!ASSERT_EQ(err, -ESTALE, "prog_attach"))494 goto cleanup_target;495 496 assert_mprog_count(target, 1);497 498 LIBBPF_OPTS_RESET(opta,499 .expected_revision = 2,500 );501 502 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);503 if (!ASSERT_EQ(err, 0, "prog_attach"))504 goto cleanup_target;505 506 assert_mprog_count(target, 2);507 508 optq.prog_ids = prog_ids;509 510 memset(prog_ids, 0, sizeof(prog_ids));511 optq.count = ARRAY_SIZE(prog_ids);512 513 err = bpf_prog_query_opts(loopback, target, &optq);514 if (!ASSERT_OK(err, "prog_query"))515 goto cleanup_target2;516 517 ASSERT_EQ(optq.count, 2, "count");518 ASSERT_EQ(optq.revision, 3, "revision");519 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");520 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");521 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");522 523 tc_skel_reset_all_seen(skel);524 ASSERT_OK(system(ping_cmd), ping_cmd);525 526 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");527 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");528 529 LIBBPF_OPTS_RESET(optd,530 .expected_revision = 2,531 );532 533 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);534 ASSERT_EQ(err, -ESTALE, "prog_detach");535 assert_mprog_count(target, 2);536 537cleanup_target2:538 LIBBPF_OPTS_RESET(optd,539 .expected_revision = 3,540 );541 542 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);543 ASSERT_OK(err, "prog_detach");544 assert_mprog_count(target, 1);545 546cleanup_target:547 LIBBPF_OPTS_RESET(optd);548 549 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);550 ASSERT_OK(err, "prog_detach");551 assert_mprog_count(target, 0);552 553cleanup:554 test_tc_link__destroy(skel);555}556 557void serial_test_tc_opts_revision(void)558{559 test_tc_opts_revision_target(BPF_TCX_INGRESS);560 test_tc_opts_revision_target(BPF_TCX_EGRESS);561}562 563static void test_tc_chain_classic(int target, bool chain_tc_old)564{565 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);566 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);567 LIBBPF_OPTS(bpf_prog_attach_opts, opta);568 LIBBPF_OPTS(bpf_prog_detach_opts, optd);569 bool hook_created = false, tc_attached = false;570 __u32 fd1, fd2, fd3, id1, id2, id3;571 struct test_tc_link *skel;572 int err;573 574 skel = test_tc_link__open_and_load();575 if (!ASSERT_OK_PTR(skel, "skel_load"))576 goto cleanup;577 578 fd1 = bpf_program__fd(skel->progs.tc1);579 fd2 = bpf_program__fd(skel->progs.tc2);580 fd3 = bpf_program__fd(skel->progs.tc3);581 582 id1 = id_from_prog_fd(fd1);583 id2 = id_from_prog_fd(fd2);584 id3 = id_from_prog_fd(fd3);585 586 ASSERT_NEQ(id1, id2, "prog_ids_1_2");587 ASSERT_NEQ(id2, id3, "prog_ids_2_3");588 589 assert_mprog_count(target, 0);590 591 if (chain_tc_old) {592 tc_hook.attach_point = target == BPF_TCX_INGRESS ?593 BPF_TC_INGRESS : BPF_TC_EGRESS;594 err = bpf_tc_hook_create(&tc_hook);595 if (err == 0)596 hook_created = true;597 err = err == -EEXIST ? 0 : err;598 if (!ASSERT_OK(err, "bpf_tc_hook_create"))599 goto cleanup;600 601 tc_opts.prog_fd = fd3;602 err = bpf_tc_attach(&tc_hook, &tc_opts);603 if (!ASSERT_OK(err, "bpf_tc_attach"))604 goto cleanup;605 tc_attached = true;606 }607 608 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);609 if (!ASSERT_EQ(err, 0, "prog_attach"))610 goto cleanup;611 612 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);613 if (!ASSERT_EQ(err, 0, "prog_attach"))614 goto cleanup_detach;615 616 assert_mprog_count(target, 2);617 618 tc_skel_reset_all_seen(skel);619 ASSERT_OK(system(ping_cmd), ping_cmd);620 621 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");622 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");623 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");624 625 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);626 if (!ASSERT_OK(err, "prog_detach"))627 goto cleanup_detach;628 629 assert_mprog_count(target, 1);630 631 tc_skel_reset_all_seen(skel);632 ASSERT_OK(system(ping_cmd), ping_cmd);633 634 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");635 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");636 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");637 638cleanup_detach:639 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);640 if (!ASSERT_OK(err, "prog_detach"))641 goto cleanup;642 643 assert_mprog_count(target, 0);644cleanup:645 if (tc_attached) {646 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;647 err = bpf_tc_detach(&tc_hook, &tc_opts);648 ASSERT_OK(err, "bpf_tc_detach");649 }650 if (hook_created) {651 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;652 bpf_tc_hook_destroy(&tc_hook);653 }654 test_tc_link__destroy(skel);655 assert_mprog_count(target, 0);656}657 658void serial_test_tc_opts_chain_classic(void)659{660 test_tc_chain_classic(BPF_TCX_INGRESS, false);661 test_tc_chain_classic(BPF_TCX_EGRESS, false);662 test_tc_chain_classic(BPF_TCX_INGRESS, true);663 test_tc_chain_classic(BPF_TCX_EGRESS, true);664}665 666static void test_tc_opts_replace_target(int target)667{668 LIBBPF_OPTS(bpf_prog_attach_opts, opta);669 LIBBPF_OPTS(bpf_prog_detach_opts, optd);670 LIBBPF_OPTS(bpf_prog_query_opts, optq);671 __u32 fd1, fd2, fd3, id1, id2, id3, detach_fd;672 __u32 prog_ids[4], prog_flags[4];673 struct test_tc_link *skel;674 int err;675 676 skel = test_tc_link__open_and_load();677 if (!ASSERT_OK_PTR(skel, "skel_load"))678 goto cleanup;679 680 fd1 = bpf_program__fd(skel->progs.tc1);681 fd2 = bpf_program__fd(skel->progs.tc2);682 fd3 = bpf_program__fd(skel->progs.tc3);683 684 id1 = id_from_prog_fd(fd1);685 id2 = id_from_prog_fd(fd2);686 id3 = id_from_prog_fd(fd3);687 688 ASSERT_NEQ(id1, id2, "prog_ids_1_2");689 ASSERT_NEQ(id2, id3, "prog_ids_2_3");690 691 assert_mprog_count(target, 0);692 693 LIBBPF_OPTS_RESET(opta,694 .expected_revision = 1,695 );696 697 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);698 if (!ASSERT_EQ(err, 0, "prog_attach"))699 goto cleanup;700 701 assert_mprog_count(target, 1);702 703 LIBBPF_OPTS_RESET(opta,704 .flags = BPF_F_BEFORE,705 .relative_id = id1,706 .expected_revision = 2,707 );708 709 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);710 if (!ASSERT_EQ(err, 0, "prog_attach"))711 goto cleanup_target;712 713 detach_fd = fd2;714 715 assert_mprog_count(target, 2);716 717 optq.prog_attach_flags = prog_flags;718 optq.prog_ids = prog_ids;719 720 memset(prog_flags, 0, sizeof(prog_flags));721 memset(prog_ids, 0, sizeof(prog_ids));722 optq.count = ARRAY_SIZE(prog_ids);723 724 err = bpf_prog_query_opts(loopback, target, &optq);725 if (!ASSERT_OK(err, "prog_query"))726 goto cleanup_target2;727 728 ASSERT_EQ(optq.count, 2, "count");729 ASSERT_EQ(optq.revision, 3, "revision");730 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");731 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");732 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");733 734 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");735 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");736 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");737 738 tc_skel_reset_all_seen(skel);739 ASSERT_OK(system(ping_cmd), ping_cmd);740 741 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");742 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");743 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");744 745 LIBBPF_OPTS_RESET(opta,746 .flags = BPF_F_REPLACE,747 .replace_prog_fd = fd2,748 .expected_revision = 3,749 );750 751 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);752 if (!ASSERT_EQ(err, 0, "prog_attach"))753 goto cleanup_target2;754 755 detach_fd = fd3;756 757 assert_mprog_count(target, 2);758 759 memset(prog_ids, 0, sizeof(prog_ids));760 optq.count = ARRAY_SIZE(prog_ids);761 762 err = bpf_prog_query_opts(loopback, target, &optq);763 if (!ASSERT_OK(err, "prog_query"))764 goto cleanup_target2;765 766 ASSERT_EQ(optq.count, 2, "count");767 ASSERT_EQ(optq.revision, 4, "revision");768 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");769 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");770 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");771 772 tc_skel_reset_all_seen(skel);773 ASSERT_OK(system(ping_cmd), ping_cmd);774 775 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");776 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");777 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");778 779 LIBBPF_OPTS_RESET(opta,780 .flags = BPF_F_REPLACE | BPF_F_BEFORE,781 .replace_prog_fd = fd3,782 .relative_fd = fd1,783 .expected_revision = 4,784 );785 786 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);787 if (!ASSERT_EQ(err, 0, "prog_attach"))788 goto cleanup_target2;789 790 detach_fd = fd2;791 792 assert_mprog_count(target, 2);793 794 memset(prog_ids, 0, sizeof(prog_ids));795 optq.count = ARRAY_SIZE(prog_ids);796 797 err = bpf_prog_query_opts(loopback, target, &optq);798 if (!ASSERT_OK(err, "prog_query"))799 goto cleanup_target2;800 801 ASSERT_EQ(optq.count, 2, "count");802 ASSERT_EQ(optq.revision, 5, "revision");803 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");804 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");805 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");806 807 tc_skel_reset_all_seen(skel);808 ASSERT_OK(system(ping_cmd), ping_cmd);809 810 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");811 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");812 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");813 814 LIBBPF_OPTS_RESET(opta,815 .flags = BPF_F_REPLACE,816 .replace_prog_fd = fd2,817 );818 819 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);820 ASSERT_EQ(err, -EEXIST, "prog_attach");821 assert_mprog_count(target, 2);822 823 LIBBPF_OPTS_RESET(opta,824 .flags = BPF_F_REPLACE | BPF_F_AFTER,825 .replace_prog_fd = fd2,826 .relative_fd = fd1,827 .expected_revision = 5,828 );829 830 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);831 ASSERT_EQ(err, -ERANGE, "prog_attach");832 assert_mprog_count(target, 2);833 834 LIBBPF_OPTS_RESET(opta,835 .flags = BPF_F_BEFORE | BPF_F_AFTER | BPF_F_REPLACE,836 .replace_prog_fd = fd2,837 .relative_fd = fd1,838 .expected_revision = 5,839 );840 841 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);842 ASSERT_EQ(err, -ERANGE, "prog_attach");843 assert_mprog_count(target, 2);844 845 LIBBPF_OPTS_RESET(optd,846 .flags = BPF_F_BEFORE,847 .relative_id = id1,848 .expected_revision = 5,849 );850 851cleanup_target2:852 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);853 ASSERT_OK(err, "prog_detach");854 assert_mprog_count(target, 1);855 856cleanup_target:857 LIBBPF_OPTS_RESET(optd);858 859 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);860 ASSERT_OK(err, "prog_detach");861 assert_mprog_count(target, 0);862 863cleanup:864 test_tc_link__destroy(skel);865}866 867void serial_test_tc_opts_replace(void)868{869 test_tc_opts_replace_target(BPF_TCX_INGRESS);870 test_tc_opts_replace_target(BPF_TCX_EGRESS);871}872 873static void test_tc_opts_invalid_target(int target)874{875 LIBBPF_OPTS(bpf_prog_attach_opts, opta);876 LIBBPF_OPTS(bpf_prog_detach_opts, optd);877 __u32 fd1, fd2, id1, id2;878 struct test_tc_link *skel;879 int err;880 881 skel = test_tc_link__open_and_load();882 if (!ASSERT_OK_PTR(skel, "skel_load"))883 goto cleanup;884 885 fd1 = bpf_program__fd(skel->progs.tc1);886 fd2 = bpf_program__fd(skel->progs.tc2);887 888 id1 = id_from_prog_fd(fd1);889 id2 = id_from_prog_fd(fd2);890 891 ASSERT_NEQ(id1, id2, "prog_ids_1_2");892 893 assert_mprog_count(target, 0);894 895 LIBBPF_OPTS_RESET(opta,896 .flags = BPF_F_BEFORE | BPF_F_AFTER,897 );898 899 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);900 ASSERT_EQ(err, -ERANGE, "prog_attach");901 assert_mprog_count(target, 0);902 903 LIBBPF_OPTS_RESET(opta,904 .flags = BPF_F_BEFORE | BPF_F_ID,905 );906 907 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);908 ASSERT_EQ(err, -ENOENT, "prog_attach");909 assert_mprog_count(target, 0);910 911 LIBBPF_OPTS_RESET(opta,912 .flags = BPF_F_AFTER | BPF_F_ID,913 );914 915 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);916 ASSERT_EQ(err, -ENOENT, "prog_attach");917 assert_mprog_count(target, 0);918 919 LIBBPF_OPTS_RESET(opta,920 .relative_fd = fd2,921 );922 923 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);924 ASSERT_EQ(err, -EINVAL, "prog_attach");925 assert_mprog_count(target, 0);926 927 LIBBPF_OPTS_RESET(opta,928 .flags = BPF_F_BEFORE | BPF_F_AFTER,929 .relative_fd = fd2,930 );931 932 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);933 ASSERT_EQ(err, -ENOENT, "prog_attach");934 assert_mprog_count(target, 0);935 936 LIBBPF_OPTS_RESET(opta,937 .flags = BPF_F_ID,938 .relative_id = id2,939 );940 941 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);942 ASSERT_EQ(err, -EINVAL, "prog_attach");943 assert_mprog_count(target, 0);944 945 LIBBPF_OPTS_RESET(opta,946 .flags = BPF_F_BEFORE,947 .relative_fd = fd1,948 );949 950 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);951 ASSERT_EQ(err, -ENOENT, "prog_attach");952 assert_mprog_count(target, 0);953 954 LIBBPF_OPTS_RESET(opta,955 .flags = BPF_F_AFTER,956 .relative_fd = fd1,957 );958 959 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);960 ASSERT_EQ(err, -ENOENT, "prog_attach");961 assert_mprog_count(target, 0);962 963 LIBBPF_OPTS_RESET(opta);964 965 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);966 if (!ASSERT_EQ(err, 0, "prog_attach"))967 goto cleanup;968 969 assert_mprog_count(target, 1);970 971 LIBBPF_OPTS_RESET(opta);972 973 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);974 ASSERT_EQ(err, -EEXIST, "prog_attach");975 assert_mprog_count(target, 1);976 977 LIBBPF_OPTS_RESET(opta,978 .flags = BPF_F_BEFORE,979 .relative_fd = fd1,980 );981 982 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);983 ASSERT_EQ(err, -EEXIST, "prog_attach");984 assert_mprog_count(target, 1);985 986 LIBBPF_OPTS_RESET(opta,987 .flags = BPF_F_AFTER,988 .relative_fd = fd1,989 );990 991 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);992 ASSERT_EQ(err, -EEXIST, "prog_attach");993 assert_mprog_count(target, 1);994 995 LIBBPF_OPTS_RESET(opta,996 .flags = BPF_F_REPLACE,997 .relative_fd = fd1,998 );999 1000 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1001 ASSERT_EQ(err, -EINVAL, "prog_attach_x1");1002 assert_mprog_count(target, 1);1003 1004 LIBBPF_OPTS_RESET(opta,1005 .flags = BPF_F_REPLACE,1006 .replace_prog_fd = fd1,1007 );1008 1009 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1010 ASSERT_EQ(err, -EEXIST, "prog_attach");1011 assert_mprog_count(target, 1);1012 1013 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1014 ASSERT_OK(err, "prog_detach");1015 assert_mprog_count(target, 0);1016cleanup:1017 test_tc_link__destroy(skel);1018}1019 1020void serial_test_tc_opts_invalid(void)1021{1022 test_tc_opts_invalid_target(BPF_TCX_INGRESS);1023 test_tc_opts_invalid_target(BPF_TCX_EGRESS);1024}1025 1026static void test_tc_opts_prepend_target(int target)1027{1028 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1029 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1030 LIBBPF_OPTS(bpf_prog_query_opts, optq);1031 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1032 struct test_tc_link *skel;1033 __u32 prog_ids[5];1034 int err;1035 1036 skel = test_tc_link__open_and_load();1037 if (!ASSERT_OK_PTR(skel, "skel_load"))1038 goto cleanup;1039 1040 fd1 = bpf_program__fd(skel->progs.tc1);1041 fd2 = bpf_program__fd(skel->progs.tc2);1042 fd3 = bpf_program__fd(skel->progs.tc3);1043 fd4 = bpf_program__fd(skel->progs.tc4);1044 1045 id1 = id_from_prog_fd(fd1);1046 id2 = id_from_prog_fd(fd2);1047 id3 = id_from_prog_fd(fd3);1048 id4 = id_from_prog_fd(fd4);1049 1050 ASSERT_NEQ(id1, id2, "prog_ids_1_2");1051 ASSERT_NEQ(id3, id4, "prog_ids_3_4");1052 ASSERT_NEQ(id2, id3, "prog_ids_2_3");1053 1054 assert_mprog_count(target, 0);1055 1056 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1057 if (!ASSERT_EQ(err, 0, "prog_attach"))1058 goto cleanup;1059 1060 assert_mprog_count(target, 1);1061 1062 LIBBPF_OPTS_RESET(opta,1063 .flags = BPF_F_BEFORE,1064 );1065 1066 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1067 if (!ASSERT_EQ(err, 0, "prog_attach"))1068 goto cleanup_target;1069 1070 assert_mprog_count(target, 2);1071 1072 optq.prog_ids = prog_ids;1073 1074 memset(prog_ids, 0, sizeof(prog_ids));1075 optq.count = ARRAY_SIZE(prog_ids);1076 1077 err = bpf_prog_query_opts(loopback, target, &optq);1078 if (!ASSERT_OK(err, "prog_query"))1079 goto cleanup_target2;1080 1081 ASSERT_EQ(optq.count, 2, "count");1082 ASSERT_EQ(optq.revision, 3, "revision");1083 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1084 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");1085 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1086 1087 tc_skel_reset_all_seen(skel);1088 ASSERT_OK(system(ping_cmd), ping_cmd);1089 1090 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1091 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1092 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1093 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1094 1095 LIBBPF_OPTS_RESET(opta,1096 .flags = BPF_F_BEFORE,1097 );1098 1099 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1100 if (!ASSERT_EQ(err, 0, "prog_attach"))1101 goto cleanup_target2;1102 1103 LIBBPF_OPTS_RESET(opta,1104 .flags = BPF_F_BEFORE,1105 );1106 1107 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1108 if (!ASSERT_EQ(err, 0, "prog_attach"))1109 goto cleanup_target3;1110 1111 assert_mprog_count(target, 4);1112 1113 memset(prog_ids, 0, sizeof(prog_ids));1114 optq.count = ARRAY_SIZE(prog_ids);1115 1116 err = bpf_prog_query_opts(loopback, target, &optq);1117 if (!ASSERT_OK(err, "prog_query"))1118 goto cleanup_target4;1119 1120 ASSERT_EQ(optq.count, 4, "count");1121 ASSERT_EQ(optq.revision, 5, "revision");1122 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");1123 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1124 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");1125 ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");1126 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1127 1128 tc_skel_reset_all_seen(skel);1129 ASSERT_OK(system(ping_cmd), ping_cmd);1130 1131 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1132 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1133 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1134 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1135 1136cleanup_target4:1137 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1138 ASSERT_OK(err, "prog_detach");1139 assert_mprog_count(target, 3);1140 1141cleanup_target3:1142 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1143 ASSERT_OK(err, "prog_detach");1144 assert_mprog_count(target, 2);1145 1146cleanup_target2:1147 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1148 ASSERT_OK(err, "prog_detach");1149 assert_mprog_count(target, 1);1150 1151cleanup_target:1152 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1153 ASSERT_OK(err, "prog_detach");1154 assert_mprog_count(target, 0);1155 1156cleanup:1157 test_tc_link__destroy(skel);1158}1159 1160void serial_test_tc_opts_prepend(void)1161{1162 test_tc_opts_prepend_target(BPF_TCX_INGRESS);1163 test_tc_opts_prepend_target(BPF_TCX_EGRESS);1164}1165 1166static void test_tc_opts_append_target(int target)1167{1168 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1169 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1170 LIBBPF_OPTS(bpf_prog_query_opts, optq);1171 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1172 struct test_tc_link *skel;1173 __u32 prog_ids[5];1174 int err;1175 1176 skel = test_tc_link__open_and_load();1177 if (!ASSERT_OK_PTR(skel, "skel_load"))1178 goto cleanup;1179 1180 fd1 = bpf_program__fd(skel->progs.tc1);1181 fd2 = bpf_program__fd(skel->progs.tc2);1182 fd3 = bpf_program__fd(skel->progs.tc3);1183 fd4 = bpf_program__fd(skel->progs.tc4);1184 1185 id1 = id_from_prog_fd(fd1);1186 id2 = id_from_prog_fd(fd2);1187 id3 = id_from_prog_fd(fd3);1188 id4 = id_from_prog_fd(fd4);1189 1190 ASSERT_NEQ(id1, id2, "prog_ids_1_2");1191 ASSERT_NEQ(id3, id4, "prog_ids_3_4");1192 ASSERT_NEQ(id2, id3, "prog_ids_2_3");1193 1194 assert_mprog_count(target, 0);1195 1196 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1197 if (!ASSERT_EQ(err, 0, "prog_attach"))1198 goto cleanup;1199 1200 assert_mprog_count(target, 1);1201 1202 LIBBPF_OPTS_RESET(opta,1203 .flags = BPF_F_AFTER,1204 );1205 1206 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1207 if (!ASSERT_EQ(err, 0, "prog_attach"))1208 goto cleanup_target;1209 1210 assert_mprog_count(target, 2);1211 1212 optq.prog_ids = prog_ids;1213 1214 memset(prog_ids, 0, sizeof(prog_ids));1215 optq.count = ARRAY_SIZE(prog_ids);1216 1217 err = bpf_prog_query_opts(loopback, target, &optq);1218 if (!ASSERT_OK(err, "prog_query"))1219 goto cleanup_target2;1220 1221 ASSERT_EQ(optq.count, 2, "count");1222 ASSERT_EQ(optq.revision, 3, "revision");1223 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1224 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1225 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1226 1227 tc_skel_reset_all_seen(skel);1228 ASSERT_OK(system(ping_cmd), ping_cmd);1229 1230 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1231 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1232 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1233 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1234 1235 LIBBPF_OPTS_RESET(opta,1236 .flags = BPF_F_AFTER,1237 );1238 1239 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1240 if (!ASSERT_EQ(err, 0, "prog_attach"))1241 goto cleanup_target2;1242 1243 LIBBPF_OPTS_RESET(opta,1244 .flags = BPF_F_AFTER,1245 );1246 1247 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1248 if (!ASSERT_EQ(err, 0, "prog_attach"))1249 goto cleanup_target3;1250 1251 assert_mprog_count(target, 4);1252 1253 memset(prog_ids, 0, sizeof(prog_ids));1254 optq.count = ARRAY_SIZE(prog_ids);1255 1256 err = bpf_prog_query_opts(loopback, target, &optq);1257 if (!ASSERT_OK(err, "prog_query"))1258 goto cleanup_target4;1259 1260 ASSERT_EQ(optq.count, 4, "count");1261 ASSERT_EQ(optq.revision, 5, "revision");1262 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1263 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1264 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1265 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1266 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1267 1268 tc_skel_reset_all_seen(skel);1269 ASSERT_OK(system(ping_cmd), ping_cmd);1270 1271 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1272 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1273 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1274 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1275 1276cleanup_target4:1277 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1278 ASSERT_OK(err, "prog_detach");1279 assert_mprog_count(target, 3);1280 1281cleanup_target3:1282 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1283 ASSERT_OK(err, "prog_detach");1284 assert_mprog_count(target, 2);1285 1286cleanup_target2:1287 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1288 ASSERT_OK(err, "prog_detach");1289 assert_mprog_count(target, 1);1290 1291cleanup_target:1292 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1293 ASSERT_OK(err, "prog_detach");1294 assert_mprog_count(target, 0);1295 1296cleanup:1297 test_tc_link__destroy(skel);1298}1299 1300void serial_test_tc_opts_append(void)1301{1302 test_tc_opts_append_target(BPF_TCX_INGRESS);1303 test_tc_opts_append_target(BPF_TCX_EGRESS);1304}1305 1306static void test_tc_opts_dev_cleanup_target(int target)1307{1308 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1309 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1310 LIBBPF_OPTS(bpf_prog_query_opts, optq);1311 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1312 struct test_tc_link *skel;1313 int err, ifindex;1314 1315 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1316 ifindex = if_nametoindex("tcx_opts1");1317 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1318 1319 skel = test_tc_link__open_and_load();1320 if (!ASSERT_OK_PTR(skel, "skel_load"))1321 goto cleanup;1322 1323 fd1 = bpf_program__fd(skel->progs.tc1);1324 fd2 = bpf_program__fd(skel->progs.tc2);1325 fd3 = bpf_program__fd(skel->progs.tc3);1326 fd4 = bpf_program__fd(skel->progs.tc4);1327 1328 id1 = id_from_prog_fd(fd1);1329 id2 = id_from_prog_fd(fd2);1330 id3 = id_from_prog_fd(fd3);1331 id4 = id_from_prog_fd(fd4);1332 1333 ASSERT_NEQ(id1, id2, "prog_ids_1_2");1334 ASSERT_NEQ(id3, id4, "prog_ids_3_4");1335 ASSERT_NEQ(id2, id3, "prog_ids_2_3");1336 1337 assert_mprog_count_ifindex(ifindex, target, 0);1338 1339 err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);1340 if (!ASSERT_EQ(err, 0, "prog_attach"))1341 goto cleanup;1342 1343 assert_mprog_count_ifindex(ifindex, target, 1);1344 1345 err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);1346 if (!ASSERT_EQ(err, 0, "prog_attach"))1347 goto cleanup1;1348 1349 assert_mprog_count_ifindex(ifindex, target, 2);1350 1351 err = bpf_prog_attach_opts(fd3, ifindex, target, &opta);1352 if (!ASSERT_EQ(err, 0, "prog_attach"))1353 goto cleanup2;1354 1355 assert_mprog_count_ifindex(ifindex, target, 3);1356 1357 err = bpf_prog_attach_opts(fd4, ifindex, target, &opta);1358 if (!ASSERT_EQ(err, 0, "prog_attach"))1359 goto cleanup3;1360 1361 assert_mprog_count_ifindex(ifindex, target, 4);1362 1363 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1364 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1365 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1366 return;1367cleanup3:1368 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1369 ASSERT_OK(err, "prog_detach");1370 1371 assert_mprog_count_ifindex(ifindex, target, 2);1372cleanup2:1373 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1374 ASSERT_OK(err, "prog_detach");1375 1376 assert_mprog_count_ifindex(ifindex, target, 1);1377cleanup1:1378 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1379 ASSERT_OK(err, "prog_detach");1380 1381 assert_mprog_count_ifindex(ifindex, target, 0);1382cleanup:1383 test_tc_link__destroy(skel);1384 1385 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1386 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1387 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1388}1389 1390void serial_test_tc_opts_dev_cleanup(void)1391{1392 test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS);1393 test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS);1394}1395 1396static void test_tc_opts_mixed_target(int target)1397{1398 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1399 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1400 LIBBPF_OPTS(bpf_prog_query_opts, optq);1401 LIBBPF_OPTS(bpf_tcx_opts, optl);1402 __u32 pid1, pid2, pid3, pid4, lid2, lid4;1403 __u32 prog_flags[4], link_flags[4];1404 __u32 prog_ids[4], link_ids[4];1405 struct test_tc_link *skel;1406 struct bpf_link *link;1407 int err, detach_fd;1408 1409 skel = test_tc_link__open();1410 if (!ASSERT_OK_PTR(skel, "skel_open"))1411 goto cleanup;1412 1413 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1414 0, "tc1_attach_type");1415 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1416 0, "tc2_attach_type");1417 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1418 0, "tc3_attach_type");1419 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1420 0, "tc4_attach_type");1421 1422 err = test_tc_link__load(skel);1423 if (!ASSERT_OK(err, "skel_load"))1424 goto cleanup;1425 1426 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1427 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1428 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1429 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1430 1431 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1432 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1433 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1434 1435 assert_mprog_count(target, 0);1436 1437 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1438 loopback, target, &opta);1439 if (!ASSERT_EQ(err, 0, "prog_attach"))1440 goto cleanup;1441 1442 detach_fd = bpf_program__fd(skel->progs.tc1);1443 1444 assert_mprog_count(target, 1);1445 1446 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1447 if (!ASSERT_OK_PTR(link, "link_attach"))1448 goto cleanup1;1449 skel->links.tc2 = link;1450 1451 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1452 1453 assert_mprog_count(target, 2);1454 1455 LIBBPF_OPTS_RESET(opta,1456 .flags = BPF_F_REPLACE,1457 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),1458 );1459 1460 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),1461 loopback, target, &opta);1462 ASSERT_EQ(err, -EEXIST, "prog_attach");1463 1464 assert_mprog_count(target, 2);1465 1466 LIBBPF_OPTS_RESET(opta,1467 .flags = BPF_F_REPLACE,1468 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),1469 );1470 1471 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1472 loopback, target, &opta);1473 ASSERT_EQ(err, -EEXIST, "prog_attach");1474 1475 assert_mprog_count(target, 2);1476 1477 LIBBPF_OPTS_RESET(opta,1478 .flags = BPF_F_REPLACE,1479 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),1480 );1481 1482 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),1483 loopback, target, &opta);1484 ASSERT_EQ(err, -EBUSY, "prog_attach");1485 1486 assert_mprog_count(target, 2);1487 1488 LIBBPF_OPTS_RESET(opta,1489 .flags = BPF_F_REPLACE,1490 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),1491 );1492 1493 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),1494 loopback, target, &opta);1495 if (!ASSERT_EQ(err, 0, "prog_attach"))1496 goto cleanup1;1497 1498 detach_fd = bpf_program__fd(skel->progs.tc3);1499 1500 assert_mprog_count(target, 2);1501 1502 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1503 if (!ASSERT_OK_PTR(link, "link_attach"))1504 goto cleanup1;1505 skel->links.tc4 = link;1506 1507 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1508 1509 assert_mprog_count(target, 3);1510 1511 LIBBPF_OPTS_RESET(opta,1512 .flags = BPF_F_REPLACE,1513 .replace_prog_fd = bpf_program__fd(skel->progs.tc4),1514 );1515 1516 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),1517 loopback, target, &opta);1518 ASSERT_EQ(err, -EEXIST, "prog_attach");1519 1520 optq.prog_ids = prog_ids;1521 optq.prog_attach_flags = prog_flags;1522 optq.link_ids = link_ids;1523 optq.link_attach_flags = link_flags;1524 1525 memset(prog_ids, 0, sizeof(prog_ids));1526 memset(prog_flags, 0, sizeof(prog_flags));1527 memset(link_ids, 0, sizeof(link_ids));1528 memset(link_flags, 0, sizeof(link_flags));1529 optq.count = ARRAY_SIZE(prog_ids);1530 1531 err = bpf_prog_query_opts(loopback, target, &optq);1532 if (!ASSERT_OK(err, "prog_query"))1533 goto cleanup1;1534 1535 ASSERT_EQ(optq.count, 3, "count");1536 ASSERT_EQ(optq.revision, 5, "revision");1537 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");1538 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");1539 ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]");1540 ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]");1541 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1542 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");1543 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1544 ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]");1545 ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]");1546 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");1547 ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]");1548 ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]");1549 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1550 ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]");1551 ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]");1552 ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]");1553 1554 ASSERT_OK(system(ping_cmd), ping_cmd);1555 1556cleanup1:1557 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);1558 ASSERT_OK(err, "prog_detach");1559 assert_mprog_count(target, 2);1560 1561cleanup:1562 test_tc_link__destroy(skel);1563 assert_mprog_count(target, 0);1564}1565 1566void serial_test_tc_opts_mixed(void)1567{1568 test_tc_opts_mixed_target(BPF_TCX_INGRESS);1569 test_tc_opts_mixed_target(BPF_TCX_EGRESS);1570}1571 1572static void test_tc_opts_demixed_target(int target)1573{1574 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1575 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1576 LIBBPF_OPTS(bpf_tcx_opts, optl);1577 struct test_tc_link *skel;1578 struct bpf_link *link;1579 __u32 pid1, pid2;1580 int err;1581 1582 skel = test_tc_link__open();1583 if (!ASSERT_OK_PTR(skel, "skel_open"))1584 goto cleanup;1585 1586 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1587 0, "tc1_attach_type");1588 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1589 0, "tc2_attach_type");1590 1591 err = test_tc_link__load(skel);1592 if (!ASSERT_OK(err, "skel_load"))1593 goto cleanup;1594 1595 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1596 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1597 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1598 1599 assert_mprog_count(target, 0);1600 1601 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1602 loopback, target, &opta);1603 if (!ASSERT_EQ(err, 0, "prog_attach"))1604 goto cleanup;1605 1606 assert_mprog_count(target, 1);1607 1608 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1609 if (!ASSERT_OK_PTR(link, "link_attach"))1610 goto cleanup1;1611 skel->links.tc2 = link;1612 1613 assert_mprog_count(target, 2);1614 1615 LIBBPF_OPTS_RESET(optd,1616 .flags = BPF_F_AFTER,1617 );1618 1619 err = bpf_prog_detach_opts(0, loopback, target, &optd);1620 ASSERT_EQ(err, -EBUSY, "prog_detach");1621 1622 assert_mprog_count(target, 2);1623 1624 LIBBPF_OPTS_RESET(optd,1625 .flags = BPF_F_BEFORE,1626 );1627 1628 err = bpf_prog_detach_opts(0, loopback, target, &optd);1629 ASSERT_OK(err, "prog_detach");1630 1631 assert_mprog_count(target, 1);1632 goto cleanup;1633 1634cleanup1:1635 err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1),1636 loopback, target, &optd);1637 ASSERT_OK(err, "prog_detach");1638 assert_mprog_count(target, 2);1639 1640cleanup:1641 test_tc_link__destroy(skel);1642 assert_mprog_count(target, 0);1643}1644 1645void serial_test_tc_opts_demixed(void)1646{1647 test_tc_opts_demixed_target(BPF_TCX_INGRESS);1648 test_tc_opts_demixed_target(BPF_TCX_EGRESS);1649}1650 1651static void test_tc_opts_detach_target(int target)1652{1653 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1654 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1655 LIBBPF_OPTS(bpf_prog_query_opts, optq);1656 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1657 struct test_tc_link *skel;1658 __u32 prog_ids[5];1659 int err;1660 1661 skel = test_tc_link__open_and_load();1662 if (!ASSERT_OK_PTR(skel, "skel_load"))1663 goto cleanup;1664 1665 fd1 = bpf_program__fd(skel->progs.tc1);1666 fd2 = bpf_program__fd(skel->progs.tc2);1667 fd3 = bpf_program__fd(skel->progs.tc3);1668 fd4 = bpf_program__fd(skel->progs.tc4);1669 1670 id1 = id_from_prog_fd(fd1);1671 id2 = id_from_prog_fd(fd2);1672 id3 = id_from_prog_fd(fd3);1673 id4 = id_from_prog_fd(fd4);1674 1675 ASSERT_NEQ(id1, id2, "prog_ids_1_2");1676 ASSERT_NEQ(id3, id4, "prog_ids_3_4");1677 ASSERT_NEQ(id2, id3, "prog_ids_2_3");1678 1679 assert_mprog_count(target, 0);1680 1681 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1682 if (!ASSERT_EQ(err, 0, "prog_attach"))1683 goto cleanup;1684 1685 assert_mprog_count(target, 1);1686 1687 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1688 if (!ASSERT_EQ(err, 0, "prog_attach"))1689 goto cleanup1;1690 1691 assert_mprog_count(target, 2);1692 1693 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1694 if (!ASSERT_EQ(err, 0, "prog_attach"))1695 goto cleanup2;1696 1697 assert_mprog_count(target, 3);1698 1699 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1700 if (!ASSERT_EQ(err, 0, "prog_attach"))1701 goto cleanup3;1702 1703 assert_mprog_count(target, 4);1704 1705 optq.prog_ids = prog_ids;1706 1707 memset(prog_ids, 0, sizeof(prog_ids));1708 optq.count = ARRAY_SIZE(prog_ids);1709 1710 err = bpf_prog_query_opts(loopback, target, &optq);1711 if (!ASSERT_OK(err, "prog_query"))1712 goto cleanup4;1713 1714 ASSERT_EQ(optq.count, 4, "count");1715 ASSERT_EQ(optq.revision, 5, "revision");1716 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1717 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1718 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1719 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1720 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1721 1722 LIBBPF_OPTS_RESET(optd,1723 .flags = BPF_F_BEFORE,1724 );1725 1726 err = bpf_prog_detach_opts(0, loopback, target, &optd);1727 ASSERT_OK(err, "prog_detach");1728 1729 assert_mprog_count(target, 3);1730 1731 memset(prog_ids, 0, sizeof(prog_ids));1732 optq.count = ARRAY_SIZE(prog_ids);1733 1734 err = bpf_prog_query_opts(loopback, target, &optq);1735 if (!ASSERT_OK(err, "prog_query"))1736 goto cleanup4;1737 1738 ASSERT_EQ(optq.count, 3, "count");1739 ASSERT_EQ(optq.revision, 6, "revision");1740 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1741 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1742 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");1743 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1744 1745 LIBBPF_OPTS_RESET(optd,1746 .flags = BPF_F_AFTER,1747 );1748 1749 err = bpf_prog_detach_opts(0, loopback, target, &optd);1750 ASSERT_OK(err, "prog_detach");1751 1752 assert_mprog_count(target, 2);1753 1754 memset(prog_ids, 0, sizeof(prog_ids));1755 optq.count = ARRAY_SIZE(prog_ids);1756 1757 err = bpf_prog_query_opts(loopback, target, &optq);1758 if (!ASSERT_OK(err, "prog_query"))1759 goto cleanup4;1760 1761 ASSERT_EQ(optq.count, 2, "count");1762 ASSERT_EQ(optq.revision, 7, "revision");1763 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1764 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1765 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1766 1767 LIBBPF_OPTS_RESET(optd);1768 1769 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1770 ASSERT_OK(err, "prog_detach");1771 assert_mprog_count(target, 1);1772 1773 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1774 ASSERT_OK(err, "prog_detach");1775 assert_mprog_count(target, 0);1776 1777 LIBBPF_OPTS_RESET(optd,1778 .flags = BPF_F_BEFORE,1779 );1780 1781 err = bpf_prog_detach_opts(0, loopback, target, &optd);1782 ASSERT_EQ(err, -ENOENT, "prog_detach");1783 1784 LIBBPF_OPTS_RESET(optd,1785 .flags = BPF_F_AFTER,1786 );1787 1788 err = bpf_prog_detach_opts(0, loopback, target, &optd);1789 ASSERT_EQ(err, -ENOENT, "prog_detach");1790 goto cleanup;1791 1792cleanup4:1793 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1794 ASSERT_OK(err, "prog_detach");1795 assert_mprog_count(target, 3);1796 1797cleanup3:1798 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1799 ASSERT_OK(err, "prog_detach");1800 assert_mprog_count(target, 2);1801 1802cleanup2:1803 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1804 ASSERT_OK(err, "prog_detach");1805 assert_mprog_count(target, 1);1806 1807cleanup1:1808 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1809 ASSERT_OK(err, "prog_detach");1810 assert_mprog_count(target, 0);1811 1812cleanup:1813 test_tc_link__destroy(skel);1814}1815 1816void serial_test_tc_opts_detach(void)1817{1818 test_tc_opts_detach_target(BPF_TCX_INGRESS);1819 test_tc_opts_detach_target(BPF_TCX_EGRESS);1820}1821 1822static void test_tc_opts_detach_before_target(int target)1823{1824 LIBBPF_OPTS(bpf_prog_attach_opts, opta);1825 LIBBPF_OPTS(bpf_prog_detach_opts, optd);1826 LIBBPF_OPTS(bpf_prog_query_opts, optq);1827 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1828 struct test_tc_link *skel;1829 __u32 prog_ids[5];1830 int err;1831 1832 skel = test_tc_link__open_and_load();1833 if (!ASSERT_OK_PTR(skel, "skel_load"))1834 goto cleanup;1835 1836 fd1 = bpf_program__fd(skel->progs.tc1);1837 fd2 = bpf_program__fd(skel->progs.tc2);1838 fd3 = bpf_program__fd(skel->progs.tc3);1839 fd4 = bpf_program__fd(skel->progs.tc4);1840 1841 id1 = id_from_prog_fd(fd1);1842 id2 = id_from_prog_fd(fd2);1843 id3 = id_from_prog_fd(fd3);1844 id4 = id_from_prog_fd(fd4);1845 1846 ASSERT_NEQ(id1, id2, "prog_ids_1_2");1847 ASSERT_NEQ(id3, id4, "prog_ids_3_4");1848 ASSERT_NEQ(id2, id3, "prog_ids_2_3");1849 1850 assert_mprog_count(target, 0);1851 1852 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1853 if (!ASSERT_EQ(err, 0, "prog_attach"))1854 goto cleanup;1855 1856 assert_mprog_count(target, 1);1857 1858 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1859 if (!ASSERT_EQ(err, 0, "prog_attach"))1860 goto cleanup1;1861 1862 assert_mprog_count(target, 2);1863 1864 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1865 if (!ASSERT_EQ(err, 0, "prog_attach"))1866 goto cleanup2;1867 1868 assert_mprog_count(target, 3);1869 1870 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1871 if (!ASSERT_EQ(err, 0, "prog_attach"))1872 goto cleanup3;1873 1874 assert_mprog_count(target, 4);1875 1876 optq.prog_ids = prog_ids;1877 1878 memset(prog_ids, 0, sizeof(prog_ids));1879 optq.count = ARRAY_SIZE(prog_ids);1880 1881 err = bpf_prog_query_opts(loopback, target, &optq);1882 if (!ASSERT_OK(err, "prog_query"))1883 goto cleanup4;1884 1885 ASSERT_EQ(optq.count, 4, "count");1886 ASSERT_EQ(optq.revision, 5, "revision");1887 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1888 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1889 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1890 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1891 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1892 1893 LIBBPF_OPTS_RESET(optd,1894 .flags = BPF_F_BEFORE,1895 .relative_fd = fd2,1896 );1897 1898 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1899 ASSERT_OK(err, "prog_detach");1900 1901 assert_mprog_count(target, 3);1902 1903 memset(prog_ids, 0, sizeof(prog_ids));1904 optq.count = ARRAY_SIZE(prog_ids);1905 1906 err = bpf_prog_query_opts(loopback, target, &optq);1907 if (!ASSERT_OK(err, "prog_query"))1908 goto cleanup4;1909 1910 ASSERT_EQ(optq.count, 3, "count");1911 ASSERT_EQ(optq.revision, 6, "revision");1912 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1913 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1914 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");1915 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1916 1917 LIBBPF_OPTS_RESET(optd,1918 .flags = BPF_F_BEFORE,1919 .relative_fd = fd2,1920 );1921 1922 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1923 ASSERT_EQ(err, -ENOENT, "prog_detach");1924 assert_mprog_count(target, 3);1925 1926 LIBBPF_OPTS_RESET(optd,1927 .flags = BPF_F_BEFORE,1928 .relative_fd = fd4,1929 );1930 1931 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1932 ASSERT_EQ(err, -ERANGE, "prog_detach");1933 assert_mprog_count(target, 3);1934 1935 LIBBPF_OPTS_RESET(optd,1936 .flags = BPF_F_BEFORE,1937 .relative_fd = fd1,1938 );1939 1940 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1941 ASSERT_EQ(err, -ENOENT, "prog_detach");1942 assert_mprog_count(target, 3);1943 1944 LIBBPF_OPTS_RESET(optd,1945 .flags = BPF_F_BEFORE,1946 .relative_fd = fd3,1947 );1948 1949 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1950 ASSERT_OK(err, "prog_detach");1951 1952 assert_mprog_count(target, 2);1953 1954 memset(prog_ids, 0, sizeof(prog_ids));1955 optq.count = ARRAY_SIZE(prog_ids);1956 1957 err = bpf_prog_query_opts(loopback, target, &optq);1958 if (!ASSERT_OK(err, "prog_query"))1959 goto cleanup4;1960 1961 ASSERT_EQ(optq.count, 2, "count");1962 ASSERT_EQ(optq.revision, 7, "revision");1963 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");1964 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");1965 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1966 1967 LIBBPF_OPTS_RESET(optd,1968 .flags = BPF_F_BEFORE,1969 .relative_fd = fd4,1970 );1971 1972 err = bpf_prog_detach_opts(0, loopback, target, &optd);1973 ASSERT_OK(err, "prog_detach");1974 1975 assert_mprog_count(target, 1);1976 1977 memset(prog_ids, 0, sizeof(prog_ids));1978 optq.count = ARRAY_SIZE(prog_ids);1979 1980 err = bpf_prog_query_opts(loopback, target, &optq);1981 if (!ASSERT_OK(err, "prog_query"))1982 goto cleanup4;1983 1984 ASSERT_EQ(optq.count, 1, "count");1985 ASSERT_EQ(optq.revision, 8, "revision");1986 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");1987 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");1988 1989 LIBBPF_OPTS_RESET(optd,1990 .flags = BPF_F_BEFORE,1991 );1992 1993 err = bpf_prog_detach_opts(0, loopback, target, &optd);1994 ASSERT_OK(err, "prog_detach");1995 1996 assert_mprog_count(target, 0);1997 goto cleanup;1998 1999cleanup4:2000 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2001 ASSERT_OK(err, "prog_detach");2002 assert_mprog_count(target, 3);2003 2004cleanup3:2005 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2006 ASSERT_OK(err, "prog_detach");2007 assert_mprog_count(target, 2);2008 2009cleanup2:2010 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2011 ASSERT_OK(err, "prog_detach");2012 assert_mprog_count(target, 1);2013 2014cleanup1:2015 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2016 ASSERT_OK(err, "prog_detach");2017 assert_mprog_count(target, 0);2018 2019cleanup:2020 test_tc_link__destroy(skel);2021}2022 2023void serial_test_tc_opts_detach_before(void)2024{2025 test_tc_opts_detach_before_target(BPF_TCX_INGRESS);2026 test_tc_opts_detach_before_target(BPF_TCX_EGRESS);2027}2028 2029static void test_tc_opts_detach_after_target(int target)2030{2031 LIBBPF_OPTS(bpf_prog_attach_opts, opta);2032 LIBBPF_OPTS(bpf_prog_detach_opts, optd);2033 LIBBPF_OPTS(bpf_prog_query_opts, optq);2034 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;2035 struct test_tc_link *skel;2036 __u32 prog_ids[5];2037 int err;2038 2039 skel = test_tc_link__open_and_load();2040 if (!ASSERT_OK_PTR(skel, "skel_load"))2041 goto cleanup;2042 2043 fd1 = bpf_program__fd(skel->progs.tc1);2044 fd2 = bpf_program__fd(skel->progs.tc2);2045 fd3 = bpf_program__fd(skel->progs.tc3);2046 fd4 = bpf_program__fd(skel->progs.tc4);2047 2048 id1 = id_from_prog_fd(fd1);2049 id2 = id_from_prog_fd(fd2);2050 id3 = id_from_prog_fd(fd3);2051 id4 = id_from_prog_fd(fd4);2052 2053 ASSERT_NEQ(id1, id2, "prog_ids_1_2");2054 ASSERT_NEQ(id3, id4, "prog_ids_3_4");2055 ASSERT_NEQ(id2, id3, "prog_ids_2_3");2056 2057 assert_mprog_count(target, 0);2058 2059 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2060 if (!ASSERT_EQ(err, 0, "prog_attach"))2061 goto cleanup;2062 2063 assert_mprog_count(target, 1);2064 2065 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);2066 if (!ASSERT_EQ(err, 0, "prog_attach"))2067 goto cleanup1;2068 2069 assert_mprog_count(target, 2);2070 2071 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2072 if (!ASSERT_EQ(err, 0, "prog_attach"))2073 goto cleanup2;2074 2075 assert_mprog_count(target, 3);2076 2077 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);2078 if (!ASSERT_EQ(err, 0, "prog_attach"))2079 goto cleanup3;2080 2081 assert_mprog_count(target, 4);2082 2083 optq.prog_ids = prog_ids;2084 2085 memset(prog_ids, 0, sizeof(prog_ids));2086 optq.count = ARRAY_SIZE(prog_ids);2087 2088 err = bpf_prog_query_opts(loopback, target, &optq);2089 if (!ASSERT_OK(err, "prog_query"))2090 goto cleanup4;2091 2092 ASSERT_EQ(optq.count, 4, "count");2093 ASSERT_EQ(optq.revision, 5, "revision");2094 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2095 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");2096 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");2097 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");2098 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");2099 2100 LIBBPF_OPTS_RESET(optd,2101 .flags = BPF_F_AFTER,2102 .relative_fd = fd1,2103 );2104 2105 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2106 ASSERT_OK(err, "prog_detach");2107 2108 assert_mprog_count(target, 3);2109 2110 memset(prog_ids, 0, sizeof(prog_ids));2111 optq.count = ARRAY_SIZE(prog_ids);2112 2113 err = bpf_prog_query_opts(loopback, target, &optq);2114 if (!ASSERT_OK(err, "prog_query"))2115 goto cleanup4;2116 2117 ASSERT_EQ(optq.count, 3, "count");2118 ASSERT_EQ(optq.revision, 6, "revision");2119 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2120 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");2121 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");2122 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");2123 2124 LIBBPF_OPTS_RESET(optd,2125 .flags = BPF_F_AFTER,2126 .relative_fd = fd1,2127 );2128 2129 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2130 ASSERT_EQ(err, -ENOENT, "prog_detach");2131 assert_mprog_count(target, 3);2132 2133 LIBBPF_OPTS_RESET(optd,2134 .flags = BPF_F_AFTER,2135 .relative_fd = fd4,2136 );2137 2138 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2139 ASSERT_EQ(err, -ERANGE, "prog_detach");2140 assert_mprog_count(target, 3);2141 2142 LIBBPF_OPTS_RESET(optd,2143 .flags = BPF_F_AFTER,2144 .relative_fd = fd3,2145 );2146 2147 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2148 ASSERT_EQ(err, -ERANGE, "prog_detach");2149 assert_mprog_count(target, 3);2150 2151 LIBBPF_OPTS_RESET(optd,2152 .flags = BPF_F_AFTER,2153 .relative_fd = fd1,2154 );2155 2156 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2157 ASSERT_EQ(err, -ERANGE, "prog_detach");2158 assert_mprog_count(target, 3);2159 2160 LIBBPF_OPTS_RESET(optd,2161 .flags = BPF_F_AFTER,2162 .relative_fd = fd1,2163 );2164 2165 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2166 ASSERT_OK(err, "prog_detach");2167 2168 assert_mprog_count(target, 2);2169 2170 memset(prog_ids, 0, sizeof(prog_ids));2171 optq.count = ARRAY_SIZE(prog_ids);2172 2173 err = bpf_prog_query_opts(loopback, target, &optq);2174 if (!ASSERT_OK(err, "prog_query"))2175 goto cleanup4;2176 2177 ASSERT_EQ(optq.count, 2, "count");2178 ASSERT_EQ(optq.revision, 7, "revision");2179 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2180 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");2181 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");2182 2183 LIBBPF_OPTS_RESET(optd,2184 .flags = BPF_F_AFTER,2185 .relative_fd = fd1,2186 );2187 2188 err = bpf_prog_detach_opts(0, loopback, target, &optd);2189 ASSERT_OK(err, "prog_detach");2190 2191 assert_mprog_count(target, 1);2192 2193 memset(prog_ids, 0, sizeof(prog_ids));2194 optq.count = ARRAY_SIZE(prog_ids);2195 2196 err = bpf_prog_query_opts(loopback, target, &optq);2197 if (!ASSERT_OK(err, "prog_query"))2198 goto cleanup4;2199 2200 ASSERT_EQ(optq.count, 1, "count");2201 ASSERT_EQ(optq.revision, 8, "revision");2202 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2203 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");2204 2205 LIBBPF_OPTS_RESET(optd,2206 .flags = BPF_F_AFTER,2207 );2208 2209 err = bpf_prog_detach_opts(0, loopback, target, &optd);2210 ASSERT_OK(err, "prog_detach");2211 2212 assert_mprog_count(target, 0);2213 goto cleanup;2214 2215cleanup4:2216 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2217 ASSERT_OK(err, "prog_detach");2218 assert_mprog_count(target, 3);2219 2220cleanup3:2221 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2222 ASSERT_OK(err, "prog_detach");2223 assert_mprog_count(target, 2);2224 2225cleanup2:2226 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2227 ASSERT_OK(err, "prog_detach");2228 assert_mprog_count(target, 1);2229 2230cleanup1:2231 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2232 ASSERT_OK(err, "prog_detach");2233 assert_mprog_count(target, 0);2234 2235cleanup:2236 test_tc_link__destroy(skel);2237}2238 2239void serial_test_tc_opts_detach_after(void)2240{2241 test_tc_opts_detach_after_target(BPF_TCX_INGRESS);2242 test_tc_opts_detach_after_target(BPF_TCX_EGRESS);2243}2244 2245static void test_tc_opts_delete_empty(int target, bool chain_tc_old)2246{2247 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);2248 LIBBPF_OPTS(bpf_prog_detach_opts, optd);2249 int err;2250 2251 assert_mprog_count(target, 0);2252 if (chain_tc_old) {2253 tc_hook.attach_point = target == BPF_TCX_INGRESS ?2254 BPF_TC_INGRESS : BPF_TC_EGRESS;2255 err = bpf_tc_hook_create(&tc_hook);2256 ASSERT_OK(err, "bpf_tc_hook_create");2257 assert_mprog_count(target, 0);2258 }2259 err = bpf_prog_detach_opts(0, loopback, target, &optd);2260 ASSERT_EQ(err, -ENOENT, "prog_detach");2261 if (chain_tc_old) {2262 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;2263 bpf_tc_hook_destroy(&tc_hook);2264 }2265 assert_mprog_count(target, 0);2266}2267 2268void serial_test_tc_opts_delete_empty(void)2269{2270 test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);2271 test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);2272 test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);2273 test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);2274}2275 2276static void test_tc_chain_mixed(int target)2277{2278 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);2279 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);2280 LIBBPF_OPTS(bpf_prog_attach_opts, opta);2281 LIBBPF_OPTS(bpf_prog_detach_opts, optd);2282 __u32 fd1, fd2, fd3, id1, id2, id3;2283 struct test_tc_link *skel;2284 int err, detach_fd;2285 2286 skel = test_tc_link__open_and_load();2287 if (!ASSERT_OK_PTR(skel, "skel_load"))2288 goto cleanup;2289 2290 fd1 = bpf_program__fd(skel->progs.tc4);2291 fd2 = bpf_program__fd(skel->progs.tc5);2292 fd3 = bpf_program__fd(skel->progs.tc6);2293 2294 id1 = id_from_prog_fd(fd1);2295 id2 = id_from_prog_fd(fd2);2296 id3 = id_from_prog_fd(fd3);2297 2298 ASSERT_NEQ(id1, id2, "prog_ids_1_2");2299 ASSERT_NEQ(id2, id3, "prog_ids_2_3");2300 2301 assert_mprog_count(target, 0);2302 2303 tc_hook.attach_point = target == BPF_TCX_INGRESS ?2304 BPF_TC_INGRESS : BPF_TC_EGRESS;2305 err = bpf_tc_hook_create(&tc_hook);2306 err = err == -EEXIST ? 0 : err;2307 if (!ASSERT_OK(err, "bpf_tc_hook_create"))2308 goto cleanup;2309 2310 tc_opts.prog_fd = fd2;2311 err = bpf_tc_attach(&tc_hook, &tc_opts);2312 if (!ASSERT_OK(err, "bpf_tc_attach"))2313 goto cleanup_hook;2314 2315 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2316 if (!ASSERT_EQ(err, 0, "prog_attach"))2317 goto cleanup_filter;2318 2319 detach_fd = fd3;2320 2321 assert_mprog_count(target, 1);2322 2323 tc_skel_reset_all_seen(skel);2324 ASSERT_OK(system(ping_cmd), ping_cmd);2325 2326 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");2327 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");2328 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");2329 2330 LIBBPF_OPTS_RESET(opta,2331 .flags = BPF_F_REPLACE,2332 .replace_prog_fd = fd3,2333 );2334 2335 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2336 if (!ASSERT_EQ(err, 0, "prog_attach"))2337 goto cleanup_opts;2338 2339 detach_fd = fd1;2340 2341 assert_mprog_count(target, 1);2342 2343 tc_skel_reset_all_seen(skel);2344 ASSERT_OK(system(ping_cmd), ping_cmd);2345 2346 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");2347 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");2348 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");2349 2350cleanup_opts:2351 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);2352 ASSERT_OK(err, "prog_detach");2353 assert_mprog_count(target, 0);2354 2355 tc_skel_reset_all_seen(skel);2356 ASSERT_OK(system(ping_cmd), ping_cmd);2357 2358 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");2359 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");2360 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");2361 2362cleanup_filter:2363 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;2364 err = bpf_tc_detach(&tc_hook, &tc_opts);2365 ASSERT_OK(err, "bpf_tc_detach");2366 2367cleanup_hook:2368 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;2369 bpf_tc_hook_destroy(&tc_hook);2370 2371cleanup:2372 test_tc_link__destroy(skel);2373}2374 2375void serial_test_tc_opts_chain_mixed(void)2376{2377 test_tc_chain_mixed(BPF_TCX_INGRESS);2378 test_tc_chain_mixed(BPF_TCX_EGRESS);2379}2380 2381static int generate_dummy_prog(void)2382{2383 const struct bpf_insn prog_insns[] = {2384 BPF_MOV64_IMM(BPF_REG_0, 0),2385 BPF_EXIT_INSN(),2386 };2387 const size_t prog_insn_cnt = ARRAY_SIZE(prog_insns);2388 LIBBPF_OPTS(bpf_prog_load_opts, opts);2389 const size_t log_buf_sz = 256;2390 char log_buf[log_buf_sz];2391 int fd = -1;2392 2393 opts.log_buf = log_buf;2394 opts.log_size = log_buf_sz;2395 2396 log_buf[0] = '\0';2397 opts.log_level = 0;2398 fd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, "tcx_prog", "GPL",2399 prog_insns, prog_insn_cnt, &opts);2400 ASSERT_STREQ(log_buf, "", "log_0");2401 ASSERT_GE(fd, 0, "prog_fd");2402 return fd;2403}2404 2405static void test_tc_opts_max_target(int target, int flags, bool relative)2406{2407 int err, ifindex, i, prog_fd, last_fd = -1;2408 LIBBPF_OPTS(bpf_prog_attach_opts, opta);2409 const int max_progs = 63;2410 2411 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");2412 ifindex = if_nametoindex("tcx_opts1");2413 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");2414 2415 assert_mprog_count_ifindex(ifindex, target, 0);2416 2417 for (i = 0; i < max_progs; i++) {2418 prog_fd = generate_dummy_prog();2419 if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))2420 goto cleanup;2421 err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);2422 if (!ASSERT_EQ(err, 0, "prog_attach"))2423 goto cleanup;2424 assert_mprog_count_ifindex(ifindex, target, i + 1);2425 if (i == max_progs - 1 && relative)2426 last_fd = prog_fd;2427 else2428 close(prog_fd);2429 }2430 2431 prog_fd = generate_dummy_prog();2432 if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))2433 goto cleanup;2434 opta.flags = flags;2435 if (last_fd > 0)2436 opta.relative_fd = last_fd;2437 err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);2438 ASSERT_EQ(err, -ERANGE, "prog_64_attach");2439 assert_mprog_count_ifindex(ifindex, target, max_progs);2440 close(prog_fd);2441cleanup:2442 if (last_fd > 0)2443 close(last_fd);2444 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");2445 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");2446 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");2447}2448 2449void serial_test_tc_opts_max(void)2450{2451 test_tc_opts_max_target(BPF_TCX_INGRESS, 0, false);2452 test_tc_opts_max_target(BPF_TCX_EGRESS, 0, false);2453 2454 test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_BEFORE, false);2455 test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_BEFORE, true);2456 2457 test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);2458 test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);2459}2460 2461static void test_tc_opts_query_target(int target)2462{2463 const size_t attr_size = offsetofend(union bpf_attr, query);2464 LIBBPF_OPTS(bpf_prog_attach_opts, opta);2465 LIBBPF_OPTS(bpf_prog_detach_opts, optd);2466 LIBBPF_OPTS(bpf_prog_query_opts, optq);2467 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;2468 struct test_tc_link *skel;2469 union bpf_attr attr;2470 __u32 prog_ids[10];2471 int err;2472 2473 skel = test_tc_link__open_and_load();2474 if (!ASSERT_OK_PTR(skel, "skel_load"))2475 goto cleanup;2476 2477 fd1 = bpf_program__fd(skel->progs.tc1);2478 fd2 = bpf_program__fd(skel->progs.tc2);2479 fd3 = bpf_program__fd(skel->progs.tc3);2480 fd4 = bpf_program__fd(skel->progs.tc4);2481 2482 id1 = id_from_prog_fd(fd1);2483 id2 = id_from_prog_fd(fd2);2484 id3 = id_from_prog_fd(fd3);2485 id4 = id_from_prog_fd(fd4);2486 2487 assert_mprog_count(target, 0);2488 2489 LIBBPF_OPTS_RESET(opta,2490 .expected_revision = 1,2491 );2492 2493 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2494 if (!ASSERT_EQ(err, 0, "prog_attach"))2495 goto cleanup;2496 2497 assert_mprog_count(target, 1);2498 2499 LIBBPF_OPTS_RESET(opta,2500 .expected_revision = 2,2501 );2502 2503 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);2504 if (!ASSERT_EQ(err, 0, "prog_attach"))2505 goto cleanup1;2506 2507 assert_mprog_count(target, 2);2508 2509 LIBBPF_OPTS_RESET(opta,2510 .expected_revision = 3,2511 );2512 2513 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2514 if (!ASSERT_EQ(err, 0, "prog_attach"))2515 goto cleanup2;2516 2517 assert_mprog_count(target, 3);2518 2519 LIBBPF_OPTS_RESET(opta,2520 .expected_revision = 4,2521 );2522 2523 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);2524 if (!ASSERT_EQ(err, 0, "prog_attach"))2525 goto cleanup3;2526 2527 assert_mprog_count(target, 4);2528 2529 /* Test 1: Double query via libbpf API */2530 err = bpf_prog_query_opts(loopback, target, &optq);2531 if (!ASSERT_OK(err, "prog_query"))2532 goto cleanup4;2533 2534 ASSERT_EQ(optq.count, 4, "count");2535 ASSERT_EQ(optq.revision, 5, "revision");2536 ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");2537 ASSERT_EQ(optq.link_ids, NULL, "link_ids");2538 2539 memset(prog_ids, 0, sizeof(prog_ids));2540 optq.prog_ids = prog_ids;2541 2542 err = bpf_prog_query_opts(loopback, target, &optq);2543 if (!ASSERT_OK(err, "prog_query"))2544 goto cleanup4;2545 2546 ASSERT_EQ(optq.count, 4, "count");2547 ASSERT_EQ(optq.revision, 5, "revision");2548 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2549 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");2550 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");2551 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");2552 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");2553 ASSERT_EQ(optq.link_ids, NULL, "link_ids");2554 2555 /* Test 2: Double query via bpf_attr & bpf(2) directly */2556 memset(&attr, 0, attr_size);2557 attr.query.target_ifindex = loopback;2558 attr.query.attach_type = target;2559 2560 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2561 if (!ASSERT_OK(err, "prog_query"))2562 goto cleanup4;2563 2564 ASSERT_EQ(attr.query.count, 4, "count");2565 ASSERT_EQ(attr.query.revision, 5, "revision");2566 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2567 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2568 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2569 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2570 ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");2571 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2572 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2573 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2574 2575 memset(prog_ids, 0, sizeof(prog_ids));2576 attr.query.prog_ids = ptr_to_u64(prog_ids);2577 2578 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2579 if (!ASSERT_OK(err, "prog_query"))2580 goto cleanup4;2581 2582 ASSERT_EQ(attr.query.count, 4, "count");2583 ASSERT_EQ(attr.query.revision, 5, "revision");2584 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2585 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2586 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2587 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2588 ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2589 ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2590 ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2591 ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");2592 ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");2593 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2594 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2595 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2596 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2597 2598 /* Test 3: Query with smaller prog_ids array */2599 memset(&attr, 0, attr_size);2600 attr.query.target_ifindex = loopback;2601 attr.query.attach_type = target;2602 2603 memset(prog_ids, 0, sizeof(prog_ids));2604 attr.query.prog_ids = ptr_to_u64(prog_ids);2605 attr.query.count = 2;2606 2607 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2608 ASSERT_EQ(err, -1, "prog_query_should_fail");2609 ASSERT_EQ(errno, ENOSPC, "prog_query_should_fail");2610 2611 ASSERT_EQ(attr.query.count, 4, "count");2612 ASSERT_EQ(attr.query.revision, 5, "revision");2613 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2614 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2615 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2616 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2617 ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2618 ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2619 ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2620 ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2621 ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2622 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2623 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2624 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2625 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2626 2627 /* Test 4: Query with larger prog_ids array */2628 memset(&attr, 0, attr_size);2629 attr.query.target_ifindex = loopback;2630 attr.query.attach_type = target;2631 2632 memset(prog_ids, 0, sizeof(prog_ids));2633 attr.query.prog_ids = ptr_to_u64(prog_ids);2634 attr.query.count = 10;2635 2636 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2637 if (!ASSERT_OK(err, "prog_query"))2638 goto cleanup4;2639 2640 ASSERT_EQ(attr.query.count, 4, "count");2641 ASSERT_EQ(attr.query.revision, 5, "revision");2642 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2643 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2644 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2645 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2646 ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2647 ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2648 ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2649 ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");2650 ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");2651 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2652 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2653 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2654 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2655 2656 /* Test 5: Query with NULL prog_ids array but with count > 0 */2657 memset(&attr, 0, attr_size);2658 attr.query.target_ifindex = loopback;2659 attr.query.attach_type = target;2660 2661 memset(prog_ids, 0, sizeof(prog_ids));2662 attr.query.count = sizeof(prog_ids);2663 2664 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2665 if (!ASSERT_OK(err, "prog_query"))2666 goto cleanup4;2667 2668 ASSERT_EQ(attr.query.count, 4, "count");2669 ASSERT_EQ(attr.query.revision, 5, "revision");2670 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2671 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2672 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2673 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2674 ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");2675 ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");2676 ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2677 ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2678 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2679 ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");2680 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2681 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2682 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2683 2684 /* Test 6: Query with non-NULL prog_ids array but with count == 0 */2685 memset(&attr, 0, attr_size);2686 attr.query.target_ifindex = loopback;2687 attr.query.attach_type = target;2688 2689 memset(prog_ids, 0, sizeof(prog_ids));2690 attr.query.prog_ids = ptr_to_u64(prog_ids);2691 2692 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2693 if (!ASSERT_OK(err, "prog_query"))2694 goto cleanup4;2695 2696 ASSERT_EQ(attr.query.count, 4, "count");2697 ASSERT_EQ(attr.query.revision, 5, "revision");2698 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2699 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2700 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2701 ASSERT_EQ(attr.query.attach_type, target, "attach_type");2702 ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");2703 ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");2704 ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2705 ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2706 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2707 ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2708 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2709 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2710 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2711 2712 /* Test 7: Query with invalid flags */2713 attr.query.attach_flags = 0;2714 attr.query.query_flags = 1;2715 2716 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2717 ASSERT_EQ(err, -1, "prog_query_should_fail");2718 ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");2719 2720 attr.query.attach_flags = 1;2721 attr.query.query_flags = 0;2722 2723 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2724 ASSERT_EQ(err, -1, "prog_query_should_fail");2725 ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");2726 2727cleanup4:2728 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2729 ASSERT_OK(err, "prog_detach");2730 assert_mprog_count(target, 3);2731 2732cleanup3:2733 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2734 ASSERT_OK(err, "prog_detach");2735 assert_mprog_count(target, 2);2736 2737cleanup2:2738 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2739 ASSERT_OK(err, "prog_detach");2740 assert_mprog_count(target, 1);2741 2742cleanup1:2743 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2744 ASSERT_OK(err, "prog_detach");2745 assert_mprog_count(target, 0);2746 2747cleanup:2748 test_tc_link__destroy(skel);2749}2750 2751void serial_test_tc_opts_query(void)2752{2753 test_tc_opts_query_target(BPF_TCX_INGRESS);2754 test_tc_opts_query_target(BPF_TCX_EGRESS);2755}2756 2757static void test_tc_opts_query_attach_target(int target)2758{2759 LIBBPF_OPTS(bpf_prog_attach_opts, opta);2760 LIBBPF_OPTS(bpf_prog_detach_opts, optd);2761 LIBBPF_OPTS(bpf_prog_query_opts, optq);2762 struct test_tc_link *skel;2763 __u32 prog_ids[2];2764 __u32 fd1, id1;2765 int err;2766 2767 skel = test_tc_link__open_and_load();2768 if (!ASSERT_OK_PTR(skel, "skel_load"))2769 goto cleanup;2770 2771 fd1 = bpf_program__fd(skel->progs.tc1);2772 id1 = id_from_prog_fd(fd1);2773 2774 err = bpf_prog_query_opts(loopback, target, &optq);2775 if (!ASSERT_OK(err, "prog_query"))2776 goto cleanup;2777 2778 ASSERT_EQ(optq.count, 0, "count");2779 ASSERT_EQ(optq.revision, 1, "revision");2780 2781 LIBBPF_OPTS_RESET(opta,2782 .expected_revision = optq.revision,2783 );2784 2785 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2786 if (!ASSERT_EQ(err, 0, "prog_attach"))2787 goto cleanup;2788 2789 memset(prog_ids, 0, sizeof(prog_ids));2790 optq.prog_ids = prog_ids;2791 optq.count = ARRAY_SIZE(prog_ids);2792 2793 err = bpf_prog_query_opts(loopback, target, &optq);2794 if (!ASSERT_OK(err, "prog_query"))2795 goto cleanup1;2796 2797 ASSERT_EQ(optq.count, 1, "count");2798 ASSERT_EQ(optq.revision, 2, "revision");2799 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2800 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");2801 2802cleanup1:2803 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2804 ASSERT_OK(err, "prog_detach");2805 assert_mprog_count(target, 0);2806cleanup:2807 test_tc_link__destroy(skel);2808}2809 2810void serial_test_tc_opts_query_attach(void)2811{2812 test_tc_opts_query_attach_target(BPF_TCX_INGRESS);2813 test_tc_opts_query_attach_target(BPF_TCX_EGRESS);2814}2815