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