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_links_basic(void) 14 { 15 LIBBPF_OPTS(bpf_prog_query_opts, optq); 16 LIBBPF_OPTS(bpf_tcx_opts, optl); 17 __u32 prog_ids[2], link_ids[2]; 18 __u32 pid1, pid2, lid1, lid2; 19 struct test_tc_link *skel; 20 struct bpf_link *link; 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 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 28 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 29 30 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 31 32 assert_mprog_count(BPF_TCX_INGRESS, 0); 33 assert_mprog_count(BPF_TCX_EGRESS, 0); 34 35 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1"); 36 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 37 38 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 39 if (!ASSERT_OK_PTR(link, "link_attach")) 40 goto cleanup; 41 42 skel->links.tc1 = link; 43 44 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 45 46 assert_mprog_count(BPF_TCX_INGRESS, 1); 47 assert_mprog_count(BPF_TCX_EGRESS, 0); 48 49 optq.prog_ids = prog_ids; 50 optq.link_ids = link_ids; 51 52 memset(prog_ids, 0, sizeof(prog_ids)); 53 memset(link_ids, 0, sizeof(link_ids)); 54 optq.count = ARRAY_SIZE(prog_ids); 55 56 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq); 57 if (!ASSERT_OK(err, "prog_query")) 58 goto cleanup; 59 60 ASSERT_EQ(optq.count, 1, "count"); 61 ASSERT_EQ(optq.revision, 2, "revision"); 62 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 63 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 64 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 65 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 66 67 ASSERT_OK(system(ping_cmd), ping_cmd); 68 69 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 70 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 71 72 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 73 if (!ASSERT_OK_PTR(link, "link_attach")) 74 goto cleanup; 75 76 skel->links.tc2 = link; 77 78 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 79 ASSERT_NEQ(lid1, lid2, "link_ids_1_2"); 80 81 assert_mprog_count(BPF_TCX_INGRESS, 1); 82 assert_mprog_count(BPF_TCX_EGRESS, 1); 83 84 memset(prog_ids, 0, sizeof(prog_ids)); 85 memset(link_ids, 0, sizeof(link_ids)); 86 optq.count = ARRAY_SIZE(prog_ids); 87 88 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq); 89 if (!ASSERT_OK(err, "prog_query")) 90 goto cleanup; 91 92 ASSERT_EQ(optq.count, 1, "count"); 93 ASSERT_EQ(optq.revision, 2, "revision"); 94 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 95 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 96 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 97 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 98 99 ASSERT_OK(system(ping_cmd), ping_cmd); 100 101 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 102 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 103 cleanup: 104 test_tc_link__destroy(skel); 105 106 assert_mprog_count(BPF_TCX_INGRESS, 0); 107 assert_mprog_count(BPF_TCX_EGRESS, 0); 108 } 109 110 static void test_tc_links_before_target(int target) 111 { 112 LIBBPF_OPTS(bpf_prog_query_opts, optq); 113 LIBBPF_OPTS(bpf_tcx_opts, optl); 114 __u32 prog_ids[5], link_ids[5]; 115 __u32 pid1, pid2, pid3, pid4; 116 __u32 lid1, lid2, lid3, lid4; 117 struct test_tc_link *skel; 118 struct bpf_link *link; 119 int err; 120 121 skel = test_tc_link__open(); 122 if (!ASSERT_OK_PTR(skel, "skel_open")) 123 goto cleanup; 124 125 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 126 0, "tc1_attach_type"); 127 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 128 0, "tc2_attach_type"); 129 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 130 0, "tc3_attach_type"); 131 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 132 0, "tc4_attach_type"); 133 134 err = test_tc_link__load(skel); 135 if (!ASSERT_OK(err, "skel_load")) 136 goto cleanup; 137 138 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 139 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 140 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 141 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 142 143 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 144 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 145 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 146 147 assert_mprog_count(target, 0); 148 149 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 150 if (!ASSERT_OK_PTR(link, "link_attach")) 151 goto cleanup; 152 153 skel->links.tc1 = link; 154 155 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 156 157 assert_mprog_count(target, 1); 158 159 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 160 if (!ASSERT_OK_PTR(link, "link_attach")) 161 goto cleanup; 162 163 skel->links.tc2 = link; 164 165 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 166 167 assert_mprog_count(target, 2); 168 169 optq.prog_ids = prog_ids; 170 optq.link_ids = link_ids; 171 172 memset(prog_ids, 0, sizeof(prog_ids)); 173 memset(link_ids, 0, sizeof(link_ids)); 174 optq.count = ARRAY_SIZE(prog_ids); 175 176 err = bpf_prog_query_opts(loopback, target, &optq); 177 if (!ASSERT_OK(err, "prog_query")) 178 goto cleanup; 179 180 ASSERT_EQ(optq.count, 2, "count"); 181 ASSERT_EQ(optq.revision, 3, "revision"); 182 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 183 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 184 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 185 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 186 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 187 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 188 189 ASSERT_OK(system(ping_cmd), ping_cmd); 190 191 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 192 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 193 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 194 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 195 196 skel->bss->seen_tc1 = false; 197 skel->bss->seen_tc2 = false; 198 199 LIBBPF_OPTS_RESET(optl, 200 .flags = BPF_F_BEFORE, 201 .relative_fd = bpf_program__fd(skel->progs.tc2), 202 ); 203 204 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 205 if (!ASSERT_OK_PTR(link, "link_attach")) 206 goto cleanup; 207 208 skel->links.tc3 = link; 209 210 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 211 212 LIBBPF_OPTS_RESET(optl, 213 .flags = BPF_F_BEFORE | BPF_F_LINK, 214 .relative_id = lid1, 215 ); 216 217 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 218 if (!ASSERT_OK_PTR(link, "link_attach")) 219 goto cleanup; 220 221 skel->links.tc4 = link; 222 223 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 224 225 assert_mprog_count(target, 4); 226 227 memset(prog_ids, 0, sizeof(prog_ids)); 228 memset(link_ids, 0, sizeof(link_ids)); 229 optq.count = ARRAY_SIZE(prog_ids); 230 231 err = bpf_prog_query_opts(loopback, target, &optq); 232 if (!ASSERT_OK(err, "prog_query")) 233 goto cleanup; 234 235 ASSERT_EQ(optq.count, 4, "count"); 236 ASSERT_EQ(optq.revision, 5, "revision"); 237 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]"); 238 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]"); 239 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 240 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 241 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]"); 242 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]"); 243 ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]"); 244 ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]"); 245 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 246 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 247 248 ASSERT_OK(system(ping_cmd), ping_cmd); 249 250 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 251 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 252 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 253 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 254 cleanup: 255 test_tc_link__destroy(skel); 256 assert_mprog_count(target, 0); 257 } 258 259 void serial_test_tc_links_before(void) 260 { 261 test_tc_links_before_target(BPF_TCX_INGRESS); 262 test_tc_links_before_target(BPF_TCX_EGRESS); 263 } 264 265 static void test_tc_links_after_target(int target) 266 { 267 LIBBPF_OPTS(bpf_prog_query_opts, optq); 268 LIBBPF_OPTS(bpf_tcx_opts, optl); 269 __u32 prog_ids[5], link_ids[5]; 270 __u32 pid1, pid2, pid3, pid4; 271 __u32 lid1, lid2, lid3, lid4; 272 struct test_tc_link *skel; 273 struct bpf_link *link; 274 int err; 275 276 skel = test_tc_link__open(); 277 if (!ASSERT_OK_PTR(skel, "skel_open")) 278 goto cleanup; 279 280 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 281 0, "tc1_attach_type"); 282 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 283 0, "tc2_attach_type"); 284 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 285 0, "tc3_attach_type"); 286 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 287 0, "tc4_attach_type"); 288 289 err = test_tc_link__load(skel); 290 if (!ASSERT_OK(err, "skel_load")) 291 goto cleanup; 292 293 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 294 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 295 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 296 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 297 298 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 299 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 300 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 301 302 assert_mprog_count(target, 0); 303 304 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 305 if (!ASSERT_OK_PTR(link, "link_attach")) 306 goto cleanup; 307 308 skel->links.tc1 = link; 309 310 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 311 312 assert_mprog_count(target, 1); 313 314 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 315 if (!ASSERT_OK_PTR(link, "link_attach")) 316 goto cleanup; 317 318 skel->links.tc2 = link; 319 320 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 321 322 assert_mprog_count(target, 2); 323 324 optq.prog_ids = prog_ids; 325 optq.link_ids = link_ids; 326 327 memset(prog_ids, 0, sizeof(prog_ids)); 328 memset(link_ids, 0, sizeof(link_ids)); 329 optq.count = ARRAY_SIZE(prog_ids); 330 331 err = bpf_prog_query_opts(loopback, target, &optq); 332 if (!ASSERT_OK(err, "prog_query")) 333 goto cleanup; 334 335 ASSERT_EQ(optq.count, 2, "count"); 336 ASSERT_EQ(optq.revision, 3, "revision"); 337 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 338 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 339 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 340 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 341 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 342 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 343 344 ASSERT_OK(system(ping_cmd), ping_cmd); 345 346 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 347 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 348 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 349 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 350 351 skel->bss->seen_tc1 = false; 352 skel->bss->seen_tc2 = false; 353 354 LIBBPF_OPTS_RESET(optl, 355 .flags = BPF_F_AFTER, 356 .relative_fd = bpf_program__fd(skel->progs.tc1), 357 ); 358 359 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 360 if (!ASSERT_OK_PTR(link, "link_attach")) 361 goto cleanup; 362 363 skel->links.tc3 = link; 364 365 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 366 367 LIBBPF_OPTS_RESET(optl, 368 .flags = BPF_F_AFTER | BPF_F_LINK, 369 .relative_fd = bpf_link__fd(skel->links.tc2), 370 ); 371 372 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 373 if (!ASSERT_OK_PTR(link, "link_attach")) 374 goto cleanup; 375 376 skel->links.tc4 = link; 377 378 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 379 380 assert_mprog_count(target, 4); 381 382 memset(prog_ids, 0, sizeof(prog_ids)); 383 memset(link_ids, 0, sizeof(link_ids)); 384 optq.count = ARRAY_SIZE(prog_ids); 385 386 err = bpf_prog_query_opts(loopback, target, &optq); 387 if (!ASSERT_OK(err, "prog_query")) 388 goto cleanup; 389 390 ASSERT_EQ(optq.count, 4, "count"); 391 ASSERT_EQ(optq.revision, 5, "revision"); 392 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 393 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 394 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]"); 395 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]"); 396 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]"); 397 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]"); 398 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]"); 399 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]"); 400 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 401 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 402 403 ASSERT_OK(system(ping_cmd), ping_cmd); 404 405 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 406 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 407 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 408 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 409 cleanup: 410 test_tc_link__destroy(skel); 411 assert_mprog_count(target, 0); 412 } 413 414 void serial_test_tc_links_after(void) 415 { 416 test_tc_links_after_target(BPF_TCX_INGRESS); 417 test_tc_links_after_target(BPF_TCX_EGRESS); 418 } 419 420 static void test_tc_links_revision_target(int target) 421 { 422 LIBBPF_OPTS(bpf_prog_query_opts, optq); 423 LIBBPF_OPTS(bpf_tcx_opts, optl); 424 __u32 prog_ids[3], link_ids[3]; 425 __u32 pid1, pid2, lid1, lid2; 426 struct test_tc_link *skel; 427 struct bpf_link *link; 428 int err; 429 430 skel = test_tc_link__open(); 431 if (!ASSERT_OK_PTR(skel, "skel_open")) 432 goto cleanup; 433 434 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 435 0, "tc1_attach_type"); 436 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 437 0, "tc2_attach_type"); 438 439 err = test_tc_link__load(skel); 440 if (!ASSERT_OK(err, "skel_load")) 441 goto cleanup; 442 443 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 444 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 445 446 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 447 448 assert_mprog_count(target, 0); 449 450 optl.expected_revision = 1; 451 452 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 453 if (!ASSERT_OK_PTR(link, "link_attach")) 454 goto cleanup; 455 456 skel->links.tc1 = link; 457 458 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 459 460 assert_mprog_count(target, 1); 461 462 optl.expected_revision = 1; 463 464 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 465 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 466 bpf_link__destroy(link); 467 goto cleanup; 468 } 469 470 assert_mprog_count(target, 1); 471 472 optl.expected_revision = 2; 473 474 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 475 if (!ASSERT_OK_PTR(link, "link_attach")) 476 goto cleanup; 477 478 skel->links.tc2 = link; 479 480 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 481 482 assert_mprog_count(target, 2); 483 484 optq.prog_ids = prog_ids; 485 optq.link_ids = link_ids; 486 487 memset(prog_ids, 0, sizeof(prog_ids)); 488 memset(link_ids, 0, sizeof(link_ids)); 489 optq.count = ARRAY_SIZE(prog_ids); 490 491 err = bpf_prog_query_opts(loopback, target, &optq); 492 if (!ASSERT_OK(err, "prog_query")) 493 goto cleanup; 494 495 ASSERT_EQ(optq.count, 2, "count"); 496 ASSERT_EQ(optq.revision, 3, "revision"); 497 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 498 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 499 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 500 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 501 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 502 ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]"); 503 504 ASSERT_OK(system(ping_cmd), ping_cmd); 505 506 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 507 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 508 cleanup: 509 test_tc_link__destroy(skel); 510 assert_mprog_count(target, 0); 511 } 512 513 void serial_test_tc_links_revision(void) 514 { 515 test_tc_links_revision_target(BPF_TCX_INGRESS); 516 test_tc_links_revision_target(BPF_TCX_EGRESS); 517 } 518 519 static void test_tc_chain_classic(int target, bool chain_tc_old) 520 { 521 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); 522 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback); 523 bool hook_created = false, tc_attached = false; 524 LIBBPF_OPTS(bpf_tcx_opts, optl); 525 __u32 pid1, pid2, pid3; 526 struct test_tc_link *skel; 527 struct bpf_link *link; 528 int err; 529 530 skel = test_tc_link__open(); 531 if (!ASSERT_OK_PTR(skel, "skel_open")) 532 goto cleanup; 533 534 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 535 0, "tc1_attach_type"); 536 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 537 0, "tc2_attach_type"); 538 539 err = test_tc_link__load(skel); 540 if (!ASSERT_OK(err, "skel_load")) 541 goto cleanup; 542 543 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 544 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 545 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 546 547 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 548 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 549 550 assert_mprog_count(target, 0); 551 552 if (chain_tc_old) { 553 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 554 BPF_TC_INGRESS : BPF_TC_EGRESS; 555 err = bpf_tc_hook_create(&tc_hook); 556 if (err == 0) 557 hook_created = true; 558 err = err == -EEXIST ? 0 : err; 559 if (!ASSERT_OK(err, "bpf_tc_hook_create")) 560 goto cleanup; 561 562 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3); 563 err = bpf_tc_attach(&tc_hook, &tc_opts); 564 if (!ASSERT_OK(err, "bpf_tc_attach")) 565 goto cleanup; 566 tc_attached = true; 567 } 568 569 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 570 if (!ASSERT_OK_PTR(link, "link_attach")) 571 goto cleanup; 572 573 skel->links.tc1 = link; 574 575 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 576 if (!ASSERT_OK_PTR(link, "link_attach")) 577 goto cleanup; 578 579 skel->links.tc2 = link; 580 581 assert_mprog_count(target, 2); 582 583 ASSERT_OK(system(ping_cmd), ping_cmd); 584 585 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 586 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 587 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 588 589 skel->bss->seen_tc1 = false; 590 skel->bss->seen_tc2 = false; 591 skel->bss->seen_tc3 = false; 592 593 err = bpf_link__detach(skel->links.tc2); 594 if (!ASSERT_OK(err, "prog_detach")) 595 goto cleanup; 596 597 assert_mprog_count(target, 1); 598 599 ASSERT_OK(system(ping_cmd), ping_cmd); 600 601 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 602 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 603 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 604 cleanup: 605 if (tc_attached) { 606 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0; 607 err = bpf_tc_detach(&tc_hook, &tc_opts); 608 ASSERT_OK(err, "bpf_tc_detach"); 609 } 610 if (hook_created) { 611 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS; 612 bpf_tc_hook_destroy(&tc_hook); 613 } 614 assert_mprog_count(target, 1); 615 test_tc_link__destroy(skel); 616 assert_mprog_count(target, 0); 617 } 618 619 void serial_test_tc_links_chain_classic(void) 620 { 621 test_tc_chain_classic(BPF_TCX_INGRESS, false); 622 test_tc_chain_classic(BPF_TCX_EGRESS, false); 623 test_tc_chain_classic(BPF_TCX_INGRESS, true); 624 test_tc_chain_classic(BPF_TCX_EGRESS, true); 625 } 626 627 static void test_tc_links_replace_target(int target) 628 { 629 LIBBPF_OPTS(bpf_prog_query_opts, optq); 630 LIBBPF_OPTS(bpf_tcx_opts, optl); 631 __u32 pid1, pid2, pid3, lid1, lid2; 632 __u32 prog_ids[4], link_ids[4]; 633 struct test_tc_link *skel; 634 struct bpf_link *link; 635 int err; 636 637 skel = test_tc_link__open(); 638 if (!ASSERT_OK_PTR(skel, "skel_open")) 639 goto cleanup; 640 641 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 642 0, "tc1_attach_type"); 643 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 644 0, "tc2_attach_type"); 645 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 646 0, "tc3_attach_type"); 647 648 err = test_tc_link__load(skel); 649 if (!ASSERT_OK(err, "skel_load")) 650 goto cleanup; 651 652 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 653 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 654 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 655 656 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 657 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 658 659 assert_mprog_count(target, 0); 660 661 optl.expected_revision = 1; 662 663 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 664 if (!ASSERT_OK_PTR(link, "link_attach")) 665 goto cleanup; 666 667 skel->links.tc1 = link; 668 669 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 670 671 assert_mprog_count(target, 1); 672 673 LIBBPF_OPTS_RESET(optl, 674 .flags = BPF_F_BEFORE, 675 .relative_id = pid1, 676 .expected_revision = 2, 677 ); 678 679 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 680 if (!ASSERT_OK_PTR(link, "link_attach")) 681 goto cleanup; 682 683 skel->links.tc2 = link; 684 685 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 686 687 assert_mprog_count(target, 2); 688 689 optq.prog_ids = prog_ids; 690 optq.link_ids = link_ids; 691 692 memset(prog_ids, 0, sizeof(prog_ids)); 693 memset(link_ids, 0, sizeof(link_ids)); 694 optq.count = ARRAY_SIZE(prog_ids); 695 696 err = bpf_prog_query_opts(loopback, target, &optq); 697 if (!ASSERT_OK(err, "prog_query")) 698 goto cleanup; 699 700 ASSERT_EQ(optq.count, 2, "count"); 701 ASSERT_EQ(optq.revision, 3, "revision"); 702 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 703 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 704 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 705 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 706 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 707 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 708 709 ASSERT_OK(system(ping_cmd), ping_cmd); 710 711 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 712 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 713 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 714 715 skel->bss->seen_tc1 = false; 716 skel->bss->seen_tc2 = false; 717 skel->bss->seen_tc3 = false; 718 719 LIBBPF_OPTS_RESET(optl, 720 .flags = BPF_F_REPLACE, 721 .relative_fd = bpf_program__fd(skel->progs.tc2), 722 .expected_revision = 3, 723 ); 724 725 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 726 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 727 bpf_link__destroy(link); 728 goto cleanup; 729 } 730 731 assert_mprog_count(target, 2); 732 733 LIBBPF_OPTS_RESET(optl, 734 .flags = BPF_F_REPLACE | BPF_F_LINK, 735 .relative_fd = bpf_link__fd(skel->links.tc2), 736 .expected_revision = 3, 737 ); 738 739 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 740 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 741 bpf_link__destroy(link); 742 goto cleanup; 743 } 744 745 assert_mprog_count(target, 2); 746 747 LIBBPF_OPTS_RESET(optl, 748 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER, 749 .relative_id = lid2, 750 ); 751 752 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 753 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 754 bpf_link__destroy(link); 755 goto cleanup; 756 } 757 758 assert_mprog_count(target, 2); 759 760 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3); 761 if (!ASSERT_OK(err, "link_update")) 762 goto cleanup; 763 764 assert_mprog_count(target, 2); 765 766 memset(prog_ids, 0, sizeof(prog_ids)); 767 memset(link_ids, 0, sizeof(link_ids)); 768 optq.count = ARRAY_SIZE(prog_ids); 769 770 err = bpf_prog_query_opts(loopback, target, &optq); 771 if (!ASSERT_OK(err, "prog_query")) 772 goto cleanup; 773 774 ASSERT_EQ(optq.count, 2, "count"); 775 ASSERT_EQ(optq.revision, 4, "revision"); 776 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]"); 777 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 778 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 779 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 780 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 781 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 782 783 ASSERT_OK(system(ping_cmd), ping_cmd); 784 785 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 786 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 787 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 788 789 skel->bss->seen_tc1 = false; 790 skel->bss->seen_tc2 = false; 791 skel->bss->seen_tc3 = false; 792 793 err = bpf_link__detach(skel->links.tc2); 794 if (!ASSERT_OK(err, "link_detach")) 795 goto cleanup; 796 797 assert_mprog_count(target, 1); 798 799 memset(prog_ids, 0, sizeof(prog_ids)); 800 memset(link_ids, 0, sizeof(link_ids)); 801 optq.count = ARRAY_SIZE(prog_ids); 802 803 err = bpf_prog_query_opts(loopback, target, &optq); 804 if (!ASSERT_OK(err, "prog_query")) 805 goto cleanup; 806 807 ASSERT_EQ(optq.count, 1, "count"); 808 ASSERT_EQ(optq.revision, 5, "revision"); 809 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 810 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 811 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 812 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 813 814 ASSERT_OK(system(ping_cmd), ping_cmd); 815 816 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 817 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 818 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 819 820 skel->bss->seen_tc1 = false; 821 skel->bss->seen_tc2 = false; 822 skel->bss->seen_tc3 = false; 823 824 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1); 825 if (!ASSERT_OK(err, "link_update_self")) 826 goto cleanup; 827 828 assert_mprog_count(target, 1); 829 830 memset(prog_ids, 0, sizeof(prog_ids)); 831 memset(link_ids, 0, sizeof(link_ids)); 832 optq.count = ARRAY_SIZE(prog_ids); 833 834 err = bpf_prog_query_opts(loopback, target, &optq); 835 if (!ASSERT_OK(err, "prog_query")) 836 goto cleanup; 837 838 ASSERT_EQ(optq.count, 1, "count"); 839 ASSERT_EQ(optq.revision, 5, "revision"); 840 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 841 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 842 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 843 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 844 845 ASSERT_OK(system(ping_cmd), ping_cmd); 846 847 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 848 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 849 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 850 cleanup: 851 test_tc_link__destroy(skel); 852 assert_mprog_count(target, 0); 853 } 854 855 void serial_test_tc_links_replace(void) 856 { 857 test_tc_links_replace_target(BPF_TCX_INGRESS); 858 test_tc_links_replace_target(BPF_TCX_EGRESS); 859 } 860 861 static void test_tc_links_invalid_target(int target) 862 { 863 LIBBPF_OPTS(bpf_prog_query_opts, optq); 864 LIBBPF_OPTS(bpf_tcx_opts, optl); 865 __u32 pid1, pid2, lid1; 866 struct test_tc_link *skel; 867 struct bpf_link *link; 868 int err; 869 870 skel = test_tc_link__open(); 871 if (!ASSERT_OK_PTR(skel, "skel_open")) 872 goto cleanup; 873 874 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 875 0, "tc1_attach_type"); 876 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 877 0, "tc2_attach_type"); 878 879 err = test_tc_link__load(skel); 880 if (!ASSERT_OK(err, "skel_load")) 881 goto cleanup; 882 883 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 884 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 885 886 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 887 888 assert_mprog_count(target, 0); 889 890 optl.flags = BPF_F_BEFORE | BPF_F_AFTER; 891 892 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 893 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 894 bpf_link__destroy(link); 895 goto cleanup; 896 } 897 898 assert_mprog_count(target, 0); 899 900 LIBBPF_OPTS_RESET(optl, 901 .flags = BPF_F_BEFORE | BPF_F_ID, 902 ); 903 904 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 905 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 906 bpf_link__destroy(link); 907 goto cleanup; 908 } 909 910 assert_mprog_count(target, 0); 911 912 LIBBPF_OPTS_RESET(optl, 913 .flags = BPF_F_AFTER | BPF_F_ID, 914 ); 915 916 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 917 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 918 bpf_link__destroy(link); 919 goto cleanup; 920 } 921 922 assert_mprog_count(target, 0); 923 924 LIBBPF_OPTS_RESET(optl, 925 .flags = BPF_F_ID, 926 ); 927 928 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 929 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 930 bpf_link__destroy(link); 931 goto cleanup; 932 } 933 934 assert_mprog_count(target, 0); 935 936 LIBBPF_OPTS_RESET(optl, 937 .flags = BPF_F_LINK, 938 .relative_fd = bpf_program__fd(skel->progs.tc2), 939 ); 940 941 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 942 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 943 bpf_link__destroy(link); 944 goto cleanup; 945 } 946 947 assert_mprog_count(target, 0); 948 949 LIBBPF_OPTS_RESET(optl, 950 .flags = BPF_F_LINK, 951 ); 952 953 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 954 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 955 bpf_link__destroy(link); 956 goto cleanup; 957 } 958 959 assert_mprog_count(target, 0); 960 961 LIBBPF_OPTS_RESET(optl, 962 .relative_fd = bpf_program__fd(skel->progs.tc2), 963 ); 964 965 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 966 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 967 bpf_link__destroy(link); 968 goto cleanup; 969 } 970 971 assert_mprog_count(target, 0); 972 973 LIBBPF_OPTS_RESET(optl, 974 .flags = BPF_F_BEFORE | BPF_F_AFTER, 975 .relative_fd = bpf_program__fd(skel->progs.tc2), 976 ); 977 978 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 979 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 980 bpf_link__destroy(link); 981 goto cleanup; 982 } 983 984 assert_mprog_count(target, 0); 985 986 LIBBPF_OPTS_RESET(optl, 987 .flags = BPF_F_BEFORE, 988 .relative_fd = bpf_program__fd(skel->progs.tc1), 989 ); 990 991 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 992 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 993 bpf_link__destroy(link); 994 goto cleanup; 995 } 996 997 assert_mprog_count(target, 0); 998 999 LIBBPF_OPTS_RESET(optl, 1000 .flags = BPF_F_ID, 1001 .relative_id = pid2, 1002 ); 1003 1004 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1005 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1006 bpf_link__destroy(link); 1007 goto cleanup; 1008 } 1009 1010 assert_mprog_count(target, 0); 1011 1012 LIBBPF_OPTS_RESET(optl, 1013 .flags = BPF_F_ID, 1014 .relative_id = 42, 1015 ); 1016 1017 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1018 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1019 bpf_link__destroy(link); 1020 goto cleanup; 1021 } 1022 1023 assert_mprog_count(target, 0); 1024 1025 LIBBPF_OPTS_RESET(optl, 1026 .flags = BPF_F_BEFORE, 1027 .relative_fd = bpf_program__fd(skel->progs.tc1), 1028 ); 1029 1030 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1031 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1032 bpf_link__destroy(link); 1033 goto cleanup; 1034 } 1035 1036 assert_mprog_count(target, 0); 1037 1038 LIBBPF_OPTS_RESET(optl, 1039 .flags = BPF_F_BEFORE | BPF_F_LINK, 1040 .relative_fd = bpf_program__fd(skel->progs.tc1), 1041 ); 1042 1043 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1044 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1045 bpf_link__destroy(link); 1046 goto cleanup; 1047 } 1048 1049 assert_mprog_count(target, 0); 1050 1051 LIBBPF_OPTS_RESET(optl, 1052 .flags = BPF_F_AFTER, 1053 .relative_fd = bpf_program__fd(skel->progs.tc1), 1054 ); 1055 1056 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1057 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1058 bpf_link__destroy(link); 1059 goto cleanup; 1060 } 1061 1062 assert_mprog_count(target, 0); 1063 1064 LIBBPF_OPTS_RESET(optl); 1065 1066 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl); 1067 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1068 bpf_link__destroy(link); 1069 goto cleanup; 1070 } 1071 1072 assert_mprog_count(target, 0); 1073 1074 LIBBPF_OPTS_RESET(optl, 1075 .flags = BPF_F_AFTER | BPF_F_LINK, 1076 .relative_fd = bpf_program__fd(skel->progs.tc1), 1077 ); 1078 1079 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1080 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1081 bpf_link__destroy(link); 1082 goto cleanup; 1083 } 1084 1085 assert_mprog_count(target, 0); 1086 1087 LIBBPF_OPTS_RESET(optl); 1088 1089 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1090 if (!ASSERT_OK_PTR(link, "link_attach")) 1091 goto cleanup; 1092 1093 skel->links.tc1 = link; 1094 1095 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1096 1097 assert_mprog_count(target, 1); 1098 1099 LIBBPF_OPTS_RESET(optl, 1100 .flags = BPF_F_AFTER | BPF_F_LINK, 1101 .relative_fd = bpf_program__fd(skel->progs.tc1), 1102 ); 1103 1104 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1105 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1106 bpf_link__destroy(link); 1107 goto cleanup; 1108 } 1109 1110 assert_mprog_count(target, 1); 1111 1112 LIBBPF_OPTS_RESET(optl, 1113 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1114 .relative_id = ~0, 1115 ); 1116 1117 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1118 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1119 bpf_link__destroy(link); 1120 goto cleanup; 1121 } 1122 1123 assert_mprog_count(target, 1); 1124 1125 LIBBPF_OPTS_RESET(optl, 1126 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1127 .relative_id = lid1, 1128 ); 1129 1130 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1131 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1132 bpf_link__destroy(link); 1133 goto cleanup; 1134 } 1135 1136 assert_mprog_count(target, 1); 1137 1138 LIBBPF_OPTS_RESET(optl, 1139 .flags = BPF_F_BEFORE | BPF_F_ID, 1140 .relative_id = pid1, 1141 ); 1142 1143 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1144 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1145 bpf_link__destroy(link); 1146 goto cleanup; 1147 } 1148 assert_mprog_count(target, 1); 1149 1150 LIBBPF_OPTS_RESET(optl, 1151 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1152 .relative_id = lid1, 1153 ); 1154 1155 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1156 if (!ASSERT_OK_PTR(link, "link_attach")) 1157 goto cleanup; 1158 1159 skel->links.tc2 = link; 1160 1161 assert_mprog_count(target, 2); 1162 cleanup: 1163 test_tc_link__destroy(skel); 1164 assert_mprog_count(target, 0); 1165 } 1166 1167 void serial_test_tc_links_invalid(void) 1168 { 1169 test_tc_links_invalid_target(BPF_TCX_INGRESS); 1170 test_tc_links_invalid_target(BPF_TCX_EGRESS); 1171 } 1172 1173 static void test_tc_links_prepend_target(int target) 1174 { 1175 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1176 LIBBPF_OPTS(bpf_tcx_opts, optl); 1177 __u32 prog_ids[5], link_ids[5]; 1178 __u32 pid1, pid2, pid3, pid4; 1179 __u32 lid1, lid2, lid3, lid4; 1180 struct test_tc_link *skel; 1181 struct bpf_link *link; 1182 int err; 1183 1184 skel = test_tc_link__open(); 1185 if (!ASSERT_OK_PTR(skel, "skel_open")) 1186 goto cleanup; 1187 1188 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1189 0, "tc1_attach_type"); 1190 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1191 0, "tc2_attach_type"); 1192 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1193 0, "tc3_attach_type"); 1194 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1195 0, "tc4_attach_type"); 1196 1197 err = test_tc_link__load(skel); 1198 if (!ASSERT_OK(err, "skel_load")) 1199 goto cleanup; 1200 1201 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1202 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1203 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1204 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1205 1206 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1207 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1208 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1209 1210 assert_mprog_count(target, 0); 1211 1212 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1213 if (!ASSERT_OK_PTR(link, "link_attach")) 1214 goto cleanup; 1215 1216 skel->links.tc1 = link; 1217 1218 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1219 1220 assert_mprog_count(target, 1); 1221 1222 LIBBPF_OPTS_RESET(optl, 1223 .flags = BPF_F_BEFORE, 1224 ); 1225 1226 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1227 if (!ASSERT_OK_PTR(link, "link_attach")) 1228 goto cleanup; 1229 1230 skel->links.tc2 = link; 1231 1232 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 1233 1234 assert_mprog_count(target, 2); 1235 1236 optq.prog_ids = prog_ids; 1237 optq.link_ids = link_ids; 1238 1239 memset(prog_ids, 0, sizeof(prog_ids)); 1240 memset(link_ids, 0, sizeof(link_ids)); 1241 optq.count = ARRAY_SIZE(prog_ids); 1242 1243 err = bpf_prog_query_opts(loopback, target, &optq); 1244 if (!ASSERT_OK(err, "prog_query")) 1245 goto cleanup; 1246 1247 ASSERT_EQ(optq.count, 2, "count"); 1248 ASSERT_EQ(optq.revision, 3, "revision"); 1249 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 1250 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 1251 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 1252 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 1253 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1254 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 1255 1256 ASSERT_OK(system(ping_cmd), ping_cmd); 1257 1258 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1259 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1260 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1261 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1262 1263 skel->bss->seen_tc1 = false; 1264 skel->bss->seen_tc2 = false; 1265 1266 LIBBPF_OPTS_RESET(optl, 1267 .flags = BPF_F_BEFORE, 1268 ); 1269 1270 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 1271 if (!ASSERT_OK_PTR(link, "link_attach")) 1272 goto cleanup; 1273 1274 skel->links.tc3 = link; 1275 1276 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 1277 1278 LIBBPF_OPTS_RESET(optl, 1279 .flags = BPF_F_BEFORE, 1280 ); 1281 1282 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 1283 if (!ASSERT_OK_PTR(link, "link_attach")) 1284 goto cleanup; 1285 1286 skel->links.tc4 = link; 1287 1288 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 1289 1290 assert_mprog_count(target, 4); 1291 1292 memset(prog_ids, 0, sizeof(prog_ids)); 1293 memset(link_ids, 0, sizeof(link_ids)); 1294 optq.count = ARRAY_SIZE(prog_ids); 1295 1296 err = bpf_prog_query_opts(loopback, target, &optq); 1297 if (!ASSERT_OK(err, "prog_query")) 1298 goto cleanup; 1299 1300 ASSERT_EQ(optq.count, 4, "count"); 1301 ASSERT_EQ(optq.revision, 5, "revision"); 1302 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]"); 1303 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]"); 1304 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]"); 1305 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]"); 1306 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]"); 1307 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]"); 1308 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]"); 1309 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]"); 1310 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1311 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 1312 1313 ASSERT_OK(system(ping_cmd), ping_cmd); 1314 1315 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1316 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1317 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1318 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1319 cleanup: 1320 test_tc_link__destroy(skel); 1321 assert_mprog_count(target, 0); 1322 } 1323 1324 void serial_test_tc_links_prepend(void) 1325 { 1326 test_tc_links_prepend_target(BPF_TCX_INGRESS); 1327 test_tc_links_prepend_target(BPF_TCX_EGRESS); 1328 } 1329 1330 static void test_tc_links_append_target(int target) 1331 { 1332 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1333 LIBBPF_OPTS(bpf_tcx_opts, optl); 1334 __u32 prog_ids[5], link_ids[5]; 1335 __u32 pid1, pid2, pid3, pid4; 1336 __u32 lid1, lid2, lid3, lid4; 1337 struct test_tc_link *skel; 1338 struct bpf_link *link; 1339 int err; 1340 1341 skel = test_tc_link__open(); 1342 if (!ASSERT_OK_PTR(skel, "skel_open")) 1343 goto cleanup; 1344 1345 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1346 0, "tc1_attach_type"); 1347 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1348 0, "tc2_attach_type"); 1349 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1350 0, "tc3_attach_type"); 1351 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1352 0, "tc4_attach_type"); 1353 1354 err = test_tc_link__load(skel); 1355 if (!ASSERT_OK(err, "skel_load")) 1356 goto cleanup; 1357 1358 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1359 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1360 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1361 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1362 1363 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1364 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1365 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1366 1367 assert_mprog_count(target, 0); 1368 1369 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1370 if (!ASSERT_OK_PTR(link, "link_attach")) 1371 goto cleanup; 1372 1373 skel->links.tc1 = link; 1374 1375 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1376 1377 assert_mprog_count(target, 1); 1378 1379 LIBBPF_OPTS_RESET(optl, 1380 .flags = BPF_F_AFTER, 1381 ); 1382 1383 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1384 if (!ASSERT_OK_PTR(link, "link_attach")) 1385 goto cleanup; 1386 1387 skel->links.tc2 = link; 1388 1389 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 1390 1391 assert_mprog_count(target, 2); 1392 1393 optq.prog_ids = prog_ids; 1394 optq.link_ids = link_ids; 1395 1396 memset(prog_ids, 0, sizeof(prog_ids)); 1397 memset(link_ids, 0, sizeof(link_ids)); 1398 optq.count = ARRAY_SIZE(prog_ids); 1399 1400 err = bpf_prog_query_opts(loopback, target, &optq); 1401 if (!ASSERT_OK(err, "prog_query")) 1402 goto cleanup; 1403 1404 ASSERT_EQ(optq.count, 2, "count"); 1405 ASSERT_EQ(optq.revision, 3, "revision"); 1406 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 1407 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 1408 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 1409 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 1410 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1411 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 1412 1413 ASSERT_OK(system(ping_cmd), ping_cmd); 1414 1415 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1416 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1417 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1418 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1419 1420 skel->bss->seen_tc1 = false; 1421 skel->bss->seen_tc2 = false; 1422 1423 LIBBPF_OPTS_RESET(optl, 1424 .flags = BPF_F_AFTER, 1425 ); 1426 1427 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 1428 if (!ASSERT_OK_PTR(link, "link_attach")) 1429 goto cleanup; 1430 1431 skel->links.tc3 = link; 1432 1433 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 1434 1435 LIBBPF_OPTS_RESET(optl, 1436 .flags = BPF_F_AFTER, 1437 ); 1438 1439 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 1440 if (!ASSERT_OK_PTR(link, "link_attach")) 1441 goto cleanup; 1442 1443 skel->links.tc4 = link; 1444 1445 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 1446 1447 assert_mprog_count(target, 4); 1448 1449 memset(prog_ids, 0, sizeof(prog_ids)); 1450 memset(link_ids, 0, sizeof(link_ids)); 1451 optq.count = ARRAY_SIZE(prog_ids); 1452 1453 err = bpf_prog_query_opts(loopback, target, &optq); 1454 if (!ASSERT_OK(err, "prog_query")) 1455 goto cleanup; 1456 1457 ASSERT_EQ(optq.count, 4, "count"); 1458 ASSERT_EQ(optq.revision, 5, "revision"); 1459 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 1460 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 1461 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 1462 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 1463 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]"); 1464 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]"); 1465 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]"); 1466 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]"); 1467 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1468 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 1469 1470 ASSERT_OK(system(ping_cmd), ping_cmd); 1471 1472 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1473 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1474 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1475 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1476 cleanup: 1477 test_tc_link__destroy(skel); 1478 assert_mprog_count(target, 0); 1479 } 1480 1481 void serial_test_tc_links_append(void) 1482 { 1483 test_tc_links_append_target(BPF_TCX_INGRESS); 1484 test_tc_links_append_target(BPF_TCX_EGRESS); 1485 } 1486 1487 static void test_tc_links_dev_cleanup_target(int target) 1488 { 1489 LIBBPF_OPTS(bpf_tcx_opts, optl); 1490 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1491 __u32 pid1, pid2, pid3, pid4; 1492 struct test_tc_link *skel; 1493 struct bpf_link *link; 1494 int err, ifindex; 1495 1496 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth"); 1497 ifindex = if_nametoindex("tcx_opts1"); 1498 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex"); 1499 1500 skel = test_tc_link__open(); 1501 if (!ASSERT_OK_PTR(skel, "skel_open")) 1502 goto cleanup; 1503 1504 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1505 0, "tc1_attach_type"); 1506 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1507 0, "tc2_attach_type"); 1508 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1509 0, "tc3_attach_type"); 1510 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1511 0, "tc4_attach_type"); 1512 1513 err = test_tc_link__load(skel); 1514 if (!ASSERT_OK(err, "skel_load")) 1515 goto cleanup; 1516 1517 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1518 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1519 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1520 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1521 1522 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1523 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1524 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1525 1526 assert_mprog_count(target, 0); 1527 1528 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl); 1529 if (!ASSERT_OK_PTR(link, "link_attach")) 1530 goto cleanup; 1531 1532 skel->links.tc1 = link; 1533 1534 assert_mprog_count_ifindex(ifindex, target, 1); 1535 1536 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl); 1537 if (!ASSERT_OK_PTR(link, "link_attach")) 1538 goto cleanup; 1539 1540 skel->links.tc2 = link; 1541 1542 assert_mprog_count_ifindex(ifindex, target, 2); 1543 1544 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl); 1545 if (!ASSERT_OK_PTR(link, "link_attach")) 1546 goto cleanup; 1547 1548 skel->links.tc3 = link; 1549 1550 assert_mprog_count_ifindex(ifindex, target, 3); 1551 1552 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl); 1553 if (!ASSERT_OK_PTR(link, "link_attach")) 1554 goto cleanup; 1555 1556 skel->links.tc4 = link; 1557 1558 assert_mprog_count_ifindex(ifindex, target, 4); 1559 1560 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1561 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1562 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1563 1564 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex"); 1565 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex"); 1566 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex"); 1567 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex"); 1568 1569 test_tc_link__destroy(skel); 1570 return; 1571 cleanup: 1572 test_tc_link__destroy(skel); 1573 1574 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1575 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1576 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1577 } 1578 1579 void serial_test_tc_links_dev_cleanup(void) 1580 { 1581 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS); 1582 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS); 1583 } 1584