1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Isovalent */ 3 #include <uapi/linux/if_link.h> 4 #include <net/if.h> 5 #include <test_progs.h> 6 7 #define loopback 1 8 #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 13 void 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 ASSERT_OK(system(ping_cmd), ping_cmd); 63 64 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 65 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 66 67 err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta); 68 if (!ASSERT_EQ(err, 0, "prog_attach")) 69 goto cleanup_in; 70 71 assert_mprog_count(BPF_TCX_INGRESS, 1); 72 assert_mprog_count(BPF_TCX_EGRESS, 1); 73 74 memset(prog_ids, 0, sizeof(prog_ids)); 75 optq.count = ARRAY_SIZE(prog_ids); 76 77 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq); 78 if (!ASSERT_OK(err, "prog_query")) 79 goto cleanup_eg; 80 81 ASSERT_EQ(optq.count, 1, "count"); 82 ASSERT_EQ(optq.revision, 2, "revision"); 83 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 84 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 85 86 ASSERT_OK(system(ping_cmd), ping_cmd); 87 88 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 89 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 90 91 cleanup_eg: 92 err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd); 93 ASSERT_OK(err, "prog_detach_eg"); 94 95 assert_mprog_count(BPF_TCX_INGRESS, 1); 96 assert_mprog_count(BPF_TCX_EGRESS, 0); 97 98 cleanup_in: 99 err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd); 100 ASSERT_OK(err, "prog_detach_in"); 101 102 assert_mprog_count(BPF_TCX_INGRESS, 0); 103 assert_mprog_count(BPF_TCX_EGRESS, 0); 104 105 cleanup: 106 test_tc_link__destroy(skel); 107 } 108 109 static void test_tc_opts_before_target(int target) 110 { 111 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 112 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 113 LIBBPF_OPTS(bpf_prog_query_opts, optq); 114 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 115 struct test_tc_link *skel; 116 __u32 prog_ids[5]; 117 int err; 118 119 skel = test_tc_link__open_and_load(); 120 if (!ASSERT_OK_PTR(skel, "skel_load")) 121 goto cleanup; 122 123 fd1 = bpf_program__fd(skel->progs.tc1); 124 fd2 = bpf_program__fd(skel->progs.tc2); 125 fd3 = bpf_program__fd(skel->progs.tc3); 126 fd4 = bpf_program__fd(skel->progs.tc4); 127 128 id1 = id_from_prog_fd(fd1); 129 id2 = id_from_prog_fd(fd2); 130 id3 = id_from_prog_fd(fd3); 131 id4 = id_from_prog_fd(fd4); 132 133 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 134 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 135 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 136 137 assert_mprog_count(target, 0); 138 139 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 140 if (!ASSERT_EQ(err, 0, "prog_attach")) 141 goto cleanup; 142 143 assert_mprog_count(target, 1); 144 145 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 146 if (!ASSERT_EQ(err, 0, "prog_attach")) 147 goto cleanup_target; 148 149 assert_mprog_count(target, 2); 150 151 optq.prog_ids = prog_ids; 152 153 memset(prog_ids, 0, sizeof(prog_ids)); 154 optq.count = ARRAY_SIZE(prog_ids); 155 156 err = bpf_prog_query_opts(loopback, target, &optq); 157 if (!ASSERT_OK(err, "prog_query")) 158 goto cleanup_target2; 159 160 ASSERT_EQ(optq.count, 2, "count"); 161 ASSERT_EQ(optq.revision, 3, "revision"); 162 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 163 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 164 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 165 166 ASSERT_OK(system(ping_cmd), ping_cmd); 167 168 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 169 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 170 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 171 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 172 173 LIBBPF_OPTS_RESET(opta, 174 .flags = BPF_F_BEFORE, 175 .relative_fd = fd2, 176 ); 177 178 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 179 if (!ASSERT_EQ(err, 0, "prog_attach")) 180 goto cleanup_target2; 181 182 memset(prog_ids, 0, sizeof(prog_ids)); 183 optq.count = ARRAY_SIZE(prog_ids); 184 185 err = bpf_prog_query_opts(loopback, target, &optq); 186 if (!ASSERT_OK(err, "prog_query")) 187 goto cleanup_target3; 188 189 ASSERT_EQ(optq.count, 3, "count"); 190 ASSERT_EQ(optq.revision, 4, "revision"); 191 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 192 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 193 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]"); 194 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 195 196 LIBBPF_OPTS_RESET(opta, 197 .flags = BPF_F_BEFORE, 198 .relative_id = id1, 199 ); 200 201 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 202 if (!ASSERT_EQ(err, 0, "prog_attach")) 203 goto cleanup_target3; 204 205 assert_mprog_count(target, 4); 206 207 memset(prog_ids, 0, sizeof(prog_ids)); 208 optq.count = ARRAY_SIZE(prog_ids); 209 210 err = bpf_prog_query_opts(loopback, target, &optq); 211 if (!ASSERT_OK(err, "prog_query")) 212 goto cleanup_target4; 213 214 ASSERT_EQ(optq.count, 4, "count"); 215 ASSERT_EQ(optq.revision, 5, "revision"); 216 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]"); 217 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]"); 218 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]"); 219 ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]"); 220 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 221 222 ASSERT_OK(system(ping_cmd), ping_cmd); 223 224 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 225 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 226 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 227 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 228 229 cleanup_target4: 230 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 231 ASSERT_OK(err, "prog_detach"); 232 assert_mprog_count(target, 3); 233 234 cleanup_target3: 235 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 236 ASSERT_OK(err, "prog_detach"); 237 assert_mprog_count(target, 2); 238 239 cleanup_target2: 240 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 241 ASSERT_OK(err, "prog_detach"); 242 assert_mprog_count(target, 1); 243 244 cleanup_target: 245 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 246 ASSERT_OK(err, "prog_detach"); 247 assert_mprog_count(target, 0); 248 249 cleanup: 250 test_tc_link__destroy(skel); 251 } 252 253 void serial_test_tc_opts_before(void) 254 { 255 test_tc_opts_before_target(BPF_TCX_INGRESS); 256 test_tc_opts_before_target(BPF_TCX_EGRESS); 257 } 258 259 static void test_tc_opts_after_target(int target) 260 { 261 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 262 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 263 LIBBPF_OPTS(bpf_prog_query_opts, optq); 264 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 265 struct test_tc_link *skel; 266 __u32 prog_ids[5]; 267 int err; 268 269 skel = test_tc_link__open_and_load(); 270 if (!ASSERT_OK_PTR(skel, "skel_load")) 271 goto cleanup; 272 273 fd1 = bpf_program__fd(skel->progs.tc1); 274 fd2 = bpf_program__fd(skel->progs.tc2); 275 fd3 = bpf_program__fd(skel->progs.tc3); 276 fd4 = bpf_program__fd(skel->progs.tc4); 277 278 id1 = id_from_prog_fd(fd1); 279 id2 = id_from_prog_fd(fd2); 280 id3 = id_from_prog_fd(fd3); 281 id4 = id_from_prog_fd(fd4); 282 283 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 284 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 285 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 286 287 assert_mprog_count(target, 0); 288 289 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 290 if (!ASSERT_EQ(err, 0, "prog_attach")) 291 goto cleanup; 292 293 assert_mprog_count(target, 1); 294 295 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 296 if (!ASSERT_EQ(err, 0, "prog_attach")) 297 goto cleanup_target; 298 299 assert_mprog_count(target, 2); 300 301 optq.prog_ids = prog_ids; 302 303 memset(prog_ids, 0, sizeof(prog_ids)); 304 optq.count = ARRAY_SIZE(prog_ids); 305 306 err = bpf_prog_query_opts(loopback, target, &optq); 307 if (!ASSERT_OK(err, "prog_query")) 308 goto cleanup_target2; 309 310 ASSERT_EQ(optq.count, 2, "count"); 311 ASSERT_EQ(optq.revision, 3, "revision"); 312 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 313 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 314 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 315 316 ASSERT_OK(system(ping_cmd), ping_cmd); 317 318 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 319 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 320 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 321 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 322 323 LIBBPF_OPTS_RESET(opta, 324 .flags = BPF_F_AFTER, 325 .relative_fd = fd1, 326 ); 327 328 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 329 if (!ASSERT_EQ(err, 0, "prog_attach")) 330 goto cleanup_target2; 331 332 memset(prog_ids, 0, sizeof(prog_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_target3; 338 339 ASSERT_EQ(optq.count, 3, "count"); 340 ASSERT_EQ(optq.revision, 4, "revision"); 341 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 342 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 343 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]"); 344 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 345 346 LIBBPF_OPTS_RESET(opta, 347 .flags = BPF_F_AFTER, 348 .relative_id = id2, 349 ); 350 351 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 352 if (!ASSERT_EQ(err, 0, "prog_attach")) 353 goto cleanup_target3; 354 355 assert_mprog_count(target, 4); 356 357 memset(prog_ids, 0, sizeof(prog_ids)); 358 optq.count = ARRAY_SIZE(prog_ids); 359 360 err = bpf_prog_query_opts(loopback, target, &optq); 361 if (!ASSERT_OK(err, "prog_query")) 362 goto cleanup_target4; 363 364 ASSERT_EQ(optq.count, 4, "count"); 365 ASSERT_EQ(optq.revision, 5, "revision"); 366 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 367 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 368 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]"); 369 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]"); 370 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 371 372 ASSERT_OK(system(ping_cmd), ping_cmd); 373 374 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 375 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 376 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 377 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 378 379 cleanup_target4: 380 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 381 ASSERT_OK(err, "prog_detach"); 382 assert_mprog_count(target, 3); 383 384 memset(prog_ids, 0, sizeof(prog_ids)); 385 optq.count = ARRAY_SIZE(prog_ids); 386 387 err = bpf_prog_query_opts(loopback, target, &optq); 388 if (!ASSERT_OK(err, "prog_query")) 389 goto cleanup_target3; 390 391 ASSERT_EQ(optq.count, 3, "count"); 392 ASSERT_EQ(optq.revision, 6, "revision"); 393 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 394 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 395 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]"); 396 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 397 398 cleanup_target3: 399 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 400 ASSERT_OK(err, "prog_detach"); 401 assert_mprog_count(target, 2); 402 403 memset(prog_ids, 0, sizeof(prog_ids)); 404 optq.count = ARRAY_SIZE(prog_ids); 405 406 err = bpf_prog_query_opts(loopback, target, &optq); 407 if (!ASSERT_OK(err, "prog_query")) 408 goto cleanup_target2; 409 410 ASSERT_EQ(optq.count, 2, "count"); 411 ASSERT_EQ(optq.revision, 7, "revision"); 412 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 413 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 414 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 415 416 cleanup_target2: 417 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 418 ASSERT_OK(err, "prog_detach"); 419 assert_mprog_count(target, 1); 420 421 memset(prog_ids, 0, sizeof(prog_ids)); 422 optq.count = ARRAY_SIZE(prog_ids); 423 424 err = bpf_prog_query_opts(loopback, target, &optq); 425 if (!ASSERT_OK(err, "prog_query")) 426 goto cleanup_target; 427 428 ASSERT_EQ(optq.count, 1, "count"); 429 ASSERT_EQ(optq.revision, 8, "revision"); 430 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 431 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 432 433 cleanup_target: 434 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 435 ASSERT_OK(err, "prog_detach"); 436 assert_mprog_count(target, 0); 437 438 cleanup: 439 test_tc_link__destroy(skel); 440 } 441 442 void serial_test_tc_opts_after(void) 443 { 444 test_tc_opts_after_target(BPF_TCX_INGRESS); 445 test_tc_opts_after_target(BPF_TCX_EGRESS); 446 } 447 448 static void test_tc_opts_revision_target(int target) 449 { 450 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 451 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 452 LIBBPF_OPTS(bpf_prog_query_opts, optq); 453 __u32 fd1, fd2, id1, id2; 454 struct test_tc_link *skel; 455 __u32 prog_ids[3]; 456 int err; 457 458 skel = test_tc_link__open_and_load(); 459 if (!ASSERT_OK_PTR(skel, "skel_load")) 460 goto cleanup; 461 462 fd1 = bpf_program__fd(skel->progs.tc1); 463 fd2 = bpf_program__fd(skel->progs.tc2); 464 465 id1 = id_from_prog_fd(fd1); 466 id2 = id_from_prog_fd(fd2); 467 468 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 469 470 assert_mprog_count(target, 0); 471 472 LIBBPF_OPTS_RESET(opta, 473 .expected_revision = 1, 474 ); 475 476 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 477 if (!ASSERT_EQ(err, 0, "prog_attach")) 478 goto cleanup; 479 480 assert_mprog_count(target, 1); 481 482 LIBBPF_OPTS_RESET(opta, 483 .expected_revision = 1, 484 ); 485 486 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 487 if (!ASSERT_EQ(err, -ESTALE, "prog_attach")) 488 goto cleanup_target; 489 490 assert_mprog_count(target, 1); 491 492 LIBBPF_OPTS_RESET(opta, 493 .expected_revision = 2, 494 ); 495 496 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 497 if (!ASSERT_EQ(err, 0, "prog_attach")) 498 goto cleanup_target; 499 500 assert_mprog_count(target, 2); 501 502 optq.prog_ids = prog_ids; 503 504 memset(prog_ids, 0, sizeof(prog_ids)); 505 optq.count = ARRAY_SIZE(prog_ids); 506 507 err = bpf_prog_query_opts(loopback, target, &optq); 508 if (!ASSERT_OK(err, "prog_query")) 509 goto cleanup_target2; 510 511 ASSERT_EQ(optq.count, 2, "count"); 512 ASSERT_EQ(optq.revision, 3, "revision"); 513 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 514 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 515 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 516 517 ASSERT_OK(system(ping_cmd), ping_cmd); 518 519 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 520 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 521 522 LIBBPF_OPTS_RESET(optd, 523 .expected_revision = 2, 524 ); 525 526 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 527 ASSERT_EQ(err, -ESTALE, "prog_detach"); 528 assert_mprog_count(target, 2); 529 530 cleanup_target2: 531 LIBBPF_OPTS_RESET(optd, 532 .expected_revision = 3, 533 ); 534 535 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 536 ASSERT_OK(err, "prog_detach"); 537 assert_mprog_count(target, 1); 538 539 cleanup_target: 540 LIBBPF_OPTS_RESET(optd); 541 542 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 543 ASSERT_OK(err, "prog_detach"); 544 assert_mprog_count(target, 0); 545 546 cleanup: 547 test_tc_link__destroy(skel); 548 } 549 550 void serial_test_tc_opts_revision(void) 551 { 552 test_tc_opts_revision_target(BPF_TCX_INGRESS); 553 test_tc_opts_revision_target(BPF_TCX_EGRESS); 554 } 555 556 static void test_tc_chain_classic(int target, bool chain_tc_old) 557 { 558 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); 559 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback); 560 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 561 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 562 bool hook_created = false, tc_attached = false; 563 __u32 fd1, fd2, fd3, id1, id2, id3; 564 struct test_tc_link *skel; 565 int err; 566 567 skel = test_tc_link__open_and_load(); 568 if (!ASSERT_OK_PTR(skel, "skel_load")) 569 goto cleanup; 570 571 fd1 = bpf_program__fd(skel->progs.tc1); 572 fd2 = bpf_program__fd(skel->progs.tc2); 573 fd3 = bpf_program__fd(skel->progs.tc3); 574 575 id1 = id_from_prog_fd(fd1); 576 id2 = id_from_prog_fd(fd2); 577 id3 = id_from_prog_fd(fd3); 578 579 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 580 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 581 582 assert_mprog_count(target, 0); 583 584 if (chain_tc_old) { 585 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 586 BPF_TC_INGRESS : BPF_TC_EGRESS; 587 err = bpf_tc_hook_create(&tc_hook); 588 if (err == 0) 589 hook_created = true; 590 err = err == -EEXIST ? 0 : err; 591 if (!ASSERT_OK(err, "bpf_tc_hook_create")) 592 goto cleanup; 593 594 tc_opts.prog_fd = fd3; 595 err = bpf_tc_attach(&tc_hook, &tc_opts); 596 if (!ASSERT_OK(err, "bpf_tc_attach")) 597 goto cleanup; 598 tc_attached = true; 599 } 600 601 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 602 if (!ASSERT_EQ(err, 0, "prog_attach")) 603 goto cleanup; 604 605 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 606 if (!ASSERT_EQ(err, 0, "prog_attach")) 607 goto cleanup_detach; 608 609 assert_mprog_count(target, 2); 610 611 ASSERT_OK(system(ping_cmd), ping_cmd); 612 613 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 614 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 615 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 616 617 skel->bss->seen_tc1 = false; 618 skel->bss->seen_tc2 = false; 619 skel->bss->seen_tc3 = false; 620 621 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 622 if (!ASSERT_OK(err, "prog_detach")) 623 goto cleanup_detach; 624 625 assert_mprog_count(target, 1); 626 627 ASSERT_OK(system(ping_cmd), ping_cmd); 628 629 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 630 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 631 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 632 633 cleanup_detach: 634 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 635 if (!ASSERT_OK(err, "prog_detach")) 636 goto cleanup; 637 638 __assert_mprog_count(target, 0, chain_tc_old, loopback); 639 cleanup: 640 if (tc_attached) { 641 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0; 642 err = bpf_tc_detach(&tc_hook, &tc_opts); 643 ASSERT_OK(err, "bpf_tc_detach"); 644 } 645 if (hook_created) { 646 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS; 647 bpf_tc_hook_destroy(&tc_hook); 648 } 649 test_tc_link__destroy(skel); 650 assert_mprog_count(target, 0); 651 } 652 653 void serial_test_tc_opts_chain_classic(void) 654 { 655 test_tc_chain_classic(BPF_TCX_INGRESS, false); 656 test_tc_chain_classic(BPF_TCX_EGRESS, false); 657 test_tc_chain_classic(BPF_TCX_INGRESS, true); 658 test_tc_chain_classic(BPF_TCX_EGRESS, true); 659 } 660 661 static void test_tc_opts_replace_target(int target) 662 { 663 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 664 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 665 LIBBPF_OPTS(bpf_prog_query_opts, optq); 666 __u32 fd1, fd2, fd3, id1, id2, id3, detach_fd; 667 __u32 prog_ids[4], prog_flags[4]; 668 struct test_tc_link *skel; 669 int err; 670 671 skel = test_tc_link__open_and_load(); 672 if (!ASSERT_OK_PTR(skel, "skel_load")) 673 goto cleanup; 674 675 fd1 = bpf_program__fd(skel->progs.tc1); 676 fd2 = bpf_program__fd(skel->progs.tc2); 677 fd3 = bpf_program__fd(skel->progs.tc3); 678 679 id1 = id_from_prog_fd(fd1); 680 id2 = id_from_prog_fd(fd2); 681 id3 = id_from_prog_fd(fd3); 682 683 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 684 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 685 686 assert_mprog_count(target, 0); 687 688 LIBBPF_OPTS_RESET(opta, 689 .expected_revision = 1, 690 ); 691 692 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 693 if (!ASSERT_EQ(err, 0, "prog_attach")) 694 goto cleanup; 695 696 assert_mprog_count(target, 1); 697 698 LIBBPF_OPTS_RESET(opta, 699 .flags = BPF_F_BEFORE, 700 .relative_id = id1, 701 .expected_revision = 2, 702 ); 703 704 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 705 if (!ASSERT_EQ(err, 0, "prog_attach")) 706 goto cleanup_target; 707 708 detach_fd = fd2; 709 710 assert_mprog_count(target, 2); 711 712 optq.prog_attach_flags = prog_flags; 713 optq.prog_ids = prog_ids; 714 715 memset(prog_flags, 0, sizeof(prog_flags)); 716 memset(prog_ids, 0, sizeof(prog_ids)); 717 optq.count = ARRAY_SIZE(prog_ids); 718 719 err = bpf_prog_query_opts(loopback, target, &optq); 720 if (!ASSERT_OK(err, "prog_query")) 721 goto cleanup_target2; 722 723 ASSERT_EQ(optq.count, 2, "count"); 724 ASSERT_EQ(optq.revision, 3, "revision"); 725 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 726 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]"); 727 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 728 729 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]"); 730 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]"); 731 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]"); 732 733 ASSERT_OK(system(ping_cmd), ping_cmd); 734 735 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 736 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 737 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 738 739 skel->bss->seen_tc1 = false; 740 skel->bss->seen_tc2 = false; 741 skel->bss->seen_tc3 = false; 742 743 LIBBPF_OPTS_RESET(opta, 744 .flags = BPF_F_REPLACE, 745 .replace_prog_fd = fd2, 746 .expected_revision = 3, 747 ); 748 749 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 750 if (!ASSERT_EQ(err, 0, "prog_attach")) 751 goto cleanup_target2; 752 753 detach_fd = fd3; 754 755 assert_mprog_count(target, 2); 756 757 memset(prog_ids, 0, sizeof(prog_ids)); 758 optq.count = ARRAY_SIZE(prog_ids); 759 760 err = bpf_prog_query_opts(loopback, target, &optq); 761 if (!ASSERT_OK(err, "prog_query")) 762 goto cleanup_target2; 763 764 ASSERT_EQ(optq.count, 2, "count"); 765 ASSERT_EQ(optq.revision, 4, "revision"); 766 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]"); 767 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]"); 768 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 769 770 ASSERT_OK(system(ping_cmd), ping_cmd); 771 772 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 773 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 774 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 775 776 skel->bss->seen_tc1 = false; 777 skel->bss->seen_tc2 = false; 778 skel->bss->seen_tc3 = false; 779 780 LIBBPF_OPTS_RESET(opta, 781 .flags = BPF_F_REPLACE | BPF_F_BEFORE, 782 .replace_prog_fd = fd3, 783 .relative_fd = fd1, 784 .expected_revision = 4, 785 ); 786 787 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 788 if (!ASSERT_EQ(err, 0, "prog_attach")) 789 goto cleanup_target2; 790 791 detach_fd = fd2; 792 793 assert_mprog_count(target, 2); 794 795 memset(prog_ids, 0, sizeof(prog_ids)); 796 optq.count = ARRAY_SIZE(prog_ids); 797 798 err = bpf_prog_query_opts(loopback, target, &optq); 799 if (!ASSERT_OK(err, "prog_query")) 800 goto cleanup_target2; 801 802 ASSERT_EQ(optq.count, 2, "count"); 803 ASSERT_EQ(optq.revision, 5, "revision"); 804 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 805 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]"); 806 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 807 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 851 cleanup_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 856 cleanup_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 863 cleanup: 864 test_tc_link__destroy(skel); 865 } 866 867 void 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 873 static 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); 1016 cleanup: 1017 test_tc_link__destroy(skel); 1018 } 1019 1020 void 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 1026 static 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 ASSERT_OK(system(ping_cmd), ping_cmd); 1088 1089 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1090 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1091 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1092 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1093 1094 LIBBPF_OPTS_RESET(opta, 1095 .flags = BPF_F_BEFORE, 1096 ); 1097 1098 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 1099 if (!ASSERT_EQ(err, 0, "prog_attach")) 1100 goto cleanup_target2; 1101 1102 LIBBPF_OPTS_RESET(opta, 1103 .flags = BPF_F_BEFORE, 1104 ); 1105 1106 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 1107 if (!ASSERT_EQ(err, 0, "prog_attach")) 1108 goto cleanup_target3; 1109 1110 assert_mprog_count(target, 4); 1111 1112 memset(prog_ids, 0, sizeof(prog_ids)); 1113 optq.count = ARRAY_SIZE(prog_ids); 1114 1115 err = bpf_prog_query_opts(loopback, target, &optq); 1116 if (!ASSERT_OK(err, "prog_query")) 1117 goto cleanup_target4; 1118 1119 ASSERT_EQ(optq.count, 4, "count"); 1120 ASSERT_EQ(optq.revision, 5, "revision"); 1121 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]"); 1122 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 1123 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]"); 1124 ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]"); 1125 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1126 1127 ASSERT_OK(system(ping_cmd), ping_cmd); 1128 1129 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1130 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1131 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1132 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1133 1134 cleanup_target4: 1135 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1136 ASSERT_OK(err, "prog_detach"); 1137 assert_mprog_count(target, 3); 1138 1139 cleanup_target3: 1140 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1141 ASSERT_OK(err, "prog_detach"); 1142 assert_mprog_count(target, 2); 1143 1144 cleanup_target2: 1145 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1146 ASSERT_OK(err, "prog_detach"); 1147 assert_mprog_count(target, 1); 1148 1149 cleanup_target: 1150 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1151 ASSERT_OK(err, "prog_detach"); 1152 assert_mprog_count(target, 0); 1153 1154 cleanup: 1155 test_tc_link__destroy(skel); 1156 } 1157 1158 void serial_test_tc_opts_prepend(void) 1159 { 1160 test_tc_opts_prepend_target(BPF_TCX_INGRESS); 1161 test_tc_opts_prepend_target(BPF_TCX_EGRESS); 1162 } 1163 1164 static void test_tc_opts_append_target(int target) 1165 { 1166 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1167 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1168 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1169 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 1170 struct test_tc_link *skel; 1171 __u32 prog_ids[5]; 1172 int err; 1173 1174 skel = test_tc_link__open_and_load(); 1175 if (!ASSERT_OK_PTR(skel, "skel_load")) 1176 goto cleanup; 1177 1178 fd1 = bpf_program__fd(skel->progs.tc1); 1179 fd2 = bpf_program__fd(skel->progs.tc2); 1180 fd3 = bpf_program__fd(skel->progs.tc3); 1181 fd4 = bpf_program__fd(skel->progs.tc4); 1182 1183 id1 = id_from_prog_fd(fd1); 1184 id2 = id_from_prog_fd(fd2); 1185 id3 = id_from_prog_fd(fd3); 1186 id4 = id_from_prog_fd(fd4); 1187 1188 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 1189 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 1190 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 1191 1192 assert_mprog_count(target, 0); 1193 1194 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 1195 if (!ASSERT_EQ(err, 0, "prog_attach")) 1196 goto cleanup; 1197 1198 assert_mprog_count(target, 1); 1199 1200 LIBBPF_OPTS_RESET(opta, 1201 .flags = BPF_F_AFTER, 1202 ); 1203 1204 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 1205 if (!ASSERT_EQ(err, 0, "prog_attach")) 1206 goto cleanup_target; 1207 1208 assert_mprog_count(target, 2); 1209 1210 optq.prog_ids = prog_ids; 1211 1212 memset(prog_ids, 0, sizeof(prog_ids)); 1213 optq.count = ARRAY_SIZE(prog_ids); 1214 1215 err = bpf_prog_query_opts(loopback, target, &optq); 1216 if (!ASSERT_OK(err, "prog_query")) 1217 goto cleanup_target2; 1218 1219 ASSERT_EQ(optq.count, 2, "count"); 1220 ASSERT_EQ(optq.revision, 3, "revision"); 1221 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 1222 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 1223 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1224 1225 ASSERT_OK(system(ping_cmd), ping_cmd); 1226 1227 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1228 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1229 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1230 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1231 1232 LIBBPF_OPTS_RESET(opta, 1233 .flags = BPF_F_AFTER, 1234 ); 1235 1236 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 1237 if (!ASSERT_EQ(err, 0, "prog_attach")) 1238 goto cleanup_target2; 1239 1240 LIBBPF_OPTS_RESET(opta, 1241 .flags = BPF_F_AFTER, 1242 ); 1243 1244 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 1245 if (!ASSERT_EQ(err, 0, "prog_attach")) 1246 goto cleanup_target3; 1247 1248 assert_mprog_count(target, 4); 1249 1250 memset(prog_ids, 0, sizeof(prog_ids)); 1251 optq.count = ARRAY_SIZE(prog_ids); 1252 1253 err = bpf_prog_query_opts(loopback, target, &optq); 1254 if (!ASSERT_OK(err, "prog_query")) 1255 goto cleanup_target4; 1256 1257 ASSERT_EQ(optq.count, 4, "count"); 1258 ASSERT_EQ(optq.revision, 5, "revision"); 1259 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 1260 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 1261 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]"); 1262 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]"); 1263 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1264 1265 ASSERT_OK(system(ping_cmd), ping_cmd); 1266 1267 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1268 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1269 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1270 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1271 1272 cleanup_target4: 1273 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1274 ASSERT_OK(err, "prog_detach"); 1275 assert_mprog_count(target, 3); 1276 1277 cleanup_target3: 1278 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1279 ASSERT_OK(err, "prog_detach"); 1280 assert_mprog_count(target, 2); 1281 1282 cleanup_target2: 1283 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1284 ASSERT_OK(err, "prog_detach"); 1285 assert_mprog_count(target, 1); 1286 1287 cleanup_target: 1288 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1289 ASSERT_OK(err, "prog_detach"); 1290 assert_mprog_count(target, 0); 1291 1292 cleanup: 1293 test_tc_link__destroy(skel); 1294 } 1295 1296 void serial_test_tc_opts_append(void) 1297 { 1298 test_tc_opts_append_target(BPF_TCX_INGRESS); 1299 test_tc_opts_append_target(BPF_TCX_EGRESS); 1300 } 1301 1302 static void test_tc_opts_dev_cleanup_target(int target) 1303 { 1304 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1305 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1306 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1307 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 1308 struct test_tc_link *skel; 1309 int err, ifindex; 1310 1311 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth"); 1312 ifindex = if_nametoindex("tcx_opts1"); 1313 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex"); 1314 1315 skel = test_tc_link__open_and_load(); 1316 if (!ASSERT_OK_PTR(skel, "skel_load")) 1317 goto cleanup; 1318 1319 fd1 = bpf_program__fd(skel->progs.tc1); 1320 fd2 = bpf_program__fd(skel->progs.tc2); 1321 fd3 = bpf_program__fd(skel->progs.tc3); 1322 fd4 = bpf_program__fd(skel->progs.tc4); 1323 1324 id1 = id_from_prog_fd(fd1); 1325 id2 = id_from_prog_fd(fd2); 1326 id3 = id_from_prog_fd(fd3); 1327 id4 = id_from_prog_fd(fd4); 1328 1329 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 1330 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 1331 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 1332 1333 assert_mprog_count_ifindex(ifindex, target, 0); 1334 1335 err = bpf_prog_attach_opts(fd1, ifindex, target, &opta); 1336 if (!ASSERT_EQ(err, 0, "prog_attach")) 1337 goto cleanup; 1338 1339 assert_mprog_count_ifindex(ifindex, target, 1); 1340 1341 err = bpf_prog_attach_opts(fd2, ifindex, target, &opta); 1342 if (!ASSERT_EQ(err, 0, "prog_attach")) 1343 goto cleanup1; 1344 1345 assert_mprog_count_ifindex(ifindex, target, 2); 1346 1347 err = bpf_prog_attach_opts(fd3, ifindex, target, &opta); 1348 if (!ASSERT_EQ(err, 0, "prog_attach")) 1349 goto cleanup2; 1350 1351 assert_mprog_count_ifindex(ifindex, target, 3); 1352 1353 err = bpf_prog_attach_opts(fd4, ifindex, target, &opta); 1354 if (!ASSERT_EQ(err, 0, "prog_attach")) 1355 goto cleanup3; 1356 1357 assert_mprog_count_ifindex(ifindex, target, 4); 1358 1359 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1360 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1361 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1362 return; 1363 cleanup3: 1364 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1365 ASSERT_OK(err, "prog_detach"); 1366 1367 assert_mprog_count_ifindex(ifindex, target, 2); 1368 cleanup2: 1369 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1370 ASSERT_OK(err, "prog_detach"); 1371 1372 assert_mprog_count_ifindex(ifindex, target, 1); 1373 cleanup1: 1374 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1375 ASSERT_OK(err, "prog_detach"); 1376 1377 assert_mprog_count_ifindex(ifindex, target, 0); 1378 cleanup: 1379 test_tc_link__destroy(skel); 1380 1381 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1382 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1383 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1384 } 1385 1386 void serial_test_tc_opts_dev_cleanup(void) 1387 { 1388 test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS); 1389 test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS); 1390 } 1391 1392 static void test_tc_opts_mixed_target(int target) 1393 { 1394 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1395 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1396 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1397 LIBBPF_OPTS(bpf_tcx_opts, optl); 1398 __u32 pid1, pid2, pid3, pid4, lid2, lid4; 1399 __u32 prog_flags[4], link_flags[4]; 1400 __u32 prog_ids[4], link_ids[4]; 1401 struct test_tc_link *skel; 1402 struct bpf_link *link; 1403 int err, detach_fd; 1404 1405 skel = test_tc_link__open(); 1406 if (!ASSERT_OK_PTR(skel, "skel_open")) 1407 goto cleanup; 1408 1409 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1410 0, "tc1_attach_type"); 1411 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1412 0, "tc2_attach_type"); 1413 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1414 0, "tc3_attach_type"); 1415 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1416 0, "tc4_attach_type"); 1417 1418 err = test_tc_link__load(skel); 1419 if (!ASSERT_OK(err, "skel_load")) 1420 goto cleanup; 1421 1422 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1423 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1424 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1425 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1426 1427 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1428 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1429 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1430 1431 assert_mprog_count(target, 0); 1432 1433 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1), 1434 loopback, target, &opta); 1435 if (!ASSERT_EQ(err, 0, "prog_attach")) 1436 goto cleanup; 1437 1438 detach_fd = bpf_program__fd(skel->progs.tc1); 1439 1440 assert_mprog_count(target, 1); 1441 1442 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1443 if (!ASSERT_OK_PTR(link, "link_attach")) 1444 goto cleanup1; 1445 skel->links.tc2 = link; 1446 1447 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 1448 1449 assert_mprog_count(target, 2); 1450 1451 LIBBPF_OPTS_RESET(opta, 1452 .flags = BPF_F_REPLACE, 1453 .replace_prog_fd = bpf_program__fd(skel->progs.tc1), 1454 ); 1455 1456 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2), 1457 loopback, target, &opta); 1458 ASSERT_EQ(err, -EEXIST, "prog_attach"); 1459 1460 assert_mprog_count(target, 2); 1461 1462 LIBBPF_OPTS_RESET(opta, 1463 .flags = BPF_F_REPLACE, 1464 .replace_prog_fd = bpf_program__fd(skel->progs.tc2), 1465 ); 1466 1467 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1), 1468 loopback, target, &opta); 1469 ASSERT_EQ(err, -EEXIST, "prog_attach"); 1470 1471 assert_mprog_count(target, 2); 1472 1473 LIBBPF_OPTS_RESET(opta, 1474 .flags = BPF_F_REPLACE, 1475 .replace_prog_fd = bpf_program__fd(skel->progs.tc2), 1476 ); 1477 1478 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3), 1479 loopback, target, &opta); 1480 ASSERT_EQ(err, -EBUSY, "prog_attach"); 1481 1482 assert_mprog_count(target, 2); 1483 1484 LIBBPF_OPTS_RESET(opta, 1485 .flags = BPF_F_REPLACE, 1486 .replace_prog_fd = bpf_program__fd(skel->progs.tc1), 1487 ); 1488 1489 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3), 1490 loopback, target, &opta); 1491 if (!ASSERT_EQ(err, 0, "prog_attach")) 1492 goto cleanup1; 1493 1494 detach_fd = bpf_program__fd(skel->progs.tc3); 1495 1496 assert_mprog_count(target, 2); 1497 1498 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 1499 if (!ASSERT_OK_PTR(link, "link_attach")) 1500 goto cleanup1; 1501 skel->links.tc4 = link; 1502 1503 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 1504 1505 assert_mprog_count(target, 3); 1506 1507 LIBBPF_OPTS_RESET(opta, 1508 .flags = BPF_F_REPLACE, 1509 .replace_prog_fd = bpf_program__fd(skel->progs.tc4), 1510 ); 1511 1512 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2), 1513 loopback, target, &opta); 1514 ASSERT_EQ(err, -EEXIST, "prog_attach"); 1515 1516 optq.prog_ids = prog_ids; 1517 optq.prog_attach_flags = prog_flags; 1518 optq.link_ids = link_ids; 1519 optq.link_attach_flags = link_flags; 1520 1521 memset(prog_ids, 0, sizeof(prog_ids)); 1522 memset(prog_flags, 0, sizeof(prog_flags)); 1523 memset(link_ids, 0, sizeof(link_ids)); 1524 memset(link_flags, 0, sizeof(link_flags)); 1525 optq.count = ARRAY_SIZE(prog_ids); 1526 1527 err = bpf_prog_query_opts(loopback, target, &optq); 1528 if (!ASSERT_OK(err, "prog_query")) 1529 goto cleanup1; 1530 1531 ASSERT_EQ(optq.count, 3, "count"); 1532 ASSERT_EQ(optq.revision, 5, "revision"); 1533 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]"); 1534 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]"); 1535 ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]"); 1536 ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]"); 1537 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 1538 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]"); 1539 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 1540 ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]"); 1541 ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]"); 1542 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]"); 1543 ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]"); 1544 ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]"); 1545 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 1546 ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]"); 1547 ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]"); 1548 ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]"); 1549 1550 ASSERT_OK(system(ping_cmd), ping_cmd); 1551 1552 cleanup1: 1553 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd); 1554 ASSERT_OK(err, "prog_detach"); 1555 assert_mprog_count(target, 2); 1556 1557 cleanup: 1558 test_tc_link__destroy(skel); 1559 assert_mprog_count(target, 0); 1560 } 1561 1562 void serial_test_tc_opts_mixed(void) 1563 { 1564 test_tc_opts_mixed_target(BPF_TCX_INGRESS); 1565 test_tc_opts_mixed_target(BPF_TCX_EGRESS); 1566 } 1567 1568 static void test_tc_opts_demixed_target(int target) 1569 { 1570 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1571 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1572 LIBBPF_OPTS(bpf_tcx_opts, optl); 1573 struct test_tc_link *skel; 1574 struct bpf_link *link; 1575 __u32 pid1, pid2; 1576 int err; 1577 1578 skel = test_tc_link__open(); 1579 if (!ASSERT_OK_PTR(skel, "skel_open")) 1580 goto cleanup; 1581 1582 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1583 0, "tc1_attach_type"); 1584 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1585 0, "tc2_attach_type"); 1586 1587 err = test_tc_link__load(skel); 1588 if (!ASSERT_OK(err, "skel_load")) 1589 goto cleanup; 1590 1591 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1592 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1593 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1594 1595 assert_mprog_count(target, 0); 1596 1597 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1), 1598 loopback, target, &opta); 1599 if (!ASSERT_EQ(err, 0, "prog_attach")) 1600 goto cleanup; 1601 1602 assert_mprog_count(target, 1); 1603 1604 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1605 if (!ASSERT_OK_PTR(link, "link_attach")) 1606 goto cleanup1; 1607 skel->links.tc2 = link; 1608 1609 assert_mprog_count(target, 2); 1610 1611 LIBBPF_OPTS_RESET(optd, 1612 .flags = BPF_F_AFTER, 1613 ); 1614 1615 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1616 ASSERT_EQ(err, -EBUSY, "prog_detach"); 1617 1618 assert_mprog_count(target, 2); 1619 1620 LIBBPF_OPTS_RESET(optd, 1621 .flags = BPF_F_BEFORE, 1622 ); 1623 1624 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1625 ASSERT_OK(err, "prog_detach"); 1626 1627 assert_mprog_count(target, 1); 1628 goto cleanup; 1629 1630 cleanup1: 1631 err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1), 1632 loopback, target, &optd); 1633 ASSERT_OK(err, "prog_detach"); 1634 assert_mprog_count(target, 2); 1635 1636 cleanup: 1637 test_tc_link__destroy(skel); 1638 assert_mprog_count(target, 0); 1639 } 1640 1641 void serial_test_tc_opts_demixed(void) 1642 { 1643 test_tc_opts_demixed_target(BPF_TCX_INGRESS); 1644 test_tc_opts_demixed_target(BPF_TCX_EGRESS); 1645 } 1646 1647 static void test_tc_opts_detach_target(int target) 1648 { 1649 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1650 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1651 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1652 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 1653 struct test_tc_link *skel; 1654 __u32 prog_ids[5]; 1655 int err; 1656 1657 skel = test_tc_link__open_and_load(); 1658 if (!ASSERT_OK_PTR(skel, "skel_load")) 1659 goto cleanup; 1660 1661 fd1 = bpf_program__fd(skel->progs.tc1); 1662 fd2 = bpf_program__fd(skel->progs.tc2); 1663 fd3 = bpf_program__fd(skel->progs.tc3); 1664 fd4 = bpf_program__fd(skel->progs.tc4); 1665 1666 id1 = id_from_prog_fd(fd1); 1667 id2 = id_from_prog_fd(fd2); 1668 id3 = id_from_prog_fd(fd3); 1669 id4 = id_from_prog_fd(fd4); 1670 1671 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 1672 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 1673 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 1674 1675 assert_mprog_count(target, 0); 1676 1677 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 1678 if (!ASSERT_EQ(err, 0, "prog_attach")) 1679 goto cleanup; 1680 1681 assert_mprog_count(target, 1); 1682 1683 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 1684 if (!ASSERT_EQ(err, 0, "prog_attach")) 1685 goto cleanup1; 1686 1687 assert_mprog_count(target, 2); 1688 1689 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 1690 if (!ASSERT_EQ(err, 0, "prog_attach")) 1691 goto cleanup2; 1692 1693 assert_mprog_count(target, 3); 1694 1695 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 1696 if (!ASSERT_EQ(err, 0, "prog_attach")) 1697 goto cleanup3; 1698 1699 assert_mprog_count(target, 4); 1700 1701 optq.prog_ids = prog_ids; 1702 1703 memset(prog_ids, 0, sizeof(prog_ids)); 1704 optq.count = ARRAY_SIZE(prog_ids); 1705 1706 err = bpf_prog_query_opts(loopback, target, &optq); 1707 if (!ASSERT_OK(err, "prog_query")) 1708 goto cleanup4; 1709 1710 ASSERT_EQ(optq.count, 4, "count"); 1711 ASSERT_EQ(optq.revision, 5, "revision"); 1712 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 1713 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 1714 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]"); 1715 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]"); 1716 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1717 1718 LIBBPF_OPTS_RESET(optd, 1719 .flags = BPF_F_BEFORE, 1720 ); 1721 1722 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1723 ASSERT_OK(err, "prog_detach"); 1724 1725 assert_mprog_count(target, 3); 1726 1727 memset(prog_ids, 0, sizeof(prog_ids)); 1728 optq.count = ARRAY_SIZE(prog_ids); 1729 1730 err = bpf_prog_query_opts(loopback, target, &optq); 1731 if (!ASSERT_OK(err, "prog_query")) 1732 goto cleanup4; 1733 1734 ASSERT_EQ(optq.count, 3, "count"); 1735 ASSERT_EQ(optq.revision, 6, "revision"); 1736 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 1737 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 1738 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]"); 1739 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 1740 1741 LIBBPF_OPTS_RESET(optd, 1742 .flags = BPF_F_AFTER, 1743 ); 1744 1745 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1746 ASSERT_OK(err, "prog_detach"); 1747 1748 assert_mprog_count(target, 2); 1749 1750 memset(prog_ids, 0, sizeof(prog_ids)); 1751 optq.count = ARRAY_SIZE(prog_ids); 1752 1753 err = bpf_prog_query_opts(loopback, target, &optq); 1754 if (!ASSERT_OK(err, "prog_query")) 1755 goto cleanup4; 1756 1757 ASSERT_EQ(optq.count, 2, "count"); 1758 ASSERT_EQ(optq.revision, 7, "revision"); 1759 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 1760 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 1761 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1762 1763 LIBBPF_OPTS_RESET(optd); 1764 1765 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1766 ASSERT_OK(err, "prog_detach"); 1767 assert_mprog_count(target, 1); 1768 1769 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1770 ASSERT_OK(err, "prog_detach"); 1771 assert_mprog_count(target, 0); 1772 1773 LIBBPF_OPTS_RESET(optd, 1774 .flags = BPF_F_BEFORE, 1775 ); 1776 1777 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1778 ASSERT_EQ(err, -ENOENT, "prog_detach"); 1779 1780 LIBBPF_OPTS_RESET(optd, 1781 .flags = BPF_F_AFTER, 1782 ); 1783 1784 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1785 ASSERT_EQ(err, -ENOENT, "prog_detach"); 1786 goto cleanup; 1787 1788 cleanup4: 1789 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1790 ASSERT_OK(err, "prog_detach"); 1791 assert_mprog_count(target, 3); 1792 1793 cleanup3: 1794 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1795 ASSERT_OK(err, "prog_detach"); 1796 assert_mprog_count(target, 2); 1797 1798 cleanup2: 1799 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1800 ASSERT_OK(err, "prog_detach"); 1801 assert_mprog_count(target, 1); 1802 1803 cleanup1: 1804 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1805 ASSERT_OK(err, "prog_detach"); 1806 assert_mprog_count(target, 0); 1807 1808 cleanup: 1809 test_tc_link__destroy(skel); 1810 } 1811 1812 void serial_test_tc_opts_detach(void) 1813 { 1814 test_tc_opts_detach_target(BPF_TCX_INGRESS); 1815 test_tc_opts_detach_target(BPF_TCX_EGRESS); 1816 } 1817 1818 static void test_tc_opts_detach_before_target(int target) 1819 { 1820 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 1821 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 1822 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1823 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 1824 struct test_tc_link *skel; 1825 __u32 prog_ids[5]; 1826 int err; 1827 1828 skel = test_tc_link__open_and_load(); 1829 if (!ASSERT_OK_PTR(skel, "skel_load")) 1830 goto cleanup; 1831 1832 fd1 = bpf_program__fd(skel->progs.tc1); 1833 fd2 = bpf_program__fd(skel->progs.tc2); 1834 fd3 = bpf_program__fd(skel->progs.tc3); 1835 fd4 = bpf_program__fd(skel->progs.tc4); 1836 1837 id1 = id_from_prog_fd(fd1); 1838 id2 = id_from_prog_fd(fd2); 1839 id3 = id_from_prog_fd(fd3); 1840 id4 = id_from_prog_fd(fd4); 1841 1842 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 1843 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 1844 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 1845 1846 assert_mprog_count(target, 0); 1847 1848 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 1849 if (!ASSERT_EQ(err, 0, "prog_attach")) 1850 goto cleanup; 1851 1852 assert_mprog_count(target, 1); 1853 1854 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 1855 if (!ASSERT_EQ(err, 0, "prog_attach")) 1856 goto cleanup1; 1857 1858 assert_mprog_count(target, 2); 1859 1860 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 1861 if (!ASSERT_EQ(err, 0, "prog_attach")) 1862 goto cleanup2; 1863 1864 assert_mprog_count(target, 3); 1865 1866 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 1867 if (!ASSERT_EQ(err, 0, "prog_attach")) 1868 goto cleanup3; 1869 1870 assert_mprog_count(target, 4); 1871 1872 optq.prog_ids = prog_ids; 1873 1874 memset(prog_ids, 0, sizeof(prog_ids)); 1875 optq.count = ARRAY_SIZE(prog_ids); 1876 1877 err = bpf_prog_query_opts(loopback, target, &optq); 1878 if (!ASSERT_OK(err, "prog_query")) 1879 goto cleanup4; 1880 1881 ASSERT_EQ(optq.count, 4, "count"); 1882 ASSERT_EQ(optq.revision, 5, "revision"); 1883 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 1884 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 1885 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]"); 1886 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]"); 1887 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1888 1889 LIBBPF_OPTS_RESET(optd, 1890 .flags = BPF_F_BEFORE, 1891 .relative_fd = fd2, 1892 ); 1893 1894 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1895 ASSERT_OK(err, "prog_detach"); 1896 1897 assert_mprog_count(target, 3); 1898 1899 memset(prog_ids, 0, sizeof(prog_ids)); 1900 optq.count = ARRAY_SIZE(prog_ids); 1901 1902 err = bpf_prog_query_opts(loopback, target, &optq); 1903 if (!ASSERT_OK(err, "prog_query")) 1904 goto cleanup4; 1905 1906 ASSERT_EQ(optq.count, 3, "count"); 1907 ASSERT_EQ(optq.revision, 6, "revision"); 1908 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]"); 1909 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 1910 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]"); 1911 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 1912 1913 LIBBPF_OPTS_RESET(optd, 1914 .flags = BPF_F_BEFORE, 1915 .relative_fd = fd2, 1916 ); 1917 1918 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1919 ASSERT_EQ(err, -ENOENT, "prog_detach"); 1920 assert_mprog_count(target, 3); 1921 1922 LIBBPF_OPTS_RESET(optd, 1923 .flags = BPF_F_BEFORE, 1924 .relative_fd = fd4, 1925 ); 1926 1927 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1928 ASSERT_EQ(err, -ERANGE, "prog_detach"); 1929 assert_mprog_count(target, 3); 1930 1931 LIBBPF_OPTS_RESET(optd, 1932 .flags = BPF_F_BEFORE, 1933 .relative_fd = fd1, 1934 ); 1935 1936 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1937 ASSERT_EQ(err, -ENOENT, "prog_detach"); 1938 assert_mprog_count(target, 3); 1939 1940 LIBBPF_OPTS_RESET(optd, 1941 .flags = BPF_F_BEFORE, 1942 .relative_fd = fd3, 1943 ); 1944 1945 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1946 ASSERT_OK(err, "prog_detach"); 1947 1948 assert_mprog_count(target, 2); 1949 1950 memset(prog_ids, 0, sizeof(prog_ids)); 1951 optq.count = ARRAY_SIZE(prog_ids); 1952 1953 err = bpf_prog_query_opts(loopback, target, &optq); 1954 if (!ASSERT_OK(err, "prog_query")) 1955 goto cleanup4; 1956 1957 ASSERT_EQ(optq.count, 2, "count"); 1958 ASSERT_EQ(optq.revision, 7, "revision"); 1959 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]"); 1960 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]"); 1961 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1962 1963 LIBBPF_OPTS_RESET(optd, 1964 .flags = BPF_F_BEFORE, 1965 .relative_fd = fd4, 1966 ); 1967 1968 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1969 ASSERT_OK(err, "prog_detach"); 1970 1971 assert_mprog_count(target, 1); 1972 1973 memset(prog_ids, 0, sizeof(prog_ids)); 1974 optq.count = ARRAY_SIZE(prog_ids); 1975 1976 err = bpf_prog_query_opts(loopback, target, &optq); 1977 if (!ASSERT_OK(err, "prog_query")) 1978 goto cleanup4; 1979 1980 ASSERT_EQ(optq.count, 1, "count"); 1981 ASSERT_EQ(optq.revision, 8, "revision"); 1982 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]"); 1983 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 1984 1985 LIBBPF_OPTS_RESET(optd, 1986 .flags = BPF_F_BEFORE, 1987 ); 1988 1989 err = bpf_prog_detach_opts(0, loopback, target, &optd); 1990 ASSERT_OK(err, "prog_detach"); 1991 1992 assert_mprog_count(target, 0); 1993 goto cleanup; 1994 1995 cleanup4: 1996 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1997 ASSERT_OK(err, "prog_detach"); 1998 assert_mprog_count(target, 3); 1999 2000 cleanup3: 2001 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2002 ASSERT_OK(err, "prog_detach"); 2003 assert_mprog_count(target, 2); 2004 2005 cleanup2: 2006 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2007 ASSERT_OK(err, "prog_detach"); 2008 assert_mprog_count(target, 1); 2009 2010 cleanup1: 2011 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2012 ASSERT_OK(err, "prog_detach"); 2013 assert_mprog_count(target, 0); 2014 2015 cleanup: 2016 test_tc_link__destroy(skel); 2017 } 2018 2019 void serial_test_tc_opts_detach_before(void) 2020 { 2021 test_tc_opts_detach_before_target(BPF_TCX_INGRESS); 2022 test_tc_opts_detach_before_target(BPF_TCX_EGRESS); 2023 } 2024 2025 static void test_tc_opts_detach_after_target(int target) 2026 { 2027 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 2028 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 2029 LIBBPF_OPTS(bpf_prog_query_opts, optq); 2030 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4; 2031 struct test_tc_link *skel; 2032 __u32 prog_ids[5]; 2033 int err; 2034 2035 skel = test_tc_link__open_and_load(); 2036 if (!ASSERT_OK_PTR(skel, "skel_load")) 2037 goto cleanup; 2038 2039 fd1 = bpf_program__fd(skel->progs.tc1); 2040 fd2 = bpf_program__fd(skel->progs.tc2); 2041 fd3 = bpf_program__fd(skel->progs.tc3); 2042 fd4 = bpf_program__fd(skel->progs.tc4); 2043 2044 id1 = id_from_prog_fd(fd1); 2045 id2 = id_from_prog_fd(fd2); 2046 id3 = id_from_prog_fd(fd3); 2047 id4 = id_from_prog_fd(fd4); 2048 2049 ASSERT_NEQ(id1, id2, "prog_ids_1_2"); 2050 ASSERT_NEQ(id3, id4, "prog_ids_3_4"); 2051 ASSERT_NEQ(id2, id3, "prog_ids_2_3"); 2052 2053 assert_mprog_count(target, 0); 2054 2055 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 2056 if (!ASSERT_EQ(err, 0, "prog_attach")) 2057 goto cleanup; 2058 2059 assert_mprog_count(target, 1); 2060 2061 err = bpf_prog_attach_opts(fd2, loopback, target, &opta); 2062 if (!ASSERT_EQ(err, 0, "prog_attach")) 2063 goto cleanup1; 2064 2065 assert_mprog_count(target, 2); 2066 2067 err = bpf_prog_attach_opts(fd3, loopback, target, &opta); 2068 if (!ASSERT_EQ(err, 0, "prog_attach")) 2069 goto cleanup2; 2070 2071 assert_mprog_count(target, 3); 2072 2073 err = bpf_prog_attach_opts(fd4, loopback, target, &opta); 2074 if (!ASSERT_EQ(err, 0, "prog_attach")) 2075 goto cleanup3; 2076 2077 assert_mprog_count(target, 4); 2078 2079 optq.prog_ids = prog_ids; 2080 2081 memset(prog_ids, 0, sizeof(prog_ids)); 2082 optq.count = ARRAY_SIZE(prog_ids); 2083 2084 err = bpf_prog_query_opts(loopback, target, &optq); 2085 if (!ASSERT_OK(err, "prog_query")) 2086 goto cleanup4; 2087 2088 ASSERT_EQ(optq.count, 4, "count"); 2089 ASSERT_EQ(optq.revision, 5, "revision"); 2090 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 2091 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]"); 2092 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]"); 2093 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]"); 2094 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 2095 2096 LIBBPF_OPTS_RESET(optd, 2097 .flags = BPF_F_AFTER, 2098 .relative_fd = fd1, 2099 ); 2100 2101 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2102 ASSERT_OK(err, "prog_detach"); 2103 2104 assert_mprog_count(target, 3); 2105 2106 memset(prog_ids, 0, sizeof(prog_ids)); 2107 optq.count = ARRAY_SIZE(prog_ids); 2108 2109 err = bpf_prog_query_opts(loopback, target, &optq); 2110 if (!ASSERT_OK(err, "prog_query")) 2111 goto cleanup4; 2112 2113 ASSERT_EQ(optq.count, 3, "count"); 2114 ASSERT_EQ(optq.revision, 6, "revision"); 2115 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 2116 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]"); 2117 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]"); 2118 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]"); 2119 2120 LIBBPF_OPTS_RESET(optd, 2121 .flags = BPF_F_AFTER, 2122 .relative_fd = fd1, 2123 ); 2124 2125 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2126 ASSERT_EQ(err, -ENOENT, "prog_detach"); 2127 assert_mprog_count(target, 3); 2128 2129 LIBBPF_OPTS_RESET(optd, 2130 .flags = BPF_F_AFTER, 2131 .relative_fd = fd4, 2132 ); 2133 2134 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2135 ASSERT_EQ(err, -ERANGE, "prog_detach"); 2136 assert_mprog_count(target, 3); 2137 2138 LIBBPF_OPTS_RESET(optd, 2139 .flags = BPF_F_AFTER, 2140 .relative_fd = fd3, 2141 ); 2142 2143 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2144 ASSERT_EQ(err, -ERANGE, "prog_detach"); 2145 assert_mprog_count(target, 3); 2146 2147 LIBBPF_OPTS_RESET(optd, 2148 .flags = BPF_F_AFTER, 2149 .relative_fd = fd1, 2150 ); 2151 2152 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2153 ASSERT_EQ(err, -ERANGE, "prog_detach"); 2154 assert_mprog_count(target, 3); 2155 2156 LIBBPF_OPTS_RESET(optd, 2157 .flags = BPF_F_AFTER, 2158 .relative_fd = fd1, 2159 ); 2160 2161 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2162 ASSERT_OK(err, "prog_detach"); 2163 2164 assert_mprog_count(target, 2); 2165 2166 memset(prog_ids, 0, sizeof(prog_ids)); 2167 optq.count = ARRAY_SIZE(prog_ids); 2168 2169 err = bpf_prog_query_opts(loopback, target, &optq); 2170 if (!ASSERT_OK(err, "prog_query")) 2171 goto cleanup4; 2172 2173 ASSERT_EQ(optq.count, 2, "count"); 2174 ASSERT_EQ(optq.revision, 7, "revision"); 2175 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 2176 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]"); 2177 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 2178 2179 LIBBPF_OPTS_RESET(optd, 2180 .flags = BPF_F_AFTER, 2181 .relative_fd = fd1, 2182 ); 2183 2184 err = bpf_prog_detach_opts(0, loopback, target, &optd); 2185 ASSERT_OK(err, "prog_detach"); 2186 2187 assert_mprog_count(target, 1); 2188 2189 memset(prog_ids, 0, sizeof(prog_ids)); 2190 optq.count = ARRAY_SIZE(prog_ids); 2191 2192 err = bpf_prog_query_opts(loopback, target, &optq); 2193 if (!ASSERT_OK(err, "prog_query")) 2194 goto cleanup4; 2195 2196 ASSERT_EQ(optq.count, 1, "count"); 2197 ASSERT_EQ(optq.revision, 8, "revision"); 2198 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 2199 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 2200 2201 LIBBPF_OPTS_RESET(optd, 2202 .flags = BPF_F_AFTER, 2203 ); 2204 2205 err = bpf_prog_detach_opts(0, loopback, target, &optd); 2206 ASSERT_OK(err, "prog_detach"); 2207 2208 assert_mprog_count(target, 0); 2209 goto cleanup; 2210 2211 cleanup4: 2212 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 2213 ASSERT_OK(err, "prog_detach"); 2214 assert_mprog_count(target, 3); 2215 2216 cleanup3: 2217 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2218 ASSERT_OK(err, "prog_detach"); 2219 assert_mprog_count(target, 2); 2220 2221 cleanup2: 2222 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2223 ASSERT_OK(err, "prog_detach"); 2224 assert_mprog_count(target, 1); 2225 2226 cleanup1: 2227 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2228 ASSERT_OK(err, "prog_detach"); 2229 assert_mprog_count(target, 0); 2230 2231 cleanup: 2232 test_tc_link__destroy(skel); 2233 } 2234 2235 void serial_test_tc_opts_detach_after(void) 2236 { 2237 test_tc_opts_detach_after_target(BPF_TCX_INGRESS); 2238 test_tc_opts_detach_after_target(BPF_TCX_EGRESS); 2239 } 2240 2241 static void test_tc_opts_delete_empty(int target, bool chain_tc_old) 2242 { 2243 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback); 2244 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 2245 int err; 2246 2247 assert_mprog_count(target, 0); 2248 if (chain_tc_old) { 2249 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 2250 BPF_TC_INGRESS : BPF_TC_EGRESS; 2251 err = bpf_tc_hook_create(&tc_hook); 2252 ASSERT_OK(err, "bpf_tc_hook_create"); 2253 __assert_mprog_count(target, 0, true, loopback); 2254 } 2255 err = bpf_prog_detach_opts(0, loopback, target, &optd); 2256 ASSERT_EQ(err, -ENOENT, "prog_detach"); 2257 if (chain_tc_old) { 2258 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS; 2259 bpf_tc_hook_destroy(&tc_hook); 2260 } 2261 assert_mprog_count(target, 0); 2262 } 2263 2264 void serial_test_tc_opts_delete_empty(void) 2265 { 2266 test_tc_opts_delete_empty(BPF_TCX_INGRESS, false); 2267 test_tc_opts_delete_empty(BPF_TCX_EGRESS, false); 2268 test_tc_opts_delete_empty(BPF_TCX_INGRESS, true); 2269 test_tc_opts_delete_empty(BPF_TCX_EGRESS, true); 2270 } 2271