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 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 93 cleanup_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 100 cleanup_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 107 cleanup: 108 test_tc_link__destroy(skel); 109 } 110 111 static 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 233 cleanup_target4: 234 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 235 ASSERT_OK(err, "prog_detach"); 236 assert_mprog_count(target, 3); 237 238 cleanup_target3: 239 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 240 ASSERT_OK(err, "prog_detach"); 241 assert_mprog_count(target, 2); 242 243 cleanup_target2: 244 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 245 ASSERT_OK(err, "prog_detach"); 246 assert_mprog_count(target, 1); 247 248 cleanup_target: 249 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 250 ASSERT_OK(err, "prog_detach"); 251 assert_mprog_count(target, 0); 252 253 cleanup: 254 test_tc_link__destroy(skel); 255 } 256 257 void 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 263 static 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 385 cleanup_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 404 cleanup_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 422 cleanup_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 439 cleanup_target: 440 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 441 ASSERT_OK(err, "prog_detach"); 442 assert_mprog_count(target, 0); 443 444 cleanup: 445 test_tc_link__destroy(skel); 446 } 447 448 void 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 454 static 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 537 cleanup_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 546 cleanup_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 553 cleanup: 554 test_tc_link__destroy(skel); 555 } 556 557 void 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 563 static 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 638 cleanup_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); 644 cleanup: 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 658 void 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 666 static 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 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 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 1136 cleanup_target4: 1137 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1138 ASSERT_OK(err, "prog_detach"); 1139 assert_mprog_count(target, 3); 1140 1141 cleanup_target3: 1142 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1143 ASSERT_OK(err, "prog_detach"); 1144 assert_mprog_count(target, 2); 1145 1146 cleanup_target2: 1147 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1148 ASSERT_OK(err, "prog_detach"); 1149 assert_mprog_count(target, 1); 1150 1151 cleanup_target: 1152 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1153 ASSERT_OK(err, "prog_detach"); 1154 assert_mprog_count(target, 0); 1155 1156 cleanup: 1157 test_tc_link__destroy(skel); 1158 } 1159 1160 void 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 1166 static 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 1276 cleanup_target4: 1277 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1278 ASSERT_OK(err, "prog_detach"); 1279 assert_mprog_count(target, 3); 1280 1281 cleanup_target3: 1282 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1283 ASSERT_OK(err, "prog_detach"); 1284 assert_mprog_count(target, 2); 1285 1286 cleanup_target2: 1287 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1288 ASSERT_OK(err, "prog_detach"); 1289 assert_mprog_count(target, 1); 1290 1291 cleanup_target: 1292 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1293 ASSERT_OK(err, "prog_detach"); 1294 assert_mprog_count(target, 0); 1295 1296 cleanup: 1297 test_tc_link__destroy(skel); 1298 } 1299 1300 void 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 1306 static 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; 1367 cleanup3: 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); 1372 cleanup2: 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); 1377 cleanup1: 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); 1382 cleanup: 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 1390 void 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 1396 static 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 1556 cleanup1: 1557 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd); 1558 ASSERT_OK(err, "prog_detach"); 1559 assert_mprog_count(target, 2); 1560 1561 cleanup: 1562 test_tc_link__destroy(skel); 1563 assert_mprog_count(target, 0); 1564 } 1565 1566 void 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 1572 static 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 1634 cleanup1: 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 1640 cleanup: 1641 test_tc_link__destroy(skel); 1642 assert_mprog_count(target, 0); 1643 } 1644 1645 void 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 1651 static 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 1792 cleanup4: 1793 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 1794 ASSERT_OK(err, "prog_detach"); 1795 assert_mprog_count(target, 3); 1796 1797 cleanup3: 1798 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 1799 ASSERT_OK(err, "prog_detach"); 1800 assert_mprog_count(target, 2); 1801 1802 cleanup2: 1803 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 1804 ASSERT_OK(err, "prog_detach"); 1805 assert_mprog_count(target, 1); 1806 1807 cleanup1: 1808 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 1809 ASSERT_OK(err, "prog_detach"); 1810 assert_mprog_count(target, 0); 1811 1812 cleanup: 1813 test_tc_link__destroy(skel); 1814 } 1815 1816 void 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 1822 static 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 1999 cleanup4: 2000 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 2001 ASSERT_OK(err, "prog_detach"); 2002 assert_mprog_count(target, 3); 2003 2004 cleanup3: 2005 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2006 ASSERT_OK(err, "prog_detach"); 2007 assert_mprog_count(target, 2); 2008 2009 cleanup2: 2010 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2011 ASSERT_OK(err, "prog_detach"); 2012 assert_mprog_count(target, 1); 2013 2014 cleanup1: 2015 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2016 ASSERT_OK(err, "prog_detach"); 2017 assert_mprog_count(target, 0); 2018 2019 cleanup: 2020 test_tc_link__destroy(skel); 2021 } 2022 2023 void 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 2029 static 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 2215 cleanup4: 2216 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 2217 ASSERT_OK(err, "prog_detach"); 2218 assert_mprog_count(target, 3); 2219 2220 cleanup3: 2221 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2222 ASSERT_OK(err, "prog_detach"); 2223 assert_mprog_count(target, 2); 2224 2225 cleanup2: 2226 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2227 ASSERT_OK(err, "prog_detach"); 2228 assert_mprog_count(target, 1); 2229 2230 cleanup1: 2231 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2232 ASSERT_OK(err, "prog_detach"); 2233 assert_mprog_count(target, 0); 2234 2235 cleanup: 2236 test_tc_link__destroy(skel); 2237 } 2238 2239 void 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 2245 static 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 2268 void 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 2276 static 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 2350 cleanup_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 2362 cleanup_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 2367 cleanup_hook: 2368 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS; 2369 bpf_tc_hook_destroy(&tc_hook); 2370 2371 cleanup: 2372 test_tc_link__destroy(skel); 2373 } 2374 2375 void 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 2381 static 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 = sizeof(prog_insns) / sizeof(struct bpf_insn); 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 2405 static 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 else 2428 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); 2441 cleanup: 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 2449 void 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 2461 static 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[5]; 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 cleanup4: 2599 err = bpf_prog_detach_opts(fd4, loopback, target, &optd); 2600 ASSERT_OK(err, "prog_detach"); 2601 assert_mprog_count(target, 3); 2602 2603 cleanup3: 2604 err = bpf_prog_detach_opts(fd3, loopback, target, &optd); 2605 ASSERT_OK(err, "prog_detach"); 2606 assert_mprog_count(target, 2); 2607 2608 cleanup2: 2609 err = bpf_prog_detach_opts(fd2, loopback, target, &optd); 2610 ASSERT_OK(err, "prog_detach"); 2611 assert_mprog_count(target, 1); 2612 2613 cleanup1: 2614 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2615 ASSERT_OK(err, "prog_detach"); 2616 assert_mprog_count(target, 0); 2617 2618 cleanup: 2619 test_tc_link__destroy(skel); 2620 } 2621 2622 void serial_test_tc_opts_query(void) 2623 { 2624 test_tc_opts_query_target(BPF_TCX_INGRESS); 2625 test_tc_opts_query_target(BPF_TCX_EGRESS); 2626 } 2627 2628 static void test_tc_opts_query_attach_target(int target) 2629 { 2630 LIBBPF_OPTS(bpf_prog_attach_opts, opta); 2631 LIBBPF_OPTS(bpf_prog_detach_opts, optd); 2632 LIBBPF_OPTS(bpf_prog_query_opts, optq); 2633 struct test_tc_link *skel; 2634 __u32 prog_ids[2]; 2635 __u32 fd1, id1; 2636 int err; 2637 2638 skel = test_tc_link__open_and_load(); 2639 if (!ASSERT_OK_PTR(skel, "skel_load")) 2640 goto cleanup; 2641 2642 fd1 = bpf_program__fd(skel->progs.tc1); 2643 id1 = id_from_prog_fd(fd1); 2644 2645 err = bpf_prog_query_opts(loopback, target, &optq); 2646 if (!ASSERT_OK(err, "prog_query")) 2647 goto cleanup; 2648 2649 ASSERT_EQ(optq.count, 0, "count"); 2650 ASSERT_EQ(optq.revision, 1, "revision"); 2651 2652 LIBBPF_OPTS_RESET(opta, 2653 .expected_revision = optq.revision, 2654 ); 2655 2656 err = bpf_prog_attach_opts(fd1, loopback, target, &opta); 2657 if (!ASSERT_EQ(err, 0, "prog_attach")) 2658 goto cleanup; 2659 2660 memset(prog_ids, 0, sizeof(prog_ids)); 2661 optq.prog_ids = prog_ids; 2662 optq.count = ARRAY_SIZE(prog_ids); 2663 2664 err = bpf_prog_query_opts(loopback, target, &optq); 2665 if (!ASSERT_OK(err, "prog_query")) 2666 goto cleanup1; 2667 2668 ASSERT_EQ(optq.count, 1, "count"); 2669 ASSERT_EQ(optq.revision, 2, "revision"); 2670 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]"); 2671 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 2672 2673 cleanup1: 2674 err = bpf_prog_detach_opts(fd1, loopback, target, &optd); 2675 ASSERT_OK(err, "prog_detach"); 2676 assert_mprog_count(target, 0); 2677 cleanup: 2678 test_tc_link__destroy(skel); 2679 } 2680 2681 void serial_test_tc_opts_query_attach(void) 2682 { 2683 test_tc_opts_query_attach_target(BPF_TCX_INGRESS); 2684 test_tc_opts_query_attach_target(BPF_TCX_EGRESS); 2685 } 2686