1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Isovalent */
3 #include <uapi/linux/if_link.h>
5 #include <test_progs.h>
8 #define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"
10 #include "test_tc_link.skel.h"
11 #include "tc_helpers.h"
13 void serial_test_tc_opts_basic(void)
15 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
16 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
17 LIBBPF_OPTS(bpf_prog_query_opts, optq);
18 __u32 fd1, fd2, id1, id2;
19 struct test_tc_link *skel;
23 skel = test_tc_link__open_and_load();
24 if (!ASSERT_OK_PTR(skel, "skel_load"))
27 fd1 = bpf_program__fd(skel->progs.tc1);
28 fd2 = bpf_program__fd(skel->progs.tc2);
30 id1 = id_from_prog_fd(fd1);
31 id2 = id_from_prog_fd(fd2);
33 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
35 assert_mprog_count(BPF_TCX_INGRESS, 0);
36 assert_mprog_count(BPF_TCX_EGRESS, 0);
38 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
39 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
41 err = bpf_prog_attach_opts(fd1, loopback, BPF_TCX_INGRESS, &opta);
42 if (!ASSERT_EQ(err, 0, "prog_attach"))
45 assert_mprog_count(BPF_TCX_INGRESS, 1);
46 assert_mprog_count(BPF_TCX_EGRESS, 0);
48 optq.prog_ids = prog_ids;
50 memset(prog_ids, 0, sizeof(prog_ids));
51 optq.count = ARRAY_SIZE(prog_ids);
53 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);
54 if (!ASSERT_OK(err, "prog_query"))
57 ASSERT_EQ(optq.count, 1, "count");
58 ASSERT_EQ(optq.revision, 2, "revision");
59 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
60 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
62 tc_skel_reset_all_seen(skel);
63 ASSERT_OK(system(ping_cmd), ping_cmd);
65 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
66 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
68 err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta);
69 if (!ASSERT_EQ(err, 0, "prog_attach"))
72 assert_mprog_count(BPF_TCX_INGRESS, 1);
73 assert_mprog_count(BPF_TCX_EGRESS, 1);
75 memset(prog_ids, 0, sizeof(prog_ids));
76 optq.count = ARRAY_SIZE(prog_ids);
78 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
79 if (!ASSERT_OK(err, "prog_query"))
82 ASSERT_EQ(optq.count, 1, "count");
83 ASSERT_EQ(optq.revision, 2, "revision");
84 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
85 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
87 tc_skel_reset_all_seen(skel);
88 ASSERT_OK(system(ping_cmd), ping_cmd);
90 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
91 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
94 err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd);
95 ASSERT_OK(err, "prog_detach_eg");
97 assert_mprog_count(BPF_TCX_INGRESS, 1);
98 assert_mprog_count(BPF_TCX_EGRESS, 0);
101 err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd);
102 ASSERT_OK(err, "prog_detach_in");
104 assert_mprog_count(BPF_TCX_INGRESS, 0);
105 assert_mprog_count(BPF_TCX_EGRESS, 0);
108 test_tc_link__destroy(skel);
111 static void test_tc_opts_before_target(int target)
113 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
114 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
115 LIBBPF_OPTS(bpf_prog_query_opts, optq);
116 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
117 struct test_tc_link *skel;
121 skel = test_tc_link__open_and_load();
122 if (!ASSERT_OK_PTR(skel, "skel_load"))
125 fd1 = bpf_program__fd(skel->progs.tc1);
126 fd2 = bpf_program__fd(skel->progs.tc2);
127 fd3 = bpf_program__fd(skel->progs.tc3);
128 fd4 = bpf_program__fd(skel->progs.tc4);
130 id1 = id_from_prog_fd(fd1);
131 id2 = id_from_prog_fd(fd2);
132 id3 = id_from_prog_fd(fd3);
133 id4 = id_from_prog_fd(fd4);
135 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
136 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
137 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
139 assert_mprog_count(target, 0);
141 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
142 if (!ASSERT_EQ(err, 0, "prog_attach"))
145 assert_mprog_count(target, 1);
147 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
148 if (!ASSERT_EQ(err, 0, "prog_attach"))
151 assert_mprog_count(target, 2);
153 optq.prog_ids = prog_ids;
155 memset(prog_ids, 0, sizeof(prog_ids));
156 optq.count = ARRAY_SIZE(prog_ids);
158 err = bpf_prog_query_opts(loopback, target, &optq);
159 if (!ASSERT_OK(err, "prog_query"))
160 goto cleanup_target2;
162 ASSERT_EQ(optq.count, 2, "count");
163 ASSERT_EQ(optq.revision, 3, "revision");
164 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
165 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
166 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
168 tc_skel_reset_all_seen(skel);
169 ASSERT_OK(system(ping_cmd), ping_cmd);
171 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
172 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
173 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
174 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
176 LIBBPF_OPTS_RESET(opta,
177 .flags = BPF_F_BEFORE,
181 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
182 if (!ASSERT_EQ(err, 0, "prog_attach"))
183 goto cleanup_target2;
185 memset(prog_ids, 0, sizeof(prog_ids));
186 optq.count = ARRAY_SIZE(prog_ids);
188 err = bpf_prog_query_opts(loopback, target, &optq);
189 if (!ASSERT_OK(err, "prog_query"))
190 goto cleanup_target3;
192 ASSERT_EQ(optq.count, 3, "count");
193 ASSERT_EQ(optq.revision, 4, "revision");
194 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
195 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
196 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
197 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
199 LIBBPF_OPTS_RESET(opta,
200 .flags = BPF_F_BEFORE,
204 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
205 if (!ASSERT_EQ(err, 0, "prog_attach"))
206 goto cleanup_target3;
208 assert_mprog_count(target, 4);
210 memset(prog_ids, 0, sizeof(prog_ids));
211 optq.count = ARRAY_SIZE(prog_ids);
213 err = bpf_prog_query_opts(loopback, target, &optq);
214 if (!ASSERT_OK(err, "prog_query"))
215 goto cleanup_target4;
217 ASSERT_EQ(optq.count, 4, "count");
218 ASSERT_EQ(optq.revision, 5, "revision");
219 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
220 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
221 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
222 ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");
223 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
225 tc_skel_reset_all_seen(skel);
226 ASSERT_OK(system(ping_cmd), ping_cmd);
228 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
229 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
230 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
231 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
234 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
235 ASSERT_OK(err, "prog_detach");
236 assert_mprog_count(target, 3);
239 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
240 ASSERT_OK(err, "prog_detach");
241 assert_mprog_count(target, 2);
244 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
245 ASSERT_OK(err, "prog_detach");
246 assert_mprog_count(target, 1);
249 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
250 ASSERT_OK(err, "prog_detach");
251 assert_mprog_count(target, 0);
254 test_tc_link__destroy(skel);
257 void serial_test_tc_opts_before(void)
259 test_tc_opts_before_target(BPF_TCX_INGRESS);
260 test_tc_opts_before_target(BPF_TCX_EGRESS);
263 static void test_tc_opts_after_target(int target)
265 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
266 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
267 LIBBPF_OPTS(bpf_prog_query_opts, optq);
268 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
269 struct test_tc_link *skel;
273 skel = test_tc_link__open_and_load();
274 if (!ASSERT_OK_PTR(skel, "skel_load"))
277 fd1 = bpf_program__fd(skel->progs.tc1);
278 fd2 = bpf_program__fd(skel->progs.tc2);
279 fd3 = bpf_program__fd(skel->progs.tc3);
280 fd4 = bpf_program__fd(skel->progs.tc4);
282 id1 = id_from_prog_fd(fd1);
283 id2 = id_from_prog_fd(fd2);
284 id3 = id_from_prog_fd(fd3);
285 id4 = id_from_prog_fd(fd4);
287 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
288 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
289 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
291 assert_mprog_count(target, 0);
293 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
294 if (!ASSERT_EQ(err, 0, "prog_attach"))
297 assert_mprog_count(target, 1);
299 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
300 if (!ASSERT_EQ(err, 0, "prog_attach"))
303 assert_mprog_count(target, 2);
305 optq.prog_ids = prog_ids;
307 memset(prog_ids, 0, sizeof(prog_ids));
308 optq.count = ARRAY_SIZE(prog_ids);
310 err = bpf_prog_query_opts(loopback, target, &optq);
311 if (!ASSERT_OK(err, "prog_query"))
312 goto cleanup_target2;
314 ASSERT_EQ(optq.count, 2, "count");
315 ASSERT_EQ(optq.revision, 3, "revision");
316 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
317 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
318 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
320 tc_skel_reset_all_seen(skel);
321 ASSERT_OK(system(ping_cmd), ping_cmd);
323 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
324 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
325 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
326 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
328 LIBBPF_OPTS_RESET(opta,
329 .flags = BPF_F_AFTER,
333 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
334 if (!ASSERT_EQ(err, 0, "prog_attach"))
335 goto cleanup_target2;
337 memset(prog_ids, 0, sizeof(prog_ids));
338 optq.count = ARRAY_SIZE(prog_ids);
340 err = bpf_prog_query_opts(loopback, target, &optq);
341 if (!ASSERT_OK(err, "prog_query"))
342 goto cleanup_target3;
344 ASSERT_EQ(optq.count, 3, "count");
345 ASSERT_EQ(optq.revision, 4, "revision");
346 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
347 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
348 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
349 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
351 LIBBPF_OPTS_RESET(opta,
352 .flags = BPF_F_AFTER,
356 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
357 if (!ASSERT_EQ(err, 0, "prog_attach"))
358 goto cleanup_target3;
360 assert_mprog_count(target, 4);
362 memset(prog_ids, 0, sizeof(prog_ids));
363 optq.count = ARRAY_SIZE(prog_ids);
365 err = bpf_prog_query_opts(loopback, target, &optq);
366 if (!ASSERT_OK(err, "prog_query"))
367 goto cleanup_target4;
369 ASSERT_EQ(optq.count, 4, "count");
370 ASSERT_EQ(optq.revision, 5, "revision");
371 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
372 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
373 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
374 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
375 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
377 tc_skel_reset_all_seen(skel);
378 ASSERT_OK(system(ping_cmd), ping_cmd);
380 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
381 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
382 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
383 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
386 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
387 ASSERT_OK(err, "prog_detach");
388 assert_mprog_count(target, 3);
390 memset(prog_ids, 0, sizeof(prog_ids));
391 optq.count = ARRAY_SIZE(prog_ids);
393 err = bpf_prog_query_opts(loopback, target, &optq);
394 if (!ASSERT_OK(err, "prog_query"))
395 goto cleanup_target3;
397 ASSERT_EQ(optq.count, 3, "count");
398 ASSERT_EQ(optq.revision, 6, "revision");
399 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
400 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
401 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
402 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
405 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
406 ASSERT_OK(err, "prog_detach");
407 assert_mprog_count(target, 2);
409 memset(prog_ids, 0, sizeof(prog_ids));
410 optq.count = ARRAY_SIZE(prog_ids);
412 err = bpf_prog_query_opts(loopback, target, &optq);
413 if (!ASSERT_OK(err, "prog_query"))
414 goto cleanup_target2;
416 ASSERT_EQ(optq.count, 2, "count");
417 ASSERT_EQ(optq.revision, 7, "revision");
418 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
419 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
420 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
423 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
424 ASSERT_OK(err, "prog_detach");
425 assert_mprog_count(target, 1);
427 memset(prog_ids, 0, sizeof(prog_ids));
428 optq.count = ARRAY_SIZE(prog_ids);
430 err = bpf_prog_query_opts(loopback, target, &optq);
431 if (!ASSERT_OK(err, "prog_query"))
434 ASSERT_EQ(optq.count, 1, "count");
435 ASSERT_EQ(optq.revision, 8, "revision");
436 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
437 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
440 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
441 ASSERT_OK(err, "prog_detach");
442 assert_mprog_count(target, 0);
445 test_tc_link__destroy(skel);
448 void serial_test_tc_opts_after(void)
450 test_tc_opts_after_target(BPF_TCX_INGRESS);
451 test_tc_opts_after_target(BPF_TCX_EGRESS);
454 static void test_tc_opts_revision_target(int target)
456 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
457 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
458 LIBBPF_OPTS(bpf_prog_query_opts, optq);
459 __u32 fd1, fd2, id1, id2;
460 struct test_tc_link *skel;
464 skel = test_tc_link__open_and_load();
465 if (!ASSERT_OK_PTR(skel, "skel_load"))
468 fd1 = bpf_program__fd(skel->progs.tc1);
469 fd2 = bpf_program__fd(skel->progs.tc2);
471 id1 = id_from_prog_fd(fd1);
472 id2 = id_from_prog_fd(fd2);
474 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
476 assert_mprog_count(target, 0);
478 LIBBPF_OPTS_RESET(opta,
479 .expected_revision = 1,
482 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
483 if (!ASSERT_EQ(err, 0, "prog_attach"))
486 assert_mprog_count(target, 1);
488 LIBBPF_OPTS_RESET(opta,
489 .expected_revision = 1,
492 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
493 if (!ASSERT_EQ(err, -ESTALE, "prog_attach"))
496 assert_mprog_count(target, 1);
498 LIBBPF_OPTS_RESET(opta,
499 .expected_revision = 2,
502 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
503 if (!ASSERT_EQ(err, 0, "prog_attach"))
506 assert_mprog_count(target, 2);
508 optq.prog_ids = prog_ids;
510 memset(prog_ids, 0, sizeof(prog_ids));
511 optq.count = ARRAY_SIZE(prog_ids);
513 err = bpf_prog_query_opts(loopback, target, &optq);
514 if (!ASSERT_OK(err, "prog_query"))
515 goto cleanup_target2;
517 ASSERT_EQ(optq.count, 2, "count");
518 ASSERT_EQ(optq.revision, 3, "revision");
519 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
520 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
521 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
523 tc_skel_reset_all_seen(skel);
524 ASSERT_OK(system(ping_cmd), ping_cmd);
526 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
527 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
529 LIBBPF_OPTS_RESET(optd,
530 .expected_revision = 2,
533 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
534 ASSERT_EQ(err, -ESTALE, "prog_detach");
535 assert_mprog_count(target, 2);
538 LIBBPF_OPTS_RESET(optd,
539 .expected_revision = 3,
542 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
543 ASSERT_OK(err, "prog_detach");
544 assert_mprog_count(target, 1);
547 LIBBPF_OPTS_RESET(optd);
549 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
550 ASSERT_OK(err, "prog_detach");
551 assert_mprog_count(target, 0);
554 test_tc_link__destroy(skel);
557 void serial_test_tc_opts_revision(void)
559 test_tc_opts_revision_target(BPF_TCX_INGRESS);
560 test_tc_opts_revision_target(BPF_TCX_EGRESS);
563 static void test_tc_chain_classic(int target, bool chain_tc_old)
565 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
566 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
567 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
568 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
569 bool hook_created = false, tc_attached = false;
570 __u32 fd1, fd2, fd3, id1, id2, id3;
571 struct test_tc_link *skel;
574 skel = test_tc_link__open_and_load();
575 if (!ASSERT_OK_PTR(skel, "skel_load"))
578 fd1 = bpf_program__fd(skel->progs.tc1);
579 fd2 = bpf_program__fd(skel->progs.tc2);
580 fd3 = bpf_program__fd(skel->progs.tc3);
582 id1 = id_from_prog_fd(fd1);
583 id2 = id_from_prog_fd(fd2);
584 id3 = id_from_prog_fd(fd3);
586 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
587 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
589 assert_mprog_count(target, 0);
592 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
593 BPF_TC_INGRESS : BPF_TC_EGRESS;
594 err = bpf_tc_hook_create(&tc_hook);
597 err = err == -EEXIST ? 0 : err;
598 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
601 tc_opts.prog_fd = fd3;
602 err = bpf_tc_attach(&tc_hook, &tc_opts);
603 if (!ASSERT_OK(err, "bpf_tc_attach"))
608 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
609 if (!ASSERT_EQ(err, 0, "prog_attach"))
612 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
613 if (!ASSERT_EQ(err, 0, "prog_attach"))
616 assert_mprog_count(target, 2);
618 tc_skel_reset_all_seen(skel);
619 ASSERT_OK(system(ping_cmd), ping_cmd);
621 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
622 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
623 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
625 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
626 if (!ASSERT_OK(err, "prog_detach"))
629 assert_mprog_count(target, 1);
631 tc_skel_reset_all_seen(skel);
632 ASSERT_OK(system(ping_cmd), ping_cmd);
634 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
635 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
636 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
639 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
640 if (!ASSERT_OK(err, "prog_detach"))
643 assert_mprog_count(target, 0);
646 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
647 err = bpf_tc_detach(&tc_hook, &tc_opts);
648 ASSERT_OK(err, "bpf_tc_detach");
651 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
652 bpf_tc_hook_destroy(&tc_hook);
654 test_tc_link__destroy(skel);
655 assert_mprog_count(target, 0);
658 void serial_test_tc_opts_chain_classic(void)
660 test_tc_chain_classic(BPF_TCX_INGRESS, false);
661 test_tc_chain_classic(BPF_TCX_EGRESS, false);
662 test_tc_chain_classic(BPF_TCX_INGRESS, true);
663 test_tc_chain_classic(BPF_TCX_EGRESS, true);
666 static void test_tc_opts_replace_target(int target)
668 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
669 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
670 LIBBPF_OPTS(bpf_prog_query_opts, optq);
671 __u32 fd1, fd2, fd3, id1, id2, id3, detach_fd;
672 __u32 prog_ids[4], prog_flags[4];
673 struct test_tc_link *skel;
676 skel = test_tc_link__open_and_load();
677 if (!ASSERT_OK_PTR(skel, "skel_load"))
680 fd1 = bpf_program__fd(skel->progs.tc1);
681 fd2 = bpf_program__fd(skel->progs.tc2);
682 fd3 = bpf_program__fd(skel->progs.tc3);
684 id1 = id_from_prog_fd(fd1);
685 id2 = id_from_prog_fd(fd2);
686 id3 = id_from_prog_fd(fd3);
688 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
689 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
691 assert_mprog_count(target, 0);
693 LIBBPF_OPTS_RESET(opta,
694 .expected_revision = 1,
697 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
698 if (!ASSERT_EQ(err, 0, "prog_attach"))
701 assert_mprog_count(target, 1);
703 LIBBPF_OPTS_RESET(opta,
704 .flags = BPF_F_BEFORE,
706 .expected_revision = 2,
709 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
710 if (!ASSERT_EQ(err, 0, "prog_attach"))
715 assert_mprog_count(target, 2);
717 optq.prog_attach_flags = prog_flags;
718 optq.prog_ids = prog_ids;
720 memset(prog_flags, 0, sizeof(prog_flags));
721 memset(prog_ids, 0, sizeof(prog_ids));
722 optq.count = ARRAY_SIZE(prog_ids);
724 err = bpf_prog_query_opts(loopback, target, &optq);
725 if (!ASSERT_OK(err, "prog_query"))
726 goto cleanup_target2;
728 ASSERT_EQ(optq.count, 2, "count");
729 ASSERT_EQ(optq.revision, 3, "revision");
730 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
731 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
732 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
734 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
735 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
736 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
738 tc_skel_reset_all_seen(skel);
739 ASSERT_OK(system(ping_cmd), ping_cmd);
741 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
742 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
743 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
745 LIBBPF_OPTS_RESET(opta,
746 .flags = BPF_F_REPLACE,
747 .replace_prog_fd = fd2,
748 .expected_revision = 3,
751 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
752 if (!ASSERT_EQ(err, 0, "prog_attach"))
753 goto cleanup_target2;
757 assert_mprog_count(target, 2);
759 memset(prog_ids, 0, sizeof(prog_ids));
760 optq.count = ARRAY_SIZE(prog_ids);
762 err = bpf_prog_query_opts(loopback, target, &optq);
763 if (!ASSERT_OK(err, "prog_query"))
764 goto cleanup_target2;
766 ASSERT_EQ(optq.count, 2, "count");
767 ASSERT_EQ(optq.revision, 4, "revision");
768 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
769 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
770 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
772 tc_skel_reset_all_seen(skel);
773 ASSERT_OK(system(ping_cmd), ping_cmd);
775 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
776 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
777 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
779 LIBBPF_OPTS_RESET(opta,
780 .flags = BPF_F_REPLACE | BPF_F_BEFORE,
781 .replace_prog_fd = fd3,
783 .expected_revision = 4,
786 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
787 if (!ASSERT_EQ(err, 0, "prog_attach"))
788 goto cleanup_target2;
792 assert_mprog_count(target, 2);
794 memset(prog_ids, 0, sizeof(prog_ids));
795 optq.count = ARRAY_SIZE(prog_ids);
797 err = bpf_prog_query_opts(loopback, target, &optq);
798 if (!ASSERT_OK(err, "prog_query"))
799 goto cleanup_target2;
801 ASSERT_EQ(optq.count, 2, "count");
802 ASSERT_EQ(optq.revision, 5, "revision");
803 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
804 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
805 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
807 tc_skel_reset_all_seen(skel);
808 ASSERT_OK(system(ping_cmd), ping_cmd);
810 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
811 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
812 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
814 LIBBPF_OPTS_RESET(opta,
815 .flags = BPF_F_REPLACE,
816 .replace_prog_fd = fd2,
819 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
820 ASSERT_EQ(err, -EEXIST, "prog_attach");
821 assert_mprog_count(target, 2);
823 LIBBPF_OPTS_RESET(opta,
824 .flags = BPF_F_REPLACE | BPF_F_AFTER,
825 .replace_prog_fd = fd2,
827 .expected_revision = 5,
830 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
831 ASSERT_EQ(err, -ERANGE, "prog_attach");
832 assert_mprog_count(target, 2);
834 LIBBPF_OPTS_RESET(opta,
835 .flags = BPF_F_BEFORE | BPF_F_AFTER | BPF_F_REPLACE,
836 .replace_prog_fd = fd2,
838 .expected_revision = 5,
841 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
842 ASSERT_EQ(err, -ERANGE, "prog_attach");
843 assert_mprog_count(target, 2);
845 LIBBPF_OPTS_RESET(optd,
846 .flags = BPF_F_BEFORE,
848 .expected_revision = 5,
852 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
853 ASSERT_OK(err, "prog_detach");
854 assert_mprog_count(target, 1);
857 LIBBPF_OPTS_RESET(optd);
859 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
860 ASSERT_OK(err, "prog_detach");
861 assert_mprog_count(target, 0);
864 test_tc_link__destroy(skel);
867 void serial_test_tc_opts_replace(void)
869 test_tc_opts_replace_target(BPF_TCX_INGRESS);
870 test_tc_opts_replace_target(BPF_TCX_EGRESS);
873 static void test_tc_opts_invalid_target(int target)
875 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
876 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
877 __u32 fd1, fd2, id1, id2;
878 struct test_tc_link *skel;
881 skel = test_tc_link__open_and_load();
882 if (!ASSERT_OK_PTR(skel, "skel_load"))
885 fd1 = bpf_program__fd(skel->progs.tc1);
886 fd2 = bpf_program__fd(skel->progs.tc2);
888 id1 = id_from_prog_fd(fd1);
889 id2 = id_from_prog_fd(fd2);
891 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
893 assert_mprog_count(target, 0);
895 LIBBPF_OPTS_RESET(opta,
896 .flags = BPF_F_BEFORE | BPF_F_AFTER,
899 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
900 ASSERT_EQ(err, -ERANGE, "prog_attach");
901 assert_mprog_count(target, 0);
903 LIBBPF_OPTS_RESET(opta,
904 .flags = BPF_F_BEFORE | BPF_F_ID,
907 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
908 ASSERT_EQ(err, -ENOENT, "prog_attach");
909 assert_mprog_count(target, 0);
911 LIBBPF_OPTS_RESET(opta,
912 .flags = BPF_F_AFTER | BPF_F_ID,
915 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
916 ASSERT_EQ(err, -ENOENT, "prog_attach");
917 assert_mprog_count(target, 0);
919 LIBBPF_OPTS_RESET(opta,
923 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
924 ASSERT_EQ(err, -EINVAL, "prog_attach");
925 assert_mprog_count(target, 0);
927 LIBBPF_OPTS_RESET(opta,
928 .flags = BPF_F_BEFORE | BPF_F_AFTER,
932 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
933 ASSERT_EQ(err, -ENOENT, "prog_attach");
934 assert_mprog_count(target, 0);
936 LIBBPF_OPTS_RESET(opta,
941 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
942 ASSERT_EQ(err, -EINVAL, "prog_attach");
943 assert_mprog_count(target, 0);
945 LIBBPF_OPTS_RESET(opta,
946 .flags = BPF_F_BEFORE,
950 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
951 ASSERT_EQ(err, -ENOENT, "prog_attach");
952 assert_mprog_count(target, 0);
954 LIBBPF_OPTS_RESET(opta,
955 .flags = BPF_F_AFTER,
959 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
960 ASSERT_EQ(err, -ENOENT, "prog_attach");
961 assert_mprog_count(target, 0);
963 LIBBPF_OPTS_RESET(opta);
965 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
966 if (!ASSERT_EQ(err, 0, "prog_attach"))
969 assert_mprog_count(target, 1);
971 LIBBPF_OPTS_RESET(opta);
973 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
974 ASSERT_EQ(err, -EEXIST, "prog_attach");
975 assert_mprog_count(target, 1);
977 LIBBPF_OPTS_RESET(opta,
978 .flags = BPF_F_BEFORE,
982 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
983 ASSERT_EQ(err, -EEXIST, "prog_attach");
984 assert_mprog_count(target, 1);
986 LIBBPF_OPTS_RESET(opta,
987 .flags = BPF_F_AFTER,
991 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
992 ASSERT_EQ(err, -EEXIST, "prog_attach");
993 assert_mprog_count(target, 1);
995 LIBBPF_OPTS_RESET(opta,
996 .flags = BPF_F_REPLACE,
1000 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1001 ASSERT_EQ(err, -EINVAL, "prog_attach_x1");
1002 assert_mprog_count(target, 1);
1004 LIBBPF_OPTS_RESET(opta,
1005 .flags = BPF_F_REPLACE,
1006 .replace_prog_fd = fd1,
1009 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1010 ASSERT_EQ(err, -EEXIST, "prog_attach");
1011 assert_mprog_count(target, 1);
1013 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1014 ASSERT_OK(err, "prog_detach");
1015 assert_mprog_count(target, 0);
1017 test_tc_link__destroy(skel);
1020 void serial_test_tc_opts_invalid(void)
1022 test_tc_opts_invalid_target(BPF_TCX_INGRESS);
1023 test_tc_opts_invalid_target(BPF_TCX_EGRESS);
1026 static void test_tc_opts_prepend_target(int target)
1028 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1029 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1030 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1031 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1032 struct test_tc_link *skel;
1036 skel = test_tc_link__open_and_load();
1037 if (!ASSERT_OK_PTR(skel, "skel_load"))
1040 fd1 = bpf_program__fd(skel->progs.tc1);
1041 fd2 = bpf_program__fd(skel->progs.tc2);
1042 fd3 = bpf_program__fd(skel->progs.tc3);
1043 fd4 = bpf_program__fd(skel->progs.tc4);
1045 id1 = id_from_prog_fd(fd1);
1046 id2 = id_from_prog_fd(fd2);
1047 id3 = id_from_prog_fd(fd3);
1048 id4 = id_from_prog_fd(fd4);
1050 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1051 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1052 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1054 assert_mprog_count(target, 0);
1056 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1057 if (!ASSERT_EQ(err, 0, "prog_attach"))
1060 assert_mprog_count(target, 1);
1062 LIBBPF_OPTS_RESET(opta,
1063 .flags = BPF_F_BEFORE,
1066 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1067 if (!ASSERT_EQ(err, 0, "prog_attach"))
1068 goto cleanup_target;
1070 assert_mprog_count(target, 2);
1072 optq.prog_ids = prog_ids;
1074 memset(prog_ids, 0, sizeof(prog_ids));
1075 optq.count = ARRAY_SIZE(prog_ids);
1077 err = bpf_prog_query_opts(loopback, target, &optq);
1078 if (!ASSERT_OK(err, "prog_query"))
1079 goto cleanup_target2;
1081 ASSERT_EQ(optq.count, 2, "count");
1082 ASSERT_EQ(optq.revision, 3, "revision");
1083 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1084 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
1085 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1087 tc_skel_reset_all_seen(skel);
1088 ASSERT_OK(system(ping_cmd), ping_cmd);
1090 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1091 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1092 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1093 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1095 LIBBPF_OPTS_RESET(opta,
1096 .flags = BPF_F_BEFORE,
1099 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1100 if (!ASSERT_EQ(err, 0, "prog_attach"))
1101 goto cleanup_target2;
1103 LIBBPF_OPTS_RESET(opta,
1104 .flags = BPF_F_BEFORE,
1107 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1108 if (!ASSERT_EQ(err, 0, "prog_attach"))
1109 goto cleanup_target3;
1111 assert_mprog_count(target, 4);
1113 memset(prog_ids, 0, sizeof(prog_ids));
1114 optq.count = ARRAY_SIZE(prog_ids);
1116 err = bpf_prog_query_opts(loopback, target, &optq);
1117 if (!ASSERT_OK(err, "prog_query"))
1118 goto cleanup_target4;
1120 ASSERT_EQ(optq.count, 4, "count");
1121 ASSERT_EQ(optq.revision, 5, "revision");
1122 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1123 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1124 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
1125 ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");
1126 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1128 tc_skel_reset_all_seen(skel);
1129 ASSERT_OK(system(ping_cmd), ping_cmd);
1131 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1132 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1133 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1134 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1137 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1138 ASSERT_OK(err, "prog_detach");
1139 assert_mprog_count(target, 3);
1142 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1143 ASSERT_OK(err, "prog_detach");
1144 assert_mprog_count(target, 2);
1147 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1148 ASSERT_OK(err, "prog_detach");
1149 assert_mprog_count(target, 1);
1152 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1153 ASSERT_OK(err, "prog_detach");
1154 assert_mprog_count(target, 0);
1157 test_tc_link__destroy(skel);
1160 void serial_test_tc_opts_prepend(void)
1162 test_tc_opts_prepend_target(BPF_TCX_INGRESS);
1163 test_tc_opts_prepend_target(BPF_TCX_EGRESS);
1166 static void test_tc_opts_append_target(int target)
1168 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1169 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1170 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1171 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1172 struct test_tc_link *skel;
1176 skel = test_tc_link__open_and_load();
1177 if (!ASSERT_OK_PTR(skel, "skel_load"))
1180 fd1 = bpf_program__fd(skel->progs.tc1);
1181 fd2 = bpf_program__fd(skel->progs.tc2);
1182 fd3 = bpf_program__fd(skel->progs.tc3);
1183 fd4 = bpf_program__fd(skel->progs.tc4);
1185 id1 = id_from_prog_fd(fd1);
1186 id2 = id_from_prog_fd(fd2);
1187 id3 = id_from_prog_fd(fd3);
1188 id4 = id_from_prog_fd(fd4);
1190 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1191 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1192 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1194 assert_mprog_count(target, 0);
1196 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1197 if (!ASSERT_EQ(err, 0, "prog_attach"))
1200 assert_mprog_count(target, 1);
1202 LIBBPF_OPTS_RESET(opta,
1203 .flags = BPF_F_AFTER,
1206 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1207 if (!ASSERT_EQ(err, 0, "prog_attach"))
1208 goto cleanup_target;
1210 assert_mprog_count(target, 2);
1212 optq.prog_ids = prog_ids;
1214 memset(prog_ids, 0, sizeof(prog_ids));
1215 optq.count = ARRAY_SIZE(prog_ids);
1217 err = bpf_prog_query_opts(loopback, target, &optq);
1218 if (!ASSERT_OK(err, "prog_query"))
1219 goto cleanup_target2;
1221 ASSERT_EQ(optq.count, 2, "count");
1222 ASSERT_EQ(optq.revision, 3, "revision");
1223 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1224 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1225 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1227 tc_skel_reset_all_seen(skel);
1228 ASSERT_OK(system(ping_cmd), ping_cmd);
1230 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1231 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1232 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1233 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1235 LIBBPF_OPTS_RESET(opta,
1236 .flags = BPF_F_AFTER,
1239 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1240 if (!ASSERT_EQ(err, 0, "prog_attach"))
1241 goto cleanup_target2;
1243 LIBBPF_OPTS_RESET(opta,
1244 .flags = BPF_F_AFTER,
1247 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1248 if (!ASSERT_EQ(err, 0, "prog_attach"))
1249 goto cleanup_target3;
1251 assert_mprog_count(target, 4);
1253 memset(prog_ids, 0, sizeof(prog_ids));
1254 optq.count = ARRAY_SIZE(prog_ids);
1256 err = bpf_prog_query_opts(loopback, target, &optq);
1257 if (!ASSERT_OK(err, "prog_query"))
1258 goto cleanup_target4;
1260 ASSERT_EQ(optq.count, 4, "count");
1261 ASSERT_EQ(optq.revision, 5, "revision");
1262 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1263 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1264 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1265 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1266 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1268 tc_skel_reset_all_seen(skel);
1269 ASSERT_OK(system(ping_cmd), ping_cmd);
1271 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1272 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1273 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1274 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1277 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1278 ASSERT_OK(err, "prog_detach");
1279 assert_mprog_count(target, 3);
1282 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1283 ASSERT_OK(err, "prog_detach");
1284 assert_mprog_count(target, 2);
1287 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1288 ASSERT_OK(err, "prog_detach");
1289 assert_mprog_count(target, 1);
1292 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1293 ASSERT_OK(err, "prog_detach");
1294 assert_mprog_count(target, 0);
1297 test_tc_link__destroy(skel);
1300 void serial_test_tc_opts_append(void)
1302 test_tc_opts_append_target(BPF_TCX_INGRESS);
1303 test_tc_opts_append_target(BPF_TCX_EGRESS);
1306 static void test_tc_opts_dev_cleanup_target(int target)
1308 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1309 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1310 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1311 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1312 struct test_tc_link *skel;
1315 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1316 ifindex = if_nametoindex("tcx_opts1");
1317 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1319 skel = test_tc_link__open_and_load();
1320 if (!ASSERT_OK_PTR(skel, "skel_load"))
1323 fd1 = bpf_program__fd(skel->progs.tc1);
1324 fd2 = bpf_program__fd(skel->progs.tc2);
1325 fd3 = bpf_program__fd(skel->progs.tc3);
1326 fd4 = bpf_program__fd(skel->progs.tc4);
1328 id1 = id_from_prog_fd(fd1);
1329 id2 = id_from_prog_fd(fd2);
1330 id3 = id_from_prog_fd(fd3);
1331 id4 = id_from_prog_fd(fd4);
1333 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1334 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1335 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1337 assert_mprog_count_ifindex(ifindex, target, 0);
1339 err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);
1340 if (!ASSERT_EQ(err, 0, "prog_attach"))
1343 assert_mprog_count_ifindex(ifindex, target, 1);
1345 err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);
1346 if (!ASSERT_EQ(err, 0, "prog_attach"))
1349 assert_mprog_count_ifindex(ifindex, target, 2);
1351 err = bpf_prog_attach_opts(fd3, ifindex, target, &opta);
1352 if (!ASSERT_EQ(err, 0, "prog_attach"))
1355 assert_mprog_count_ifindex(ifindex, target, 3);
1357 err = bpf_prog_attach_opts(fd4, ifindex, target, &opta);
1358 if (!ASSERT_EQ(err, 0, "prog_attach"))
1361 assert_mprog_count_ifindex(ifindex, target, 4);
1363 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1364 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1365 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1368 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1369 ASSERT_OK(err, "prog_detach");
1371 assert_mprog_count_ifindex(ifindex, target, 2);
1373 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1374 ASSERT_OK(err, "prog_detach");
1376 assert_mprog_count_ifindex(ifindex, target, 1);
1378 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1379 ASSERT_OK(err, "prog_detach");
1381 assert_mprog_count_ifindex(ifindex, target, 0);
1383 test_tc_link__destroy(skel);
1385 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1386 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1387 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1390 void serial_test_tc_opts_dev_cleanup(void)
1392 test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS);
1393 test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS);
1396 static void test_tc_opts_mixed_target(int target)
1398 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1399 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1400 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1401 LIBBPF_OPTS(bpf_tcx_opts, optl);
1402 __u32 pid1, pid2, pid3, pid4, lid2, lid4;
1403 __u32 prog_flags[4], link_flags[4];
1404 __u32 prog_ids[4], link_ids[4];
1405 struct test_tc_link *skel;
1406 struct bpf_link *link;
1409 skel = test_tc_link__open();
1410 if (!ASSERT_OK_PTR(skel, "skel_open"))
1413 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1414 0, "tc1_attach_type");
1415 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1416 0, "tc2_attach_type");
1417 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1418 0, "tc3_attach_type");
1419 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1420 0, "tc4_attach_type");
1422 err = test_tc_link__load(skel);
1423 if (!ASSERT_OK(err, "skel_load"))
1426 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1427 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1428 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1429 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1431 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1432 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1433 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1435 assert_mprog_count(target, 0);
1437 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1438 loopback, target, &opta);
1439 if (!ASSERT_EQ(err, 0, "prog_attach"))
1442 detach_fd = bpf_program__fd(skel->progs.tc1);
1444 assert_mprog_count(target, 1);
1446 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1447 if (!ASSERT_OK_PTR(link, "link_attach"))
1449 skel->links.tc2 = link;
1451 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1453 assert_mprog_count(target, 2);
1455 LIBBPF_OPTS_RESET(opta,
1456 .flags = BPF_F_REPLACE,
1457 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1460 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1461 loopback, target, &opta);
1462 ASSERT_EQ(err, -EEXIST, "prog_attach");
1464 assert_mprog_count(target, 2);
1466 LIBBPF_OPTS_RESET(opta,
1467 .flags = BPF_F_REPLACE,
1468 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1471 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1472 loopback, target, &opta);
1473 ASSERT_EQ(err, -EEXIST, "prog_attach");
1475 assert_mprog_count(target, 2);
1477 LIBBPF_OPTS_RESET(opta,
1478 .flags = BPF_F_REPLACE,
1479 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1482 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1483 loopback, target, &opta);
1484 ASSERT_EQ(err, -EBUSY, "prog_attach");
1486 assert_mprog_count(target, 2);
1488 LIBBPF_OPTS_RESET(opta,
1489 .flags = BPF_F_REPLACE,
1490 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1493 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1494 loopback, target, &opta);
1495 if (!ASSERT_EQ(err, 0, "prog_attach"))
1498 detach_fd = bpf_program__fd(skel->progs.tc3);
1500 assert_mprog_count(target, 2);
1502 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1503 if (!ASSERT_OK_PTR(link, "link_attach"))
1505 skel->links.tc4 = link;
1507 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1509 assert_mprog_count(target, 3);
1511 LIBBPF_OPTS_RESET(opta,
1512 .flags = BPF_F_REPLACE,
1513 .replace_prog_fd = bpf_program__fd(skel->progs.tc4),
1516 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1517 loopback, target, &opta);
1518 ASSERT_EQ(err, -EEXIST, "prog_attach");
1520 optq.prog_ids = prog_ids;
1521 optq.prog_attach_flags = prog_flags;
1522 optq.link_ids = link_ids;
1523 optq.link_attach_flags = link_flags;
1525 memset(prog_ids, 0, sizeof(prog_ids));
1526 memset(prog_flags, 0, sizeof(prog_flags));
1527 memset(link_ids, 0, sizeof(link_ids));
1528 memset(link_flags, 0, sizeof(link_flags));
1529 optq.count = ARRAY_SIZE(prog_ids);
1531 err = bpf_prog_query_opts(loopback, target, &optq);
1532 if (!ASSERT_OK(err, "prog_query"))
1535 ASSERT_EQ(optq.count, 3, "count");
1536 ASSERT_EQ(optq.revision, 5, "revision");
1537 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
1538 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
1539 ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]");
1540 ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]");
1541 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1542 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
1543 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1544 ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]");
1545 ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]");
1546 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
1547 ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]");
1548 ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]");
1549 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1550 ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]");
1551 ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]");
1552 ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]");
1554 ASSERT_OK(system(ping_cmd), ping_cmd);
1557 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
1558 ASSERT_OK(err, "prog_detach");
1559 assert_mprog_count(target, 2);
1562 test_tc_link__destroy(skel);
1563 assert_mprog_count(target, 0);
1566 void serial_test_tc_opts_mixed(void)
1568 test_tc_opts_mixed_target(BPF_TCX_INGRESS);
1569 test_tc_opts_mixed_target(BPF_TCX_EGRESS);
1572 static void test_tc_opts_demixed_target(int target)
1574 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1575 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1576 LIBBPF_OPTS(bpf_tcx_opts, optl);
1577 struct test_tc_link *skel;
1578 struct bpf_link *link;
1582 skel = test_tc_link__open();
1583 if (!ASSERT_OK_PTR(skel, "skel_open"))
1586 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1587 0, "tc1_attach_type");
1588 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1589 0, "tc2_attach_type");
1591 err = test_tc_link__load(skel);
1592 if (!ASSERT_OK(err, "skel_load"))
1595 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1596 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1597 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1599 assert_mprog_count(target, 0);
1601 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1602 loopback, target, &opta);
1603 if (!ASSERT_EQ(err, 0, "prog_attach"))
1606 assert_mprog_count(target, 1);
1608 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1609 if (!ASSERT_OK_PTR(link, "link_attach"))
1611 skel->links.tc2 = link;
1613 assert_mprog_count(target, 2);
1615 LIBBPF_OPTS_RESET(optd,
1616 .flags = BPF_F_AFTER,
1619 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1620 ASSERT_EQ(err, -EBUSY, "prog_detach");
1622 assert_mprog_count(target, 2);
1624 LIBBPF_OPTS_RESET(optd,
1625 .flags = BPF_F_BEFORE,
1628 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1629 ASSERT_OK(err, "prog_detach");
1631 assert_mprog_count(target, 1);
1635 err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1),
1636 loopback, target, &optd);
1637 ASSERT_OK(err, "prog_detach");
1638 assert_mprog_count(target, 2);
1641 test_tc_link__destroy(skel);
1642 assert_mprog_count(target, 0);
1645 void serial_test_tc_opts_demixed(void)
1647 test_tc_opts_demixed_target(BPF_TCX_INGRESS);
1648 test_tc_opts_demixed_target(BPF_TCX_EGRESS);
1651 static void test_tc_opts_detach_target(int target)
1653 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1654 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1655 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1656 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1657 struct test_tc_link *skel;
1661 skel = test_tc_link__open_and_load();
1662 if (!ASSERT_OK_PTR(skel, "skel_load"))
1665 fd1 = bpf_program__fd(skel->progs.tc1);
1666 fd2 = bpf_program__fd(skel->progs.tc2);
1667 fd3 = bpf_program__fd(skel->progs.tc3);
1668 fd4 = bpf_program__fd(skel->progs.tc4);
1670 id1 = id_from_prog_fd(fd1);
1671 id2 = id_from_prog_fd(fd2);
1672 id3 = id_from_prog_fd(fd3);
1673 id4 = id_from_prog_fd(fd4);
1675 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1676 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1677 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1679 assert_mprog_count(target, 0);
1681 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1682 if (!ASSERT_EQ(err, 0, "prog_attach"))
1685 assert_mprog_count(target, 1);
1687 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1688 if (!ASSERT_EQ(err, 0, "prog_attach"))
1691 assert_mprog_count(target, 2);
1693 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1694 if (!ASSERT_EQ(err, 0, "prog_attach"))
1697 assert_mprog_count(target, 3);
1699 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1700 if (!ASSERT_EQ(err, 0, "prog_attach"))
1703 assert_mprog_count(target, 4);
1705 optq.prog_ids = prog_ids;
1707 memset(prog_ids, 0, sizeof(prog_ids));
1708 optq.count = ARRAY_SIZE(prog_ids);
1710 err = bpf_prog_query_opts(loopback, target, &optq);
1711 if (!ASSERT_OK(err, "prog_query"))
1714 ASSERT_EQ(optq.count, 4, "count");
1715 ASSERT_EQ(optq.revision, 5, "revision");
1716 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1717 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1718 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1719 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1720 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1722 LIBBPF_OPTS_RESET(optd,
1723 .flags = BPF_F_BEFORE,
1726 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1727 ASSERT_OK(err, "prog_detach");
1729 assert_mprog_count(target, 3);
1731 memset(prog_ids, 0, sizeof(prog_ids));
1732 optq.count = ARRAY_SIZE(prog_ids);
1734 err = bpf_prog_query_opts(loopback, target, &optq);
1735 if (!ASSERT_OK(err, "prog_query"))
1738 ASSERT_EQ(optq.count, 3, "count");
1739 ASSERT_EQ(optq.revision, 6, "revision");
1740 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1741 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1742 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1743 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1745 LIBBPF_OPTS_RESET(optd,
1746 .flags = BPF_F_AFTER,
1749 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1750 ASSERT_OK(err, "prog_detach");
1752 assert_mprog_count(target, 2);
1754 memset(prog_ids, 0, sizeof(prog_ids));
1755 optq.count = ARRAY_SIZE(prog_ids);
1757 err = bpf_prog_query_opts(loopback, target, &optq);
1758 if (!ASSERT_OK(err, "prog_query"))
1761 ASSERT_EQ(optq.count, 2, "count");
1762 ASSERT_EQ(optq.revision, 7, "revision");
1763 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1764 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1765 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1767 LIBBPF_OPTS_RESET(optd);
1769 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1770 ASSERT_OK(err, "prog_detach");
1771 assert_mprog_count(target, 1);
1773 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1774 ASSERT_OK(err, "prog_detach");
1775 assert_mprog_count(target, 0);
1777 LIBBPF_OPTS_RESET(optd,
1778 .flags = BPF_F_BEFORE,
1781 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1782 ASSERT_EQ(err, -ENOENT, "prog_detach");
1784 LIBBPF_OPTS_RESET(optd,
1785 .flags = BPF_F_AFTER,
1788 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1789 ASSERT_EQ(err, -ENOENT, "prog_detach");
1793 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1794 ASSERT_OK(err, "prog_detach");
1795 assert_mprog_count(target, 3);
1798 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1799 ASSERT_OK(err, "prog_detach");
1800 assert_mprog_count(target, 2);
1803 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1804 ASSERT_OK(err, "prog_detach");
1805 assert_mprog_count(target, 1);
1808 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1809 ASSERT_OK(err, "prog_detach");
1810 assert_mprog_count(target, 0);
1813 test_tc_link__destroy(skel);
1816 void serial_test_tc_opts_detach(void)
1818 test_tc_opts_detach_target(BPF_TCX_INGRESS);
1819 test_tc_opts_detach_target(BPF_TCX_EGRESS);
1822 static void test_tc_opts_detach_before_target(int target)
1824 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1825 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1826 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1827 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1828 struct test_tc_link *skel;
1832 skel = test_tc_link__open_and_load();
1833 if (!ASSERT_OK_PTR(skel, "skel_load"))
1836 fd1 = bpf_program__fd(skel->progs.tc1);
1837 fd2 = bpf_program__fd(skel->progs.tc2);
1838 fd3 = bpf_program__fd(skel->progs.tc3);
1839 fd4 = bpf_program__fd(skel->progs.tc4);
1841 id1 = id_from_prog_fd(fd1);
1842 id2 = id_from_prog_fd(fd2);
1843 id3 = id_from_prog_fd(fd3);
1844 id4 = id_from_prog_fd(fd4);
1846 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1847 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1848 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1850 assert_mprog_count(target, 0);
1852 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1853 if (!ASSERT_EQ(err, 0, "prog_attach"))
1856 assert_mprog_count(target, 1);
1858 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1859 if (!ASSERT_EQ(err, 0, "prog_attach"))
1862 assert_mprog_count(target, 2);
1864 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1865 if (!ASSERT_EQ(err, 0, "prog_attach"))
1868 assert_mprog_count(target, 3);
1870 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1871 if (!ASSERT_EQ(err, 0, "prog_attach"))
1874 assert_mprog_count(target, 4);
1876 optq.prog_ids = prog_ids;
1878 memset(prog_ids, 0, sizeof(prog_ids));
1879 optq.count = ARRAY_SIZE(prog_ids);
1881 err = bpf_prog_query_opts(loopback, target, &optq);
1882 if (!ASSERT_OK(err, "prog_query"))
1885 ASSERT_EQ(optq.count, 4, "count");
1886 ASSERT_EQ(optq.revision, 5, "revision");
1887 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1888 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1889 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1890 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1891 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1893 LIBBPF_OPTS_RESET(optd,
1894 .flags = BPF_F_BEFORE,
1898 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1899 ASSERT_OK(err, "prog_detach");
1901 assert_mprog_count(target, 3);
1903 memset(prog_ids, 0, sizeof(prog_ids));
1904 optq.count = ARRAY_SIZE(prog_ids);
1906 err = bpf_prog_query_opts(loopback, target, &optq);
1907 if (!ASSERT_OK(err, "prog_query"))
1910 ASSERT_EQ(optq.count, 3, "count");
1911 ASSERT_EQ(optq.revision, 6, "revision");
1912 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1913 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1914 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1915 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1917 LIBBPF_OPTS_RESET(optd,
1918 .flags = BPF_F_BEFORE,
1922 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1923 ASSERT_EQ(err, -ENOENT, "prog_detach");
1924 assert_mprog_count(target, 3);
1926 LIBBPF_OPTS_RESET(optd,
1927 .flags = BPF_F_BEFORE,
1931 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1932 ASSERT_EQ(err, -ERANGE, "prog_detach");
1933 assert_mprog_count(target, 3);
1935 LIBBPF_OPTS_RESET(optd,
1936 .flags = BPF_F_BEFORE,
1940 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1941 ASSERT_EQ(err, -ENOENT, "prog_detach");
1942 assert_mprog_count(target, 3);
1944 LIBBPF_OPTS_RESET(optd,
1945 .flags = BPF_F_BEFORE,
1949 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1950 ASSERT_OK(err, "prog_detach");
1952 assert_mprog_count(target, 2);
1954 memset(prog_ids, 0, sizeof(prog_ids));
1955 optq.count = ARRAY_SIZE(prog_ids);
1957 err = bpf_prog_query_opts(loopback, target, &optq);
1958 if (!ASSERT_OK(err, "prog_query"))
1961 ASSERT_EQ(optq.count, 2, "count");
1962 ASSERT_EQ(optq.revision, 7, "revision");
1963 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
1964 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
1965 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1967 LIBBPF_OPTS_RESET(optd,
1968 .flags = BPF_F_BEFORE,
1972 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1973 ASSERT_OK(err, "prog_detach");
1975 assert_mprog_count(target, 1);
1977 memset(prog_ids, 0, sizeof(prog_ids));
1978 optq.count = ARRAY_SIZE(prog_ids);
1980 err = bpf_prog_query_opts(loopback, target, &optq);
1981 if (!ASSERT_OK(err, "prog_query"))
1984 ASSERT_EQ(optq.count, 1, "count");
1985 ASSERT_EQ(optq.revision, 8, "revision");
1986 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1987 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
1989 LIBBPF_OPTS_RESET(optd,
1990 .flags = BPF_F_BEFORE,
1993 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1994 ASSERT_OK(err, "prog_detach");
1996 assert_mprog_count(target, 0);
2000 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2001 ASSERT_OK(err, "prog_detach");
2002 assert_mprog_count(target, 3);
2005 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2006 ASSERT_OK(err, "prog_detach");
2007 assert_mprog_count(target, 2);
2010 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2011 ASSERT_OK(err, "prog_detach");
2012 assert_mprog_count(target, 1);
2015 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2016 ASSERT_OK(err, "prog_detach");
2017 assert_mprog_count(target, 0);
2020 test_tc_link__destroy(skel);
2023 void serial_test_tc_opts_detach_before(void)
2025 test_tc_opts_detach_before_target(BPF_TCX_INGRESS);
2026 test_tc_opts_detach_before_target(BPF_TCX_EGRESS);
2029 static void test_tc_opts_detach_after_target(int target)
2031 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2032 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2033 LIBBPF_OPTS(bpf_prog_query_opts, optq);
2034 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
2035 struct test_tc_link *skel;
2039 skel = test_tc_link__open_and_load();
2040 if (!ASSERT_OK_PTR(skel, "skel_load"))
2043 fd1 = bpf_program__fd(skel->progs.tc1);
2044 fd2 = bpf_program__fd(skel->progs.tc2);
2045 fd3 = bpf_program__fd(skel->progs.tc3);
2046 fd4 = bpf_program__fd(skel->progs.tc4);
2048 id1 = id_from_prog_fd(fd1);
2049 id2 = id_from_prog_fd(fd2);
2050 id3 = id_from_prog_fd(fd3);
2051 id4 = id_from_prog_fd(fd4);
2053 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2054 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
2055 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2057 assert_mprog_count(target, 0);
2059 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2060 if (!ASSERT_EQ(err, 0, "prog_attach"))
2063 assert_mprog_count(target, 1);
2065 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
2066 if (!ASSERT_EQ(err, 0, "prog_attach"))
2069 assert_mprog_count(target, 2);
2071 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2072 if (!ASSERT_EQ(err, 0, "prog_attach"))
2075 assert_mprog_count(target, 3);
2077 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
2078 if (!ASSERT_EQ(err, 0, "prog_attach"))
2081 assert_mprog_count(target, 4);
2083 optq.prog_ids = prog_ids;
2085 memset(prog_ids, 0, sizeof(prog_ids));
2086 optq.count = ARRAY_SIZE(prog_ids);
2088 err = bpf_prog_query_opts(loopback, target, &optq);
2089 if (!ASSERT_OK(err, "prog_query"))
2092 ASSERT_EQ(optq.count, 4, "count");
2093 ASSERT_EQ(optq.revision, 5, "revision");
2094 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2095 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
2096 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
2097 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
2098 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
2100 LIBBPF_OPTS_RESET(optd,
2101 .flags = BPF_F_AFTER,
2105 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2106 ASSERT_OK(err, "prog_detach");
2108 assert_mprog_count(target, 3);
2110 memset(prog_ids, 0, sizeof(prog_ids));
2111 optq.count = ARRAY_SIZE(prog_ids);
2113 err = bpf_prog_query_opts(loopback, target, &optq);
2114 if (!ASSERT_OK(err, "prog_query"))
2117 ASSERT_EQ(optq.count, 3, "count");
2118 ASSERT_EQ(optq.revision, 6, "revision");
2119 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2120 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
2121 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
2122 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
2124 LIBBPF_OPTS_RESET(optd,
2125 .flags = BPF_F_AFTER,
2129 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2130 ASSERT_EQ(err, -ENOENT, "prog_detach");
2131 assert_mprog_count(target, 3);
2133 LIBBPF_OPTS_RESET(optd,
2134 .flags = BPF_F_AFTER,
2138 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2139 ASSERT_EQ(err, -ERANGE, "prog_detach");
2140 assert_mprog_count(target, 3);
2142 LIBBPF_OPTS_RESET(optd,
2143 .flags = BPF_F_AFTER,
2147 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2148 ASSERT_EQ(err, -ERANGE, "prog_detach");
2149 assert_mprog_count(target, 3);
2151 LIBBPF_OPTS_RESET(optd,
2152 .flags = BPF_F_AFTER,
2156 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2157 ASSERT_EQ(err, -ERANGE, "prog_detach");
2158 assert_mprog_count(target, 3);
2160 LIBBPF_OPTS_RESET(optd,
2161 .flags = BPF_F_AFTER,
2165 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2166 ASSERT_OK(err, "prog_detach");
2168 assert_mprog_count(target, 2);
2170 memset(prog_ids, 0, sizeof(prog_ids));
2171 optq.count = ARRAY_SIZE(prog_ids);
2173 err = bpf_prog_query_opts(loopback, target, &optq);
2174 if (!ASSERT_OK(err, "prog_query"))
2177 ASSERT_EQ(optq.count, 2, "count");
2178 ASSERT_EQ(optq.revision, 7, "revision");
2179 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2180 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
2181 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
2183 LIBBPF_OPTS_RESET(optd,
2184 .flags = BPF_F_AFTER,
2188 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2189 ASSERT_OK(err, "prog_detach");
2191 assert_mprog_count(target, 1);
2193 memset(prog_ids, 0, sizeof(prog_ids));
2194 optq.count = ARRAY_SIZE(prog_ids);
2196 err = bpf_prog_query_opts(loopback, target, &optq);
2197 if (!ASSERT_OK(err, "prog_query"))
2200 ASSERT_EQ(optq.count, 1, "count");
2201 ASSERT_EQ(optq.revision, 8, "revision");
2202 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2203 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
2205 LIBBPF_OPTS_RESET(optd,
2206 .flags = BPF_F_AFTER,
2209 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2210 ASSERT_OK(err, "prog_detach");
2212 assert_mprog_count(target, 0);
2216 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2217 ASSERT_OK(err, "prog_detach");
2218 assert_mprog_count(target, 3);
2221 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2222 ASSERT_OK(err, "prog_detach");
2223 assert_mprog_count(target, 2);
2226 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2227 ASSERT_OK(err, "prog_detach");
2228 assert_mprog_count(target, 1);
2231 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2232 ASSERT_OK(err, "prog_detach");
2233 assert_mprog_count(target, 0);
2236 test_tc_link__destroy(skel);
2239 void serial_test_tc_opts_detach_after(void)
2241 test_tc_opts_detach_after_target(BPF_TCX_INGRESS);
2242 test_tc_opts_detach_after_target(BPF_TCX_EGRESS);
2245 static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
2247 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2248 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2251 assert_mprog_count(target, 0);
2253 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2254 BPF_TC_INGRESS : BPF_TC_EGRESS;
2255 err = bpf_tc_hook_create(&tc_hook);
2256 ASSERT_OK(err, "bpf_tc_hook_create");
2257 assert_mprog_count(target, 0);
2259 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2260 ASSERT_EQ(err, -ENOENT, "prog_detach");
2262 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2263 bpf_tc_hook_destroy(&tc_hook);
2265 assert_mprog_count(target, 0);
2268 void serial_test_tc_opts_delete_empty(void)
2270 test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);
2271 test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);
2272 test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);
2273 test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);
2276 static void test_tc_chain_mixed(int target)
2278 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
2279 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2280 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2281 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2282 __u32 fd1, fd2, fd3, id1, id2, id3;
2283 struct test_tc_link *skel;
2286 skel = test_tc_link__open_and_load();
2287 if (!ASSERT_OK_PTR(skel, "skel_load"))
2290 fd1 = bpf_program__fd(skel->progs.tc4);
2291 fd2 = bpf_program__fd(skel->progs.tc5);
2292 fd3 = bpf_program__fd(skel->progs.tc6);
2294 id1 = id_from_prog_fd(fd1);
2295 id2 = id_from_prog_fd(fd2);
2296 id3 = id_from_prog_fd(fd3);
2298 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2299 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2301 assert_mprog_count(target, 0);
2303 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2304 BPF_TC_INGRESS : BPF_TC_EGRESS;
2305 err = bpf_tc_hook_create(&tc_hook);
2306 err = err == -EEXIST ? 0 : err;
2307 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
2310 tc_opts.prog_fd = fd2;
2311 err = bpf_tc_attach(&tc_hook, &tc_opts);
2312 if (!ASSERT_OK(err, "bpf_tc_attach"))
2315 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2316 if (!ASSERT_EQ(err, 0, "prog_attach"))
2317 goto cleanup_filter;
2321 assert_mprog_count(target, 1);
2323 tc_skel_reset_all_seen(skel);
2324 ASSERT_OK(system(ping_cmd), ping_cmd);
2326 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2327 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
2328 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
2330 LIBBPF_OPTS_RESET(opta,
2331 .flags = BPF_F_REPLACE,
2332 .replace_prog_fd = fd3,
2335 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2336 if (!ASSERT_EQ(err, 0, "prog_attach"))
2341 assert_mprog_count(target, 1);
2343 tc_skel_reset_all_seen(skel);
2344 ASSERT_OK(system(ping_cmd), ping_cmd);
2346 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
2347 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2348 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2351 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
2352 ASSERT_OK(err, "prog_detach");
2353 assert_mprog_count(target, 0);
2355 tc_skel_reset_all_seen(skel);
2356 ASSERT_OK(system(ping_cmd), ping_cmd);
2358 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2359 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2360 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2363 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
2364 err = bpf_tc_detach(&tc_hook, &tc_opts);
2365 ASSERT_OK(err, "bpf_tc_detach");
2368 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2369 bpf_tc_hook_destroy(&tc_hook);
2372 test_tc_link__destroy(skel);
2375 void serial_test_tc_opts_chain_mixed(void)
2377 test_tc_chain_mixed(BPF_TCX_INGRESS);
2378 test_tc_chain_mixed(BPF_TCX_EGRESS);
2381 static int generate_dummy_prog(void)
2383 const struct bpf_insn prog_insns[] = {
2384 BPF_MOV64_IMM(BPF_REG_0, 0),
2387 const size_t prog_insn_cnt = sizeof(prog_insns) / sizeof(struct bpf_insn);
2388 LIBBPF_OPTS(bpf_prog_load_opts, opts);
2389 const size_t log_buf_sz = 256;
2393 log_buf = malloc(log_buf_sz);
2394 if (!ASSERT_OK_PTR(log_buf, "log_buf_alloc"))
2396 opts.log_buf = log_buf;
2397 opts.log_size = log_buf_sz;
2401 fd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, "tcx_prog", "GPL",
2402 prog_insns, prog_insn_cnt, &opts);
2403 ASSERT_STREQ(log_buf, "", "log_0");
2404 ASSERT_GE(fd, 0, "prog_fd");
2409 static void test_tc_opts_max_target(int target, int flags, bool relative)
2411 int err, ifindex, i, prog_fd, last_fd = -1;
2412 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2413 const int max_progs = 63;
2415 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
2416 ifindex = if_nametoindex("tcx_opts1");
2417 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
2419 assert_mprog_count_ifindex(ifindex, target, 0);
2421 for (i = 0; i < max_progs; i++) {
2422 prog_fd = generate_dummy_prog();
2423 if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
2425 err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
2426 if (!ASSERT_EQ(err, 0, "prog_attach"))
2428 assert_mprog_count_ifindex(ifindex, target, i + 1);
2429 if (i == max_progs - 1 && relative)
2435 prog_fd = generate_dummy_prog();
2436 if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
2440 opta.relative_fd = last_fd;
2441 err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
2442 ASSERT_EQ(err, -ERANGE, "prog_64_attach");
2443 assert_mprog_count_ifindex(ifindex, target, max_progs);
2448 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
2449 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
2450 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
2453 void serial_test_tc_opts_max(void)
2455 test_tc_opts_max_target(BPF_TCX_INGRESS, 0, false);
2456 test_tc_opts_max_target(BPF_TCX_EGRESS, 0, false);
2458 test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_BEFORE, false);
2459 test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_BEFORE, true);
2461 test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);
2462 test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);
2465 static void test_tc_opts_query_target(int target)
2467 const size_t attr_size = offsetofend(union bpf_attr, query);
2468 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2469 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2470 LIBBPF_OPTS(bpf_prog_query_opts, optq);
2471 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
2472 struct test_tc_link *skel;
2473 union bpf_attr attr;
2477 skel = test_tc_link__open_and_load();
2478 if (!ASSERT_OK_PTR(skel, "skel_load"))
2481 fd1 = bpf_program__fd(skel->progs.tc1);
2482 fd2 = bpf_program__fd(skel->progs.tc2);
2483 fd3 = bpf_program__fd(skel->progs.tc3);
2484 fd4 = bpf_program__fd(skel->progs.tc4);
2486 id1 = id_from_prog_fd(fd1);
2487 id2 = id_from_prog_fd(fd2);
2488 id3 = id_from_prog_fd(fd3);
2489 id4 = id_from_prog_fd(fd4);
2491 assert_mprog_count(target, 0);
2493 LIBBPF_OPTS_RESET(opta,
2494 .expected_revision = 1,
2497 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2498 if (!ASSERT_EQ(err, 0, "prog_attach"))
2501 assert_mprog_count(target, 1);
2503 LIBBPF_OPTS_RESET(opta,
2504 .expected_revision = 2,
2507 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
2508 if (!ASSERT_EQ(err, 0, "prog_attach"))
2511 assert_mprog_count(target, 2);
2513 LIBBPF_OPTS_RESET(opta,
2514 .expected_revision = 3,
2517 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2518 if (!ASSERT_EQ(err, 0, "prog_attach"))
2521 assert_mprog_count(target, 3);
2523 LIBBPF_OPTS_RESET(opta,
2524 .expected_revision = 4,
2527 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
2528 if (!ASSERT_EQ(err, 0, "prog_attach"))
2531 assert_mprog_count(target, 4);
2533 /* Test 1: Double query via libbpf API */
2534 err = bpf_prog_query_opts(loopback, target, &optq);
2535 if (!ASSERT_OK(err, "prog_query"))
2538 ASSERT_EQ(optq.count, 4, "count");
2539 ASSERT_EQ(optq.revision, 5, "revision");
2540 ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");
2541 ASSERT_EQ(optq.link_ids, NULL, "link_ids");
2543 memset(prog_ids, 0, sizeof(prog_ids));
2544 optq.prog_ids = prog_ids;
2546 err = bpf_prog_query_opts(loopback, target, &optq);
2547 if (!ASSERT_OK(err, "prog_query"))
2550 ASSERT_EQ(optq.count, 4, "count");
2551 ASSERT_EQ(optq.revision, 5, "revision");
2552 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2553 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
2554 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
2555 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
2556 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
2557 ASSERT_EQ(optq.link_ids, NULL, "link_ids");
2559 /* Test 2: Double query via bpf_attr & bpf(2) directly */
2560 memset(&attr, 0, attr_size);
2561 attr.query.target_ifindex = loopback;
2562 attr.query.attach_type = target;
2564 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2565 if (!ASSERT_OK(err, "prog_query"))
2568 ASSERT_EQ(attr.query.count, 4, "count");
2569 ASSERT_EQ(attr.query.revision, 5, "revision");
2570 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2571 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2572 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2573 ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2574 ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");
2575 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2576 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2577 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2579 memset(prog_ids, 0, sizeof(prog_ids));
2580 attr.query.prog_ids = ptr_to_u64(prog_ids);
2582 err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2583 if (!ASSERT_OK(err, "prog_query"))
2586 ASSERT_EQ(attr.query.count, 4, "count");
2587 ASSERT_EQ(attr.query.revision, 5, "revision");
2588 ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2589 ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2590 ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2591 ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2592 ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
2593 ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
2594 ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
2595 ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");
2596 ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");
2597 ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2598 ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2599 ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2600 ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2603 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2604 ASSERT_OK(err, "prog_detach");
2605 assert_mprog_count(target, 3);
2608 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2609 ASSERT_OK(err, "prog_detach");
2610 assert_mprog_count(target, 2);
2613 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2614 ASSERT_OK(err, "prog_detach");
2615 assert_mprog_count(target, 1);
2618 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2619 ASSERT_OK(err, "prog_detach");
2620 assert_mprog_count(target, 0);
2623 test_tc_link__destroy(skel);
2626 void serial_test_tc_opts_query(void)
2628 test_tc_opts_query_target(BPF_TCX_INGRESS);
2629 test_tc_opts_query_target(BPF_TCX_EGRESS);
2632 static void test_tc_opts_query_attach_target(int target)
2634 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2635 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2636 LIBBPF_OPTS(bpf_prog_query_opts, optq);
2637 struct test_tc_link *skel;
2642 skel = test_tc_link__open_and_load();
2643 if (!ASSERT_OK_PTR(skel, "skel_load"))
2646 fd1 = bpf_program__fd(skel->progs.tc1);
2647 id1 = id_from_prog_fd(fd1);
2649 err = bpf_prog_query_opts(loopback, target, &optq);
2650 if (!ASSERT_OK(err, "prog_query"))
2653 ASSERT_EQ(optq.count, 0, "count");
2654 ASSERT_EQ(optq.revision, 1, "revision");
2656 LIBBPF_OPTS_RESET(opta,
2657 .expected_revision = optq.revision,
2660 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2661 if (!ASSERT_EQ(err, 0, "prog_attach"))
2664 memset(prog_ids, 0, sizeof(prog_ids));
2665 optq.prog_ids = prog_ids;
2666 optq.count = ARRAY_SIZE(prog_ids);
2668 err = bpf_prog_query_opts(loopback, target, &optq);
2669 if (!ASSERT_OK(err, "prog_query"))
2672 ASSERT_EQ(optq.count, 1, "count");
2673 ASSERT_EQ(optq.revision, 2, "revision");
2674 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2675 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
2678 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2679 ASSERT_OK(err, "prog_detach");
2680 assert_mprog_count(target, 0);
2682 test_tc_link__destroy(skel);
2685 void serial_test_tc_opts_query_attach(void)
2687 test_tc_opts_query_attach_target(BPF_TCX_INGRESS);
2688 test_tc_opts_query_attach_target(BPF_TCX_EGRESS);