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 tc_skel_reset_all_seen(skel); 69 ASSERT_OK(system(ping_cmd), ping_cmd); 70 71 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 72 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 73 74 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 75 if (!ASSERT_OK_PTR(link, "link_attach")) 76 goto cleanup; 77 78 skel->links.tc2 = link; 79 80 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 81 ASSERT_NEQ(lid1, lid2, "link_ids_1_2"); 82 83 assert_mprog_count(BPF_TCX_INGRESS, 1); 84 assert_mprog_count(BPF_TCX_EGRESS, 1); 85 86 memset(prog_ids, 0, sizeof(prog_ids)); 87 memset(link_ids, 0, sizeof(link_ids)); 88 optq.count = ARRAY_SIZE(prog_ids); 89 90 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq); 91 if (!ASSERT_OK(err, "prog_query")) 92 goto cleanup; 93 94 ASSERT_EQ(optq.count, 1, "count"); 95 ASSERT_EQ(optq.revision, 2, "revision"); 96 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 97 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 98 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 99 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 100 101 tc_skel_reset_all_seen(skel); 102 ASSERT_OK(system(ping_cmd), ping_cmd); 103 104 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 105 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 106 cleanup: 107 test_tc_link__destroy(skel); 108 109 assert_mprog_count(BPF_TCX_INGRESS, 0); 110 assert_mprog_count(BPF_TCX_EGRESS, 0); 111 } 112 113 static void test_tc_links_before_target(int target) 114 { 115 LIBBPF_OPTS(bpf_prog_query_opts, optq); 116 LIBBPF_OPTS(bpf_tcx_opts, optl); 117 __u32 prog_ids[5], link_ids[5]; 118 __u32 pid1, pid2, pid3, pid4; 119 __u32 lid1, lid2, lid3, lid4; 120 struct test_tc_link *skel; 121 struct bpf_link *link; 122 int err; 123 124 skel = test_tc_link__open(); 125 if (!ASSERT_OK_PTR(skel, "skel_open")) 126 goto cleanup; 127 128 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 129 0, "tc1_attach_type"); 130 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 131 0, "tc2_attach_type"); 132 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 133 0, "tc3_attach_type"); 134 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 135 0, "tc4_attach_type"); 136 137 err = test_tc_link__load(skel); 138 if (!ASSERT_OK(err, "skel_load")) 139 goto cleanup; 140 141 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 142 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 143 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 144 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 145 146 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 147 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 148 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 149 150 assert_mprog_count(target, 0); 151 152 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 153 if (!ASSERT_OK_PTR(link, "link_attach")) 154 goto cleanup; 155 156 skel->links.tc1 = link; 157 158 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 159 160 assert_mprog_count(target, 1); 161 162 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 163 if (!ASSERT_OK_PTR(link, "link_attach")) 164 goto cleanup; 165 166 skel->links.tc2 = link; 167 168 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 169 170 assert_mprog_count(target, 2); 171 172 optq.prog_ids = prog_ids; 173 optq.link_ids = link_ids; 174 175 memset(prog_ids, 0, sizeof(prog_ids)); 176 memset(link_ids, 0, sizeof(link_ids)); 177 optq.count = ARRAY_SIZE(prog_ids); 178 179 err = bpf_prog_query_opts(loopback, target, &optq); 180 if (!ASSERT_OK(err, "prog_query")) 181 goto cleanup; 182 183 ASSERT_EQ(optq.count, 2, "count"); 184 ASSERT_EQ(optq.revision, 3, "revision"); 185 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 186 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 187 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 188 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 189 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 190 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 191 192 tc_skel_reset_all_seen(skel); 193 ASSERT_OK(system(ping_cmd), ping_cmd); 194 195 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 196 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 197 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 198 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 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 tc_skel_reset_all_seen(skel); 250 ASSERT_OK(system(ping_cmd), ping_cmd); 251 252 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 253 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 254 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 255 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 256 cleanup: 257 test_tc_link__destroy(skel); 258 assert_mprog_count(target, 0); 259 } 260 261 void serial_test_tc_links_before(void) 262 { 263 test_tc_links_before_target(BPF_TCX_INGRESS); 264 test_tc_links_before_target(BPF_TCX_EGRESS); 265 } 266 267 static void test_tc_links_after_target(int target) 268 { 269 LIBBPF_OPTS(bpf_prog_query_opts, optq); 270 LIBBPF_OPTS(bpf_tcx_opts, optl); 271 __u32 prog_ids[5], link_ids[5]; 272 __u32 pid1, pid2, pid3, pid4; 273 __u32 lid1, lid2, lid3, lid4; 274 struct test_tc_link *skel; 275 struct bpf_link *link; 276 int err; 277 278 skel = test_tc_link__open(); 279 if (!ASSERT_OK_PTR(skel, "skel_open")) 280 goto cleanup; 281 282 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 283 0, "tc1_attach_type"); 284 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 285 0, "tc2_attach_type"); 286 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 287 0, "tc3_attach_type"); 288 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 289 0, "tc4_attach_type"); 290 291 err = test_tc_link__load(skel); 292 if (!ASSERT_OK(err, "skel_load")) 293 goto cleanup; 294 295 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 296 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 297 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 298 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 299 300 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 301 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 302 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 303 304 assert_mprog_count(target, 0); 305 306 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 307 if (!ASSERT_OK_PTR(link, "link_attach")) 308 goto cleanup; 309 310 skel->links.tc1 = link; 311 312 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 313 314 assert_mprog_count(target, 1); 315 316 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 317 if (!ASSERT_OK_PTR(link, "link_attach")) 318 goto cleanup; 319 320 skel->links.tc2 = link; 321 322 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 323 324 assert_mprog_count(target, 2); 325 326 optq.prog_ids = prog_ids; 327 optq.link_ids = link_ids; 328 329 memset(prog_ids, 0, sizeof(prog_ids)); 330 memset(link_ids, 0, sizeof(link_ids)); 331 optq.count = ARRAY_SIZE(prog_ids); 332 333 err = bpf_prog_query_opts(loopback, target, &optq); 334 if (!ASSERT_OK(err, "prog_query")) 335 goto cleanup; 336 337 ASSERT_EQ(optq.count, 2, "count"); 338 ASSERT_EQ(optq.revision, 3, "revision"); 339 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 340 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 341 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 342 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 343 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 344 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 345 346 tc_skel_reset_all_seen(skel); 347 ASSERT_OK(system(ping_cmd), ping_cmd); 348 349 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 350 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 351 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 352 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 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 tc_skel_reset_all_seen(skel); 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 tc_skel_reset_all_seen(skel); 506 ASSERT_OK(system(ping_cmd), ping_cmd); 507 508 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 509 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 510 cleanup: 511 test_tc_link__destroy(skel); 512 assert_mprog_count(target, 0); 513 } 514 515 void serial_test_tc_links_revision(void) 516 { 517 test_tc_links_revision_target(BPF_TCX_INGRESS); 518 test_tc_links_revision_target(BPF_TCX_EGRESS); 519 } 520 521 static void test_tc_chain_classic(int target, bool chain_tc_old) 522 { 523 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); 524 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback); 525 bool hook_created = false, tc_attached = false; 526 LIBBPF_OPTS(bpf_tcx_opts, optl); 527 __u32 pid1, pid2, pid3; 528 struct test_tc_link *skel; 529 struct bpf_link *link; 530 int err; 531 532 skel = test_tc_link__open(); 533 if (!ASSERT_OK_PTR(skel, "skel_open")) 534 goto cleanup; 535 536 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 537 0, "tc1_attach_type"); 538 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 539 0, "tc2_attach_type"); 540 541 err = test_tc_link__load(skel); 542 if (!ASSERT_OK(err, "skel_load")) 543 goto cleanup; 544 545 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 546 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 547 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 548 549 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 550 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 551 552 assert_mprog_count(target, 0); 553 554 if (chain_tc_old) { 555 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 556 BPF_TC_INGRESS : BPF_TC_EGRESS; 557 err = bpf_tc_hook_create(&tc_hook); 558 if (err == 0) 559 hook_created = true; 560 err = err == -EEXIST ? 0 : err; 561 if (!ASSERT_OK(err, "bpf_tc_hook_create")) 562 goto cleanup; 563 564 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3); 565 err = bpf_tc_attach(&tc_hook, &tc_opts); 566 if (!ASSERT_OK(err, "bpf_tc_attach")) 567 goto cleanup; 568 tc_attached = true; 569 } 570 571 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 572 if (!ASSERT_OK_PTR(link, "link_attach")) 573 goto cleanup; 574 575 skel->links.tc1 = link; 576 577 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 578 if (!ASSERT_OK_PTR(link, "link_attach")) 579 goto cleanup; 580 581 skel->links.tc2 = link; 582 583 assert_mprog_count(target, 2); 584 585 tc_skel_reset_all_seen(skel); 586 ASSERT_OK(system(ping_cmd), ping_cmd); 587 588 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 589 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 590 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 591 592 err = bpf_link__detach(skel->links.tc2); 593 if (!ASSERT_OK(err, "prog_detach")) 594 goto cleanup; 595 596 assert_mprog_count(target, 1); 597 598 tc_skel_reset_all_seen(skel); 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 tc_skel_reset_all_seen(skel); 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 LIBBPF_OPTS_RESET(optl, 717 .flags = BPF_F_REPLACE, 718 .relative_fd = bpf_program__fd(skel->progs.tc2), 719 .expected_revision = 3, 720 ); 721 722 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 723 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 724 bpf_link__destroy(link); 725 goto cleanup; 726 } 727 728 assert_mprog_count(target, 2); 729 730 LIBBPF_OPTS_RESET(optl, 731 .flags = BPF_F_REPLACE | BPF_F_LINK, 732 .relative_fd = bpf_link__fd(skel->links.tc2), 733 .expected_revision = 3, 734 ); 735 736 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 737 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 738 bpf_link__destroy(link); 739 goto cleanup; 740 } 741 742 assert_mprog_count(target, 2); 743 744 LIBBPF_OPTS_RESET(optl, 745 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER, 746 .relative_id = lid2, 747 ); 748 749 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 750 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 751 bpf_link__destroy(link); 752 goto cleanup; 753 } 754 755 assert_mprog_count(target, 2); 756 757 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3); 758 if (!ASSERT_OK(err, "link_update")) 759 goto cleanup; 760 761 assert_mprog_count(target, 2); 762 763 memset(prog_ids, 0, sizeof(prog_ids)); 764 memset(link_ids, 0, sizeof(link_ids)); 765 optq.count = ARRAY_SIZE(prog_ids); 766 767 err = bpf_prog_query_opts(loopback, target, &optq); 768 if (!ASSERT_OK(err, "prog_query")) 769 goto cleanup; 770 771 ASSERT_EQ(optq.count, 2, "count"); 772 ASSERT_EQ(optq.revision, 4, "revision"); 773 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]"); 774 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 775 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 776 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 777 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 778 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 779 780 tc_skel_reset_all_seen(skel); 781 ASSERT_OK(system(ping_cmd), ping_cmd); 782 783 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 784 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 785 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 786 787 err = bpf_link__detach(skel->links.tc2); 788 if (!ASSERT_OK(err, "link_detach")) 789 goto cleanup; 790 791 assert_mprog_count(target, 1); 792 793 memset(prog_ids, 0, sizeof(prog_ids)); 794 memset(link_ids, 0, sizeof(link_ids)); 795 optq.count = ARRAY_SIZE(prog_ids); 796 797 err = bpf_prog_query_opts(loopback, target, &optq); 798 if (!ASSERT_OK(err, "prog_query")) 799 goto cleanup; 800 801 ASSERT_EQ(optq.count, 1, "count"); 802 ASSERT_EQ(optq.revision, 5, "revision"); 803 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 804 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 805 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 806 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 807 808 tc_skel_reset_all_seen(skel); 809 ASSERT_OK(system(ping_cmd), ping_cmd); 810 811 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 812 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 813 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 814 815 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1); 816 if (!ASSERT_OK(err, "link_update_self")) 817 goto cleanup; 818 819 assert_mprog_count(target, 1); 820 821 memset(prog_ids, 0, sizeof(prog_ids)); 822 memset(link_ids, 0, sizeof(link_ids)); 823 optq.count = ARRAY_SIZE(prog_ids); 824 825 err = bpf_prog_query_opts(loopback, target, &optq); 826 if (!ASSERT_OK(err, "prog_query")) 827 goto cleanup; 828 829 ASSERT_EQ(optq.count, 1, "count"); 830 ASSERT_EQ(optq.revision, 5, "revision"); 831 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 832 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 833 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]"); 834 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]"); 835 836 tc_skel_reset_all_seen(skel); 837 ASSERT_OK(system(ping_cmd), ping_cmd); 838 839 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 840 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 841 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 842 cleanup: 843 test_tc_link__destroy(skel); 844 assert_mprog_count(target, 0); 845 } 846 847 void serial_test_tc_links_replace(void) 848 { 849 test_tc_links_replace_target(BPF_TCX_INGRESS); 850 test_tc_links_replace_target(BPF_TCX_EGRESS); 851 } 852 853 static void test_tc_links_invalid_target(int target) 854 { 855 LIBBPF_OPTS(bpf_prog_query_opts, optq); 856 LIBBPF_OPTS(bpf_tcx_opts, optl); 857 __u32 pid1, pid2, lid1; 858 struct test_tc_link *skel; 859 struct bpf_link *link; 860 int err; 861 862 skel = test_tc_link__open(); 863 if (!ASSERT_OK_PTR(skel, "skel_open")) 864 goto cleanup; 865 866 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 867 0, "tc1_attach_type"); 868 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 869 0, "tc2_attach_type"); 870 871 err = test_tc_link__load(skel); 872 if (!ASSERT_OK(err, "skel_load")) 873 goto cleanup; 874 875 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 876 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 877 878 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 879 880 assert_mprog_count(target, 0); 881 882 optl.flags = BPF_F_BEFORE | BPF_F_AFTER; 883 884 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 885 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 886 bpf_link__destroy(link); 887 goto cleanup; 888 } 889 890 assert_mprog_count(target, 0); 891 892 LIBBPF_OPTS_RESET(optl, 893 .flags = BPF_F_BEFORE | BPF_F_ID, 894 ); 895 896 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 897 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 898 bpf_link__destroy(link); 899 goto cleanup; 900 } 901 902 assert_mprog_count(target, 0); 903 904 LIBBPF_OPTS_RESET(optl, 905 .flags = BPF_F_AFTER | BPF_F_ID, 906 ); 907 908 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 909 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 910 bpf_link__destroy(link); 911 goto cleanup; 912 } 913 914 assert_mprog_count(target, 0); 915 916 LIBBPF_OPTS_RESET(optl, 917 .flags = BPF_F_ID, 918 ); 919 920 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 921 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 922 bpf_link__destroy(link); 923 goto cleanup; 924 } 925 926 assert_mprog_count(target, 0); 927 928 LIBBPF_OPTS_RESET(optl, 929 .flags = BPF_F_LINK, 930 .relative_fd = bpf_program__fd(skel->progs.tc2), 931 ); 932 933 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 934 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 935 bpf_link__destroy(link); 936 goto cleanup; 937 } 938 939 assert_mprog_count(target, 0); 940 941 LIBBPF_OPTS_RESET(optl, 942 .flags = BPF_F_LINK, 943 ); 944 945 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 946 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 947 bpf_link__destroy(link); 948 goto cleanup; 949 } 950 951 assert_mprog_count(target, 0); 952 953 LIBBPF_OPTS_RESET(optl, 954 .relative_fd = bpf_program__fd(skel->progs.tc2), 955 ); 956 957 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 958 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 959 bpf_link__destroy(link); 960 goto cleanup; 961 } 962 963 assert_mprog_count(target, 0); 964 965 LIBBPF_OPTS_RESET(optl, 966 .flags = BPF_F_BEFORE | BPF_F_AFTER, 967 .relative_fd = bpf_program__fd(skel->progs.tc2), 968 ); 969 970 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 971 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 972 bpf_link__destroy(link); 973 goto cleanup; 974 } 975 976 assert_mprog_count(target, 0); 977 978 LIBBPF_OPTS_RESET(optl, 979 .flags = BPF_F_BEFORE, 980 .relative_fd = bpf_program__fd(skel->progs.tc1), 981 ); 982 983 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 984 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 985 bpf_link__destroy(link); 986 goto cleanup; 987 } 988 989 assert_mprog_count(target, 0); 990 991 LIBBPF_OPTS_RESET(optl, 992 .flags = BPF_F_ID, 993 .relative_id = pid2, 994 ); 995 996 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 997 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 998 bpf_link__destroy(link); 999 goto cleanup; 1000 } 1001 1002 assert_mprog_count(target, 0); 1003 1004 LIBBPF_OPTS_RESET(optl, 1005 .flags = BPF_F_ID, 1006 .relative_id = 42, 1007 ); 1008 1009 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1010 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1011 bpf_link__destroy(link); 1012 goto cleanup; 1013 } 1014 1015 assert_mprog_count(target, 0); 1016 1017 LIBBPF_OPTS_RESET(optl, 1018 .flags = BPF_F_BEFORE, 1019 .relative_fd = bpf_program__fd(skel->progs.tc1), 1020 ); 1021 1022 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1023 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1024 bpf_link__destroy(link); 1025 goto cleanup; 1026 } 1027 1028 assert_mprog_count(target, 0); 1029 1030 LIBBPF_OPTS_RESET(optl, 1031 .flags = BPF_F_BEFORE | BPF_F_LINK, 1032 .relative_fd = bpf_program__fd(skel->progs.tc1), 1033 ); 1034 1035 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1036 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1037 bpf_link__destroy(link); 1038 goto cleanup; 1039 } 1040 1041 assert_mprog_count(target, 0); 1042 1043 LIBBPF_OPTS_RESET(optl, 1044 .flags = BPF_F_AFTER, 1045 .relative_fd = bpf_program__fd(skel->progs.tc1), 1046 ); 1047 1048 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1049 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1050 bpf_link__destroy(link); 1051 goto cleanup; 1052 } 1053 1054 assert_mprog_count(target, 0); 1055 1056 LIBBPF_OPTS_RESET(optl); 1057 1058 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl); 1059 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1060 bpf_link__destroy(link); 1061 goto cleanup; 1062 } 1063 1064 assert_mprog_count(target, 0); 1065 1066 LIBBPF_OPTS_RESET(optl, 1067 .flags = BPF_F_AFTER | BPF_F_LINK, 1068 .relative_fd = bpf_program__fd(skel->progs.tc1), 1069 ); 1070 1071 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1072 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1073 bpf_link__destroy(link); 1074 goto cleanup; 1075 } 1076 1077 assert_mprog_count(target, 0); 1078 1079 LIBBPF_OPTS_RESET(optl); 1080 1081 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1082 if (!ASSERT_OK_PTR(link, "link_attach")) 1083 goto cleanup; 1084 1085 skel->links.tc1 = link; 1086 1087 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1088 1089 assert_mprog_count(target, 1); 1090 1091 LIBBPF_OPTS_RESET(optl, 1092 .flags = BPF_F_AFTER | BPF_F_LINK, 1093 .relative_fd = bpf_program__fd(skel->progs.tc1), 1094 ); 1095 1096 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1097 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1098 bpf_link__destroy(link); 1099 goto cleanup; 1100 } 1101 1102 assert_mprog_count(target, 1); 1103 1104 LIBBPF_OPTS_RESET(optl, 1105 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1106 .relative_id = ~0, 1107 ); 1108 1109 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1110 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1111 bpf_link__destroy(link); 1112 goto cleanup; 1113 } 1114 1115 assert_mprog_count(target, 1); 1116 1117 LIBBPF_OPTS_RESET(optl, 1118 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1119 .relative_id = lid1, 1120 ); 1121 1122 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1123 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1124 bpf_link__destroy(link); 1125 goto cleanup; 1126 } 1127 1128 assert_mprog_count(target, 1); 1129 1130 LIBBPF_OPTS_RESET(optl, 1131 .flags = BPF_F_BEFORE | BPF_F_ID, 1132 .relative_id = pid1, 1133 ); 1134 1135 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1136 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 1137 bpf_link__destroy(link); 1138 goto cleanup; 1139 } 1140 assert_mprog_count(target, 1); 1141 1142 LIBBPF_OPTS_RESET(optl, 1143 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID, 1144 .relative_id = lid1, 1145 ); 1146 1147 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1148 if (!ASSERT_OK_PTR(link, "link_attach")) 1149 goto cleanup; 1150 1151 skel->links.tc2 = link; 1152 1153 assert_mprog_count(target, 2); 1154 cleanup: 1155 test_tc_link__destroy(skel); 1156 assert_mprog_count(target, 0); 1157 } 1158 1159 void serial_test_tc_links_invalid(void) 1160 { 1161 test_tc_links_invalid_target(BPF_TCX_INGRESS); 1162 test_tc_links_invalid_target(BPF_TCX_EGRESS); 1163 } 1164 1165 static void test_tc_links_prepend_target(int target) 1166 { 1167 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1168 LIBBPF_OPTS(bpf_tcx_opts, optl); 1169 __u32 prog_ids[5], link_ids[5]; 1170 __u32 pid1, pid2, pid3, pid4; 1171 __u32 lid1, lid2, lid3, lid4; 1172 struct test_tc_link *skel; 1173 struct bpf_link *link; 1174 int err; 1175 1176 skel = test_tc_link__open(); 1177 if (!ASSERT_OK_PTR(skel, "skel_open")) 1178 goto cleanup; 1179 1180 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1181 0, "tc1_attach_type"); 1182 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1183 0, "tc2_attach_type"); 1184 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1185 0, "tc3_attach_type"); 1186 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1187 0, "tc4_attach_type"); 1188 1189 err = test_tc_link__load(skel); 1190 if (!ASSERT_OK(err, "skel_load")) 1191 goto cleanup; 1192 1193 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1194 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1195 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1196 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1197 1198 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1199 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1200 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1201 1202 assert_mprog_count(target, 0); 1203 1204 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1205 if (!ASSERT_OK_PTR(link, "link_attach")) 1206 goto cleanup; 1207 1208 skel->links.tc1 = link; 1209 1210 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1211 1212 assert_mprog_count(target, 1); 1213 1214 LIBBPF_OPTS_RESET(optl, 1215 .flags = BPF_F_BEFORE, 1216 ); 1217 1218 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1219 if (!ASSERT_OK_PTR(link, "link_attach")) 1220 goto cleanup; 1221 1222 skel->links.tc2 = link; 1223 1224 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 1225 1226 assert_mprog_count(target, 2); 1227 1228 optq.prog_ids = prog_ids; 1229 optq.link_ids = link_ids; 1230 1231 memset(prog_ids, 0, sizeof(prog_ids)); 1232 memset(link_ids, 0, sizeof(link_ids)); 1233 optq.count = ARRAY_SIZE(prog_ids); 1234 1235 err = bpf_prog_query_opts(loopback, target, &optq); 1236 if (!ASSERT_OK(err, "prog_query")) 1237 goto cleanup; 1238 1239 ASSERT_EQ(optq.count, 2, "count"); 1240 ASSERT_EQ(optq.revision, 3, "revision"); 1241 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]"); 1242 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]"); 1243 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]"); 1244 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]"); 1245 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1246 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 1247 1248 tc_skel_reset_all_seen(skel); 1249 ASSERT_OK(system(ping_cmd), ping_cmd); 1250 1251 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1252 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1253 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1254 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1255 1256 LIBBPF_OPTS_RESET(optl, 1257 .flags = BPF_F_BEFORE, 1258 ); 1259 1260 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 1261 if (!ASSERT_OK_PTR(link, "link_attach")) 1262 goto cleanup; 1263 1264 skel->links.tc3 = link; 1265 1266 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 1267 1268 LIBBPF_OPTS_RESET(optl, 1269 .flags = BPF_F_BEFORE, 1270 ); 1271 1272 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 1273 if (!ASSERT_OK_PTR(link, "link_attach")) 1274 goto cleanup; 1275 1276 skel->links.tc4 = link; 1277 1278 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 1279 1280 assert_mprog_count(target, 4); 1281 1282 memset(prog_ids, 0, sizeof(prog_ids)); 1283 memset(link_ids, 0, sizeof(link_ids)); 1284 optq.count = ARRAY_SIZE(prog_ids); 1285 1286 err = bpf_prog_query_opts(loopback, target, &optq); 1287 if (!ASSERT_OK(err, "prog_query")) 1288 goto cleanup; 1289 1290 ASSERT_EQ(optq.count, 4, "count"); 1291 ASSERT_EQ(optq.revision, 5, "revision"); 1292 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]"); 1293 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]"); 1294 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]"); 1295 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]"); 1296 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]"); 1297 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]"); 1298 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]"); 1299 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]"); 1300 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1301 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 1302 1303 tc_skel_reset_all_seen(skel); 1304 ASSERT_OK(system(ping_cmd), ping_cmd); 1305 1306 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1307 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1308 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1309 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1310 cleanup: 1311 test_tc_link__destroy(skel); 1312 assert_mprog_count(target, 0); 1313 } 1314 1315 void serial_test_tc_links_prepend(void) 1316 { 1317 test_tc_links_prepend_target(BPF_TCX_INGRESS); 1318 test_tc_links_prepend_target(BPF_TCX_EGRESS); 1319 } 1320 1321 static void test_tc_links_append_target(int target) 1322 { 1323 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1324 LIBBPF_OPTS(bpf_tcx_opts, optl); 1325 __u32 prog_ids[5], link_ids[5]; 1326 __u32 pid1, pid2, pid3, pid4; 1327 __u32 lid1, lid2, lid3, lid4; 1328 struct test_tc_link *skel; 1329 struct bpf_link *link; 1330 int err; 1331 1332 skel = test_tc_link__open(); 1333 if (!ASSERT_OK_PTR(skel, "skel_open")) 1334 goto cleanup; 1335 1336 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1337 0, "tc1_attach_type"); 1338 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1339 0, "tc2_attach_type"); 1340 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1341 0, "tc3_attach_type"); 1342 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1343 0, "tc4_attach_type"); 1344 1345 err = test_tc_link__load(skel); 1346 if (!ASSERT_OK(err, "skel_load")) 1347 goto cleanup; 1348 1349 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1350 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1351 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1352 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1353 1354 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1355 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1356 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1357 1358 assert_mprog_count(target, 0); 1359 1360 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1361 if (!ASSERT_OK_PTR(link, "link_attach")) 1362 goto cleanup; 1363 1364 skel->links.tc1 = link; 1365 1366 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1)); 1367 1368 assert_mprog_count(target, 1); 1369 1370 LIBBPF_OPTS_RESET(optl, 1371 .flags = BPF_F_AFTER, 1372 ); 1373 1374 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1375 if (!ASSERT_OK_PTR(link, "link_attach")) 1376 goto cleanup; 1377 1378 skel->links.tc2 = link; 1379 1380 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2)); 1381 1382 assert_mprog_count(target, 2); 1383 1384 optq.prog_ids = prog_ids; 1385 optq.link_ids = link_ids; 1386 1387 memset(prog_ids, 0, sizeof(prog_ids)); 1388 memset(link_ids, 0, sizeof(link_ids)); 1389 optq.count = ARRAY_SIZE(prog_ids); 1390 1391 err = bpf_prog_query_opts(loopback, target, &optq); 1392 if (!ASSERT_OK(err, "prog_query")) 1393 goto cleanup; 1394 1395 ASSERT_EQ(optq.count, 2, "count"); 1396 ASSERT_EQ(optq.revision, 3, "revision"); 1397 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 1398 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 1399 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 1400 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 1401 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]"); 1402 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]"); 1403 1404 tc_skel_reset_all_seen(skel); 1405 ASSERT_OK(system(ping_cmd), ping_cmd); 1406 1407 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1408 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1409 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3"); 1410 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1411 1412 LIBBPF_OPTS_RESET(optl, 1413 .flags = BPF_F_AFTER, 1414 ); 1415 1416 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl); 1417 if (!ASSERT_OK_PTR(link, "link_attach")) 1418 goto cleanup; 1419 1420 skel->links.tc3 = link; 1421 1422 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3)); 1423 1424 LIBBPF_OPTS_RESET(optl, 1425 .flags = BPF_F_AFTER, 1426 ); 1427 1428 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl); 1429 if (!ASSERT_OK_PTR(link, "link_attach")) 1430 goto cleanup; 1431 1432 skel->links.tc4 = link; 1433 1434 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4)); 1435 1436 assert_mprog_count(target, 4); 1437 1438 memset(prog_ids, 0, sizeof(prog_ids)); 1439 memset(link_ids, 0, sizeof(link_ids)); 1440 optq.count = ARRAY_SIZE(prog_ids); 1441 1442 err = bpf_prog_query_opts(loopback, target, &optq); 1443 if (!ASSERT_OK(err, "prog_query")) 1444 goto cleanup; 1445 1446 ASSERT_EQ(optq.count, 4, "count"); 1447 ASSERT_EQ(optq.revision, 5, "revision"); 1448 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]"); 1449 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]"); 1450 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]"); 1451 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]"); 1452 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]"); 1453 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]"); 1454 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]"); 1455 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]"); 1456 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]"); 1457 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]"); 1458 1459 tc_skel_reset_all_seen(skel); 1460 ASSERT_OK(system(ping_cmd), ping_cmd); 1461 1462 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1463 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1464 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3"); 1465 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1466 cleanup: 1467 test_tc_link__destroy(skel); 1468 assert_mprog_count(target, 0); 1469 } 1470 1471 void serial_test_tc_links_append(void) 1472 { 1473 test_tc_links_append_target(BPF_TCX_INGRESS); 1474 test_tc_links_append_target(BPF_TCX_EGRESS); 1475 } 1476 1477 static void test_tc_links_dev_cleanup_target(int target) 1478 { 1479 LIBBPF_OPTS(bpf_tcx_opts, optl); 1480 LIBBPF_OPTS(bpf_prog_query_opts, optq); 1481 __u32 pid1, pid2, pid3, pid4; 1482 struct test_tc_link *skel; 1483 struct bpf_link *link; 1484 int err, ifindex; 1485 1486 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth"); 1487 ifindex = if_nametoindex("tcx_opts1"); 1488 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex"); 1489 1490 skel = test_tc_link__open(); 1491 if (!ASSERT_OK_PTR(skel, "skel_open")) 1492 goto cleanup; 1493 1494 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1495 0, "tc1_attach_type"); 1496 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1497 0, "tc2_attach_type"); 1498 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1499 0, "tc3_attach_type"); 1500 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1501 0, "tc4_attach_type"); 1502 1503 err = test_tc_link__load(skel); 1504 if (!ASSERT_OK(err, "skel_load")) 1505 goto cleanup; 1506 1507 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1508 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1509 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1510 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1511 1512 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1513 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1514 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1515 1516 assert_mprog_count(target, 0); 1517 1518 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl); 1519 if (!ASSERT_OK_PTR(link, "link_attach")) 1520 goto cleanup; 1521 1522 skel->links.tc1 = link; 1523 1524 assert_mprog_count_ifindex(ifindex, target, 1); 1525 1526 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl); 1527 if (!ASSERT_OK_PTR(link, "link_attach")) 1528 goto cleanup; 1529 1530 skel->links.tc2 = link; 1531 1532 assert_mprog_count_ifindex(ifindex, target, 2); 1533 1534 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl); 1535 if (!ASSERT_OK_PTR(link, "link_attach")) 1536 goto cleanup; 1537 1538 skel->links.tc3 = link; 1539 1540 assert_mprog_count_ifindex(ifindex, target, 3); 1541 1542 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl); 1543 if (!ASSERT_OK_PTR(link, "link_attach")) 1544 goto cleanup; 1545 1546 skel->links.tc4 = link; 1547 1548 assert_mprog_count_ifindex(ifindex, target, 4); 1549 1550 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1551 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1552 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1553 1554 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex"); 1555 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex"); 1556 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex"); 1557 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex"); 1558 1559 test_tc_link__destroy(skel); 1560 return; 1561 cleanup: 1562 test_tc_link__destroy(skel); 1563 1564 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1565 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1566 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1567 } 1568 1569 void serial_test_tc_links_dev_cleanup(void) 1570 { 1571 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS); 1572 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS); 1573 } 1574 1575 static void test_tc_chain_mixed(int target) 1576 { 1577 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); 1578 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback); 1579 LIBBPF_OPTS(bpf_tcx_opts, optl); 1580 struct test_tc_link *skel; 1581 struct bpf_link *link; 1582 __u32 pid1, pid2, pid3; 1583 int err; 1584 1585 skel = test_tc_link__open(); 1586 if (!ASSERT_OK_PTR(skel, "skel_open")) 1587 goto cleanup; 1588 1589 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1590 0, "tc4_attach_type"); 1591 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target), 1592 0, "tc5_attach_type"); 1593 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target), 1594 0, "tc6_attach_type"); 1595 1596 err = test_tc_link__load(skel); 1597 if (!ASSERT_OK(err, "skel_load")) 1598 goto cleanup; 1599 1600 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1601 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5)); 1602 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6)); 1603 1604 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1605 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1606 1607 assert_mprog_count(target, 0); 1608 1609 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 1610 BPF_TC_INGRESS : BPF_TC_EGRESS; 1611 err = bpf_tc_hook_create(&tc_hook); 1612 err = err == -EEXIST ? 0 : err; 1613 if (!ASSERT_OK(err, "bpf_tc_hook_create")) 1614 goto cleanup; 1615 1616 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5); 1617 err = bpf_tc_attach(&tc_hook, &tc_opts); 1618 if (!ASSERT_OK(err, "bpf_tc_attach")) 1619 goto cleanup; 1620 1621 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl); 1622 if (!ASSERT_OK_PTR(link, "link_attach")) 1623 goto cleanup; 1624 1625 skel->links.tc6 = link; 1626 1627 assert_mprog_count(target, 1); 1628 1629 tc_skel_reset_all_seen(skel); 1630 ASSERT_OK(system(ping_cmd), ping_cmd); 1631 1632 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1633 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5"); 1634 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6"); 1635 1636 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4); 1637 if (!ASSERT_OK(err, "link_update")) 1638 goto cleanup; 1639 1640 assert_mprog_count(target, 1); 1641 1642 tc_skel_reset_all_seen(skel); 1643 ASSERT_OK(system(ping_cmd), ping_cmd); 1644 1645 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4"); 1646 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5"); 1647 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6"); 1648 1649 err = bpf_link__detach(skel->links.tc6); 1650 if (!ASSERT_OK(err, "prog_detach")) 1651 goto cleanup; 1652 1653 assert_mprog_count(target, 0); 1654 1655 tc_skel_reset_all_seen(skel); 1656 ASSERT_OK(system(ping_cmd), ping_cmd); 1657 1658 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4"); 1659 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5"); 1660 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6"); 1661 1662 cleanup: 1663 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0; 1664 err = bpf_tc_detach(&tc_hook, &tc_opts); 1665 ASSERT_OK(err, "bpf_tc_detach"); 1666 1667 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS; 1668 bpf_tc_hook_destroy(&tc_hook); 1669 1670 test_tc_link__destroy(skel); 1671 } 1672 1673 void serial_test_tc_links_chain_mixed(void) 1674 { 1675 test_tc_chain_mixed(BPF_TCX_INGRESS); 1676 test_tc_chain_mixed(BPF_TCX_EGRESS); 1677 } 1678 1679 static void test_tc_links_ingress(int target, bool chain_tc_old, 1680 bool tcx_teardown_first) 1681 { 1682 LIBBPF_OPTS(bpf_tc_opts, tc_opts, 1683 .handle = 1, 1684 .priority = 1, 1685 ); 1686 LIBBPF_OPTS(bpf_tc_hook, tc_hook, 1687 .ifindex = loopback, 1688 .attach_point = BPF_TC_CUSTOM, 1689 .parent = TC_H_INGRESS, 1690 ); 1691 bool hook_created = false, tc_attached = false; 1692 LIBBPF_OPTS(bpf_tcx_opts, optl); 1693 __u32 pid1, pid2, pid3; 1694 struct test_tc_link *skel; 1695 struct bpf_link *link; 1696 int err; 1697 1698 skel = test_tc_link__open(); 1699 if (!ASSERT_OK_PTR(skel, "skel_open")) 1700 goto cleanup; 1701 1702 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1703 0, "tc1_attach_type"); 1704 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1705 0, "tc2_attach_type"); 1706 1707 err = test_tc_link__load(skel); 1708 if (!ASSERT_OK(err, "skel_load")) 1709 goto cleanup; 1710 1711 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1712 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1713 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1714 1715 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1716 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1717 1718 assert_mprog_count(target, 0); 1719 1720 if (chain_tc_old) { 1721 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress"); 1722 hook_created = true; 1723 1724 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3); 1725 err = bpf_tc_attach(&tc_hook, &tc_opts); 1726 if (!ASSERT_OK(err, "bpf_tc_attach")) 1727 goto cleanup; 1728 tc_attached = true; 1729 } 1730 1731 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl); 1732 if (!ASSERT_OK_PTR(link, "link_attach")) 1733 goto cleanup; 1734 1735 skel->links.tc1 = link; 1736 1737 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl); 1738 if (!ASSERT_OK_PTR(link, "link_attach")) 1739 goto cleanup; 1740 1741 skel->links.tc2 = link; 1742 1743 assert_mprog_count(target, 2); 1744 1745 tc_skel_reset_all_seen(skel); 1746 ASSERT_OK(system(ping_cmd), ping_cmd); 1747 1748 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1749 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2"); 1750 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 1751 1752 err = bpf_link__detach(skel->links.tc2); 1753 if (!ASSERT_OK(err, "prog_detach")) 1754 goto cleanup; 1755 1756 assert_mprog_count(target, 1); 1757 1758 tc_skel_reset_all_seen(skel); 1759 ASSERT_OK(system(ping_cmd), ping_cmd); 1760 1761 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1"); 1762 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2"); 1763 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3"); 1764 cleanup: 1765 if (tc_attached) { 1766 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0; 1767 err = bpf_tc_detach(&tc_hook, &tc_opts); 1768 ASSERT_OK(err, "bpf_tc_detach"); 1769 } 1770 ASSERT_OK(system(ping_cmd), ping_cmd); 1771 assert_mprog_count(target, 1); 1772 if (hook_created && tcx_teardown_first) 1773 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress"); 1774 ASSERT_OK(system(ping_cmd), ping_cmd); 1775 test_tc_link__destroy(skel); 1776 ASSERT_OK(system(ping_cmd), ping_cmd); 1777 if (hook_created && !tcx_teardown_first) 1778 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress"); 1779 ASSERT_OK(system(ping_cmd), ping_cmd); 1780 assert_mprog_count(target, 0); 1781 } 1782 1783 void serial_test_tc_links_ingress(void) 1784 { 1785 test_tc_links_ingress(BPF_TCX_INGRESS, true, true); 1786 test_tc_links_ingress(BPF_TCX_INGRESS, true, false); 1787 test_tc_links_ingress(BPF_TCX_INGRESS, false, false); 1788 } 1789 1790 static void test_tc_links_dev_mixed(int target) 1791 { 1792 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); 1793 LIBBPF_OPTS(bpf_tc_hook, tc_hook); 1794 LIBBPF_OPTS(bpf_tcx_opts, optl); 1795 __u32 pid1, pid2, pid3, pid4; 1796 struct test_tc_link *skel; 1797 struct bpf_link *link; 1798 int err, ifindex; 1799 1800 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth"); 1801 ifindex = if_nametoindex("tcx_opts1"); 1802 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex"); 1803 1804 skel = test_tc_link__open(); 1805 if (!ASSERT_OK_PTR(skel, "skel_open")) 1806 goto cleanup; 1807 1808 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target), 1809 0, "tc1_attach_type"); 1810 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target), 1811 0, "tc2_attach_type"); 1812 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target), 1813 0, "tc3_attach_type"); 1814 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target), 1815 0, "tc4_attach_type"); 1816 1817 err = test_tc_link__load(skel); 1818 if (!ASSERT_OK(err, "skel_load")) 1819 goto cleanup; 1820 1821 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1)); 1822 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2)); 1823 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3)); 1824 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4)); 1825 1826 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2"); 1827 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4"); 1828 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3"); 1829 1830 assert_mprog_count(target, 0); 1831 1832 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl); 1833 if (!ASSERT_OK_PTR(link, "link_attach")) 1834 goto cleanup; 1835 1836 skel->links.tc1 = link; 1837 1838 assert_mprog_count_ifindex(ifindex, target, 1); 1839 1840 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl); 1841 if (!ASSERT_OK_PTR(link, "link_attach")) 1842 goto cleanup; 1843 1844 skel->links.tc2 = link; 1845 1846 assert_mprog_count_ifindex(ifindex, target, 2); 1847 1848 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl); 1849 if (!ASSERT_OK_PTR(link, "link_attach")) 1850 goto cleanup; 1851 1852 skel->links.tc3 = link; 1853 1854 assert_mprog_count_ifindex(ifindex, target, 3); 1855 1856 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl); 1857 if (!ASSERT_OK_PTR(link, "link_attach")) 1858 goto cleanup; 1859 1860 skel->links.tc4 = link; 1861 1862 assert_mprog_count_ifindex(ifindex, target, 4); 1863 1864 tc_hook.ifindex = ifindex; 1865 tc_hook.attach_point = target == BPF_TCX_INGRESS ? 1866 BPF_TC_INGRESS : BPF_TC_EGRESS; 1867 1868 err = bpf_tc_hook_create(&tc_hook); 1869 err = err == -EEXIST ? 0 : err; 1870 if (!ASSERT_OK(err, "bpf_tc_hook_create")) 1871 goto cleanup; 1872 1873 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5); 1874 err = bpf_tc_attach(&tc_hook, &tc_opts); 1875 if (!ASSERT_OK(err, "bpf_tc_attach")) 1876 goto cleanup; 1877 1878 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1879 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1880 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1881 1882 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex"); 1883 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex"); 1884 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex"); 1885 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex"); 1886 1887 test_tc_link__destroy(skel); 1888 return; 1889 cleanup: 1890 test_tc_link__destroy(skel); 1891 1892 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth"); 1893 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed"); 1894 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed"); 1895 } 1896 1897 void serial_test_tc_links_dev_mixed(void) 1898 { 1899 test_tc_links_dev_mixed(BPF_TCX_INGRESS); 1900 test_tc_links_dev_mixed(BPF_TCX_EGRESS); 1901 } 1902