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 ASSERT_OK(system(ping_cmd), ping_cmd);
64 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
65 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
67 err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta);
68 if (!ASSERT_EQ(err, 0, "prog_attach"))
71 assert_mprog_count(BPF_TCX_INGRESS, 1);
72 assert_mprog_count(BPF_TCX_EGRESS, 1);
74 memset(prog_ids, 0, sizeof(prog_ids));
75 optq.count = ARRAY_SIZE(prog_ids);
77 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
78 if (!ASSERT_OK(err, "prog_query"))
81 ASSERT_EQ(optq.count, 1, "count");
82 ASSERT_EQ(optq.revision, 2, "revision");
83 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
84 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
86 ASSERT_OK(system(ping_cmd), ping_cmd);
88 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
89 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
92 err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd);
93 ASSERT_OK(err, "prog_detach_eg");
95 assert_mprog_count(BPF_TCX_INGRESS, 1);
96 assert_mprog_count(BPF_TCX_EGRESS, 0);
99 err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd);
100 ASSERT_OK(err, "prog_detach_in");
102 assert_mprog_count(BPF_TCX_INGRESS, 0);
103 assert_mprog_count(BPF_TCX_EGRESS, 0);
106 test_tc_link__destroy(skel);
109 static void test_tc_opts_before_target(int target)
111 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
112 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
113 LIBBPF_OPTS(bpf_prog_query_opts, optq);
114 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
115 struct test_tc_link *skel;
119 skel = test_tc_link__open_and_load();
120 if (!ASSERT_OK_PTR(skel, "skel_load"))
123 fd1 = bpf_program__fd(skel->progs.tc1);
124 fd2 = bpf_program__fd(skel->progs.tc2);
125 fd3 = bpf_program__fd(skel->progs.tc3);
126 fd4 = bpf_program__fd(skel->progs.tc4);
128 id1 = id_from_prog_fd(fd1);
129 id2 = id_from_prog_fd(fd2);
130 id3 = id_from_prog_fd(fd3);
131 id4 = id_from_prog_fd(fd4);
133 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
134 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
135 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
137 assert_mprog_count(target, 0);
139 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
140 if (!ASSERT_EQ(err, 0, "prog_attach"))
143 assert_mprog_count(target, 1);
145 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
146 if (!ASSERT_EQ(err, 0, "prog_attach"))
149 assert_mprog_count(target, 2);
151 optq.prog_ids = prog_ids;
153 memset(prog_ids, 0, sizeof(prog_ids));
154 optq.count = ARRAY_SIZE(prog_ids);
156 err = bpf_prog_query_opts(loopback, target, &optq);
157 if (!ASSERT_OK(err, "prog_query"))
158 goto cleanup_target2;
160 ASSERT_EQ(optq.count, 2, "count");
161 ASSERT_EQ(optq.revision, 3, "revision");
162 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
163 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
164 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
166 ASSERT_OK(system(ping_cmd), ping_cmd);
168 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
169 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
170 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
171 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
173 LIBBPF_OPTS_RESET(opta,
174 .flags = BPF_F_BEFORE,
178 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
179 if (!ASSERT_EQ(err, 0, "prog_attach"))
180 goto cleanup_target2;
182 memset(prog_ids, 0, sizeof(prog_ids));
183 optq.count = ARRAY_SIZE(prog_ids);
185 err = bpf_prog_query_opts(loopback, target, &optq);
186 if (!ASSERT_OK(err, "prog_query"))
187 goto cleanup_target3;
189 ASSERT_EQ(optq.count, 3, "count");
190 ASSERT_EQ(optq.revision, 4, "revision");
191 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
192 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
193 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
194 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
196 LIBBPF_OPTS_RESET(opta,
197 .flags = BPF_F_BEFORE,
201 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
202 if (!ASSERT_EQ(err, 0, "prog_attach"))
203 goto cleanup_target3;
205 assert_mprog_count(target, 4);
207 memset(prog_ids, 0, sizeof(prog_ids));
208 optq.count = ARRAY_SIZE(prog_ids);
210 err = bpf_prog_query_opts(loopback, target, &optq);
211 if (!ASSERT_OK(err, "prog_query"))
212 goto cleanup_target4;
214 ASSERT_EQ(optq.count, 4, "count");
215 ASSERT_EQ(optq.revision, 5, "revision");
216 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
217 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
218 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
219 ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");
220 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
222 ASSERT_OK(system(ping_cmd), ping_cmd);
224 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
225 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
226 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
227 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
230 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
231 ASSERT_OK(err, "prog_detach");
232 assert_mprog_count(target, 3);
235 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
236 ASSERT_OK(err, "prog_detach");
237 assert_mprog_count(target, 2);
240 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
241 ASSERT_OK(err, "prog_detach");
242 assert_mprog_count(target, 1);
245 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
246 ASSERT_OK(err, "prog_detach");
247 assert_mprog_count(target, 0);
250 test_tc_link__destroy(skel);
253 void serial_test_tc_opts_before(void)
255 test_tc_opts_before_target(BPF_TCX_INGRESS);
256 test_tc_opts_before_target(BPF_TCX_EGRESS);
259 static void test_tc_opts_after_target(int target)
261 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
262 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
263 LIBBPF_OPTS(bpf_prog_query_opts, optq);
264 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
265 struct test_tc_link *skel;
269 skel = test_tc_link__open_and_load();
270 if (!ASSERT_OK_PTR(skel, "skel_load"))
273 fd1 = bpf_program__fd(skel->progs.tc1);
274 fd2 = bpf_program__fd(skel->progs.tc2);
275 fd3 = bpf_program__fd(skel->progs.tc3);
276 fd4 = bpf_program__fd(skel->progs.tc4);
278 id1 = id_from_prog_fd(fd1);
279 id2 = id_from_prog_fd(fd2);
280 id3 = id_from_prog_fd(fd3);
281 id4 = id_from_prog_fd(fd4);
283 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
284 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
285 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
287 assert_mprog_count(target, 0);
289 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
290 if (!ASSERT_EQ(err, 0, "prog_attach"))
293 assert_mprog_count(target, 1);
295 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
296 if (!ASSERT_EQ(err, 0, "prog_attach"))
299 assert_mprog_count(target, 2);
301 optq.prog_ids = prog_ids;
303 memset(prog_ids, 0, sizeof(prog_ids));
304 optq.count = ARRAY_SIZE(prog_ids);
306 err = bpf_prog_query_opts(loopback, target, &optq);
307 if (!ASSERT_OK(err, "prog_query"))
308 goto cleanup_target2;
310 ASSERT_EQ(optq.count, 2, "count");
311 ASSERT_EQ(optq.revision, 3, "revision");
312 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
313 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
314 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
316 ASSERT_OK(system(ping_cmd), ping_cmd);
318 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
319 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
320 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
321 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
323 LIBBPF_OPTS_RESET(opta,
324 .flags = BPF_F_AFTER,
328 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
329 if (!ASSERT_EQ(err, 0, "prog_attach"))
330 goto cleanup_target2;
332 memset(prog_ids, 0, sizeof(prog_ids));
333 optq.count = ARRAY_SIZE(prog_ids);
335 err = bpf_prog_query_opts(loopback, target, &optq);
336 if (!ASSERT_OK(err, "prog_query"))
337 goto cleanup_target3;
339 ASSERT_EQ(optq.count, 3, "count");
340 ASSERT_EQ(optq.revision, 4, "revision");
341 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
342 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
343 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
344 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
346 LIBBPF_OPTS_RESET(opta,
347 .flags = BPF_F_AFTER,
351 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
352 if (!ASSERT_EQ(err, 0, "prog_attach"))
353 goto cleanup_target3;
355 assert_mprog_count(target, 4);
357 memset(prog_ids, 0, sizeof(prog_ids));
358 optq.count = ARRAY_SIZE(prog_ids);
360 err = bpf_prog_query_opts(loopback, target, &optq);
361 if (!ASSERT_OK(err, "prog_query"))
362 goto cleanup_target4;
364 ASSERT_EQ(optq.count, 4, "count");
365 ASSERT_EQ(optq.revision, 5, "revision");
366 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
367 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
368 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
369 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
370 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
372 ASSERT_OK(system(ping_cmd), ping_cmd);
374 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
375 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
376 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
377 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
380 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
381 ASSERT_OK(err, "prog_detach");
382 assert_mprog_count(target, 3);
384 memset(prog_ids, 0, sizeof(prog_ids));
385 optq.count = ARRAY_SIZE(prog_ids);
387 err = bpf_prog_query_opts(loopback, target, &optq);
388 if (!ASSERT_OK(err, "prog_query"))
389 goto cleanup_target3;
391 ASSERT_EQ(optq.count, 3, "count");
392 ASSERT_EQ(optq.revision, 6, "revision");
393 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
394 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
395 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
396 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
399 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
400 ASSERT_OK(err, "prog_detach");
401 assert_mprog_count(target, 2);
403 memset(prog_ids, 0, sizeof(prog_ids));
404 optq.count = ARRAY_SIZE(prog_ids);
406 err = bpf_prog_query_opts(loopback, target, &optq);
407 if (!ASSERT_OK(err, "prog_query"))
408 goto cleanup_target2;
410 ASSERT_EQ(optq.count, 2, "count");
411 ASSERT_EQ(optq.revision, 7, "revision");
412 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
413 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
414 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
417 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
418 ASSERT_OK(err, "prog_detach");
419 assert_mprog_count(target, 1);
421 memset(prog_ids, 0, sizeof(prog_ids));
422 optq.count = ARRAY_SIZE(prog_ids);
424 err = bpf_prog_query_opts(loopback, target, &optq);
425 if (!ASSERT_OK(err, "prog_query"))
428 ASSERT_EQ(optq.count, 1, "count");
429 ASSERT_EQ(optq.revision, 8, "revision");
430 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
431 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
434 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
435 ASSERT_OK(err, "prog_detach");
436 assert_mprog_count(target, 0);
439 test_tc_link__destroy(skel);
442 void serial_test_tc_opts_after(void)
444 test_tc_opts_after_target(BPF_TCX_INGRESS);
445 test_tc_opts_after_target(BPF_TCX_EGRESS);
448 static void test_tc_opts_revision_target(int target)
450 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
451 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
452 LIBBPF_OPTS(bpf_prog_query_opts, optq);
453 __u32 fd1, fd2, id1, id2;
454 struct test_tc_link *skel;
458 skel = test_tc_link__open_and_load();
459 if (!ASSERT_OK_PTR(skel, "skel_load"))
462 fd1 = bpf_program__fd(skel->progs.tc1);
463 fd2 = bpf_program__fd(skel->progs.tc2);
465 id1 = id_from_prog_fd(fd1);
466 id2 = id_from_prog_fd(fd2);
468 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
470 assert_mprog_count(target, 0);
472 LIBBPF_OPTS_RESET(opta,
473 .expected_revision = 1,
476 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
477 if (!ASSERT_EQ(err, 0, "prog_attach"))
480 assert_mprog_count(target, 1);
482 LIBBPF_OPTS_RESET(opta,
483 .expected_revision = 1,
486 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
487 if (!ASSERT_EQ(err, -ESTALE, "prog_attach"))
490 assert_mprog_count(target, 1);
492 LIBBPF_OPTS_RESET(opta,
493 .expected_revision = 2,
496 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
497 if (!ASSERT_EQ(err, 0, "prog_attach"))
500 assert_mprog_count(target, 2);
502 optq.prog_ids = prog_ids;
504 memset(prog_ids, 0, sizeof(prog_ids));
505 optq.count = ARRAY_SIZE(prog_ids);
507 err = bpf_prog_query_opts(loopback, target, &optq);
508 if (!ASSERT_OK(err, "prog_query"))
509 goto cleanup_target2;
511 ASSERT_EQ(optq.count, 2, "count");
512 ASSERT_EQ(optq.revision, 3, "revision");
513 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
514 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
515 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
517 ASSERT_OK(system(ping_cmd), ping_cmd);
519 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
520 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
522 LIBBPF_OPTS_RESET(optd,
523 .expected_revision = 2,
526 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
527 ASSERT_EQ(err, -ESTALE, "prog_detach");
528 assert_mprog_count(target, 2);
531 LIBBPF_OPTS_RESET(optd,
532 .expected_revision = 3,
535 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
536 ASSERT_OK(err, "prog_detach");
537 assert_mprog_count(target, 1);
540 LIBBPF_OPTS_RESET(optd);
542 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
543 ASSERT_OK(err, "prog_detach");
544 assert_mprog_count(target, 0);
547 test_tc_link__destroy(skel);
550 void serial_test_tc_opts_revision(void)
552 test_tc_opts_revision_target(BPF_TCX_INGRESS);
553 test_tc_opts_revision_target(BPF_TCX_EGRESS);
556 static void test_tc_chain_classic(int target, bool chain_tc_old)
558 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
559 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
560 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
561 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
562 bool hook_created = false, tc_attached = false;
563 __u32 fd1, fd2, fd3, id1, id2, id3;
564 struct test_tc_link *skel;
567 skel = test_tc_link__open_and_load();
568 if (!ASSERT_OK_PTR(skel, "skel_load"))
571 fd1 = bpf_program__fd(skel->progs.tc1);
572 fd2 = bpf_program__fd(skel->progs.tc2);
573 fd3 = bpf_program__fd(skel->progs.tc3);
575 id1 = id_from_prog_fd(fd1);
576 id2 = id_from_prog_fd(fd2);
577 id3 = id_from_prog_fd(fd3);
579 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
580 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
582 assert_mprog_count(target, 0);
585 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
586 BPF_TC_INGRESS : BPF_TC_EGRESS;
587 err = bpf_tc_hook_create(&tc_hook);
590 err = err == -EEXIST ? 0 : err;
591 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
594 tc_opts.prog_fd = fd3;
595 err = bpf_tc_attach(&tc_hook, &tc_opts);
596 if (!ASSERT_OK(err, "bpf_tc_attach"))
601 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
602 if (!ASSERT_EQ(err, 0, "prog_attach"))
605 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
606 if (!ASSERT_EQ(err, 0, "prog_attach"))
609 assert_mprog_count(target, 2);
611 ASSERT_OK(system(ping_cmd), ping_cmd);
613 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
614 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
615 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
617 skel->bss->seen_tc1 = false;
618 skel->bss->seen_tc2 = false;
619 skel->bss->seen_tc3 = false;
621 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
622 if (!ASSERT_OK(err, "prog_detach"))
625 assert_mprog_count(target, 1);
627 ASSERT_OK(system(ping_cmd), ping_cmd);
629 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
630 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
631 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
634 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
635 if (!ASSERT_OK(err, "prog_detach"))
638 __assert_mprog_count(target, 0, chain_tc_old, loopback);
641 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
642 err = bpf_tc_detach(&tc_hook, &tc_opts);
643 ASSERT_OK(err, "bpf_tc_detach");
646 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
647 bpf_tc_hook_destroy(&tc_hook);
649 test_tc_link__destroy(skel);
650 assert_mprog_count(target, 0);
653 void serial_test_tc_opts_chain_classic(void)
655 test_tc_chain_classic(BPF_TCX_INGRESS, false);
656 test_tc_chain_classic(BPF_TCX_EGRESS, false);
657 test_tc_chain_classic(BPF_TCX_INGRESS, true);
658 test_tc_chain_classic(BPF_TCX_EGRESS, true);
661 static void test_tc_opts_replace_target(int target)
663 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
664 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
665 LIBBPF_OPTS(bpf_prog_query_opts, optq);
666 __u32 fd1, fd2, fd3, id1, id2, id3, detach_fd;
667 __u32 prog_ids[4], prog_flags[4];
668 struct test_tc_link *skel;
671 skel = test_tc_link__open_and_load();
672 if (!ASSERT_OK_PTR(skel, "skel_load"))
675 fd1 = bpf_program__fd(skel->progs.tc1);
676 fd2 = bpf_program__fd(skel->progs.tc2);
677 fd3 = bpf_program__fd(skel->progs.tc3);
679 id1 = id_from_prog_fd(fd1);
680 id2 = id_from_prog_fd(fd2);
681 id3 = id_from_prog_fd(fd3);
683 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
684 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
686 assert_mprog_count(target, 0);
688 LIBBPF_OPTS_RESET(opta,
689 .expected_revision = 1,
692 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
693 if (!ASSERT_EQ(err, 0, "prog_attach"))
696 assert_mprog_count(target, 1);
698 LIBBPF_OPTS_RESET(opta,
699 .flags = BPF_F_BEFORE,
701 .expected_revision = 2,
704 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
705 if (!ASSERT_EQ(err, 0, "prog_attach"))
710 assert_mprog_count(target, 2);
712 optq.prog_attach_flags = prog_flags;
713 optq.prog_ids = prog_ids;
715 memset(prog_flags, 0, sizeof(prog_flags));
716 memset(prog_ids, 0, sizeof(prog_ids));
717 optq.count = ARRAY_SIZE(prog_ids);
719 err = bpf_prog_query_opts(loopback, target, &optq);
720 if (!ASSERT_OK(err, "prog_query"))
721 goto cleanup_target2;
723 ASSERT_EQ(optq.count, 2, "count");
724 ASSERT_EQ(optq.revision, 3, "revision");
725 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
726 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
727 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
729 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
730 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
731 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
733 ASSERT_OK(system(ping_cmd), ping_cmd);
735 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
736 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
737 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
739 skel->bss->seen_tc1 = false;
740 skel->bss->seen_tc2 = false;
741 skel->bss->seen_tc3 = false;
743 LIBBPF_OPTS_RESET(opta,
744 .flags = BPF_F_REPLACE,
745 .replace_prog_fd = fd2,
746 .expected_revision = 3,
749 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
750 if (!ASSERT_EQ(err, 0, "prog_attach"))
751 goto cleanup_target2;
755 assert_mprog_count(target, 2);
757 memset(prog_ids, 0, sizeof(prog_ids));
758 optq.count = ARRAY_SIZE(prog_ids);
760 err = bpf_prog_query_opts(loopback, target, &optq);
761 if (!ASSERT_OK(err, "prog_query"))
762 goto cleanup_target2;
764 ASSERT_EQ(optq.count, 2, "count");
765 ASSERT_EQ(optq.revision, 4, "revision");
766 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
767 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
768 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
770 ASSERT_OK(system(ping_cmd), ping_cmd);
772 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
773 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
774 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
776 skel->bss->seen_tc1 = false;
777 skel->bss->seen_tc2 = false;
778 skel->bss->seen_tc3 = false;
780 LIBBPF_OPTS_RESET(opta,
781 .flags = BPF_F_REPLACE | BPF_F_BEFORE,
782 .replace_prog_fd = fd3,
784 .expected_revision = 4,
787 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
788 if (!ASSERT_EQ(err, 0, "prog_attach"))
789 goto cleanup_target2;
793 assert_mprog_count(target, 2);
795 memset(prog_ids, 0, sizeof(prog_ids));
796 optq.count = ARRAY_SIZE(prog_ids);
798 err = bpf_prog_query_opts(loopback, target, &optq);
799 if (!ASSERT_OK(err, "prog_query"))
800 goto cleanup_target2;
802 ASSERT_EQ(optq.count, 2, "count");
803 ASSERT_EQ(optq.revision, 5, "revision");
804 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
805 ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
806 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
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 ASSERT_OK(system(ping_cmd), ping_cmd);
1089 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1090 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1091 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1092 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1094 LIBBPF_OPTS_RESET(opta,
1095 .flags = BPF_F_BEFORE,
1098 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1099 if (!ASSERT_EQ(err, 0, "prog_attach"))
1100 goto cleanup_target2;
1102 LIBBPF_OPTS_RESET(opta,
1103 .flags = BPF_F_BEFORE,
1106 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1107 if (!ASSERT_EQ(err, 0, "prog_attach"))
1108 goto cleanup_target3;
1110 assert_mprog_count(target, 4);
1112 memset(prog_ids, 0, sizeof(prog_ids));
1113 optq.count = ARRAY_SIZE(prog_ids);
1115 err = bpf_prog_query_opts(loopback, target, &optq);
1116 if (!ASSERT_OK(err, "prog_query"))
1117 goto cleanup_target4;
1119 ASSERT_EQ(optq.count, 4, "count");
1120 ASSERT_EQ(optq.revision, 5, "revision");
1121 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1122 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1123 ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
1124 ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");
1125 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1127 ASSERT_OK(system(ping_cmd), ping_cmd);
1129 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1130 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1131 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1132 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1135 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1136 ASSERT_OK(err, "prog_detach");
1137 assert_mprog_count(target, 3);
1140 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1141 ASSERT_OK(err, "prog_detach");
1142 assert_mprog_count(target, 2);
1145 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1146 ASSERT_OK(err, "prog_detach");
1147 assert_mprog_count(target, 1);
1150 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1151 ASSERT_OK(err, "prog_detach");
1152 assert_mprog_count(target, 0);
1155 test_tc_link__destroy(skel);
1158 void serial_test_tc_opts_prepend(void)
1160 test_tc_opts_prepend_target(BPF_TCX_INGRESS);
1161 test_tc_opts_prepend_target(BPF_TCX_EGRESS);
1164 static void test_tc_opts_append_target(int target)
1166 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1167 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1168 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1169 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1170 struct test_tc_link *skel;
1174 skel = test_tc_link__open_and_load();
1175 if (!ASSERT_OK_PTR(skel, "skel_load"))
1178 fd1 = bpf_program__fd(skel->progs.tc1);
1179 fd2 = bpf_program__fd(skel->progs.tc2);
1180 fd3 = bpf_program__fd(skel->progs.tc3);
1181 fd4 = bpf_program__fd(skel->progs.tc4);
1183 id1 = id_from_prog_fd(fd1);
1184 id2 = id_from_prog_fd(fd2);
1185 id3 = id_from_prog_fd(fd3);
1186 id4 = id_from_prog_fd(fd4);
1188 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1189 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1190 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1192 assert_mprog_count(target, 0);
1194 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1195 if (!ASSERT_EQ(err, 0, "prog_attach"))
1198 assert_mprog_count(target, 1);
1200 LIBBPF_OPTS_RESET(opta,
1201 .flags = BPF_F_AFTER,
1204 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1205 if (!ASSERT_EQ(err, 0, "prog_attach"))
1206 goto cleanup_target;
1208 assert_mprog_count(target, 2);
1210 optq.prog_ids = prog_ids;
1212 memset(prog_ids, 0, sizeof(prog_ids));
1213 optq.count = ARRAY_SIZE(prog_ids);
1215 err = bpf_prog_query_opts(loopback, target, &optq);
1216 if (!ASSERT_OK(err, "prog_query"))
1217 goto cleanup_target2;
1219 ASSERT_EQ(optq.count, 2, "count");
1220 ASSERT_EQ(optq.revision, 3, "revision");
1221 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1222 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1223 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1225 ASSERT_OK(system(ping_cmd), ping_cmd);
1227 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1228 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1229 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1230 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1232 LIBBPF_OPTS_RESET(opta,
1233 .flags = BPF_F_AFTER,
1236 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1237 if (!ASSERT_EQ(err, 0, "prog_attach"))
1238 goto cleanup_target2;
1240 LIBBPF_OPTS_RESET(opta,
1241 .flags = BPF_F_AFTER,
1244 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1245 if (!ASSERT_EQ(err, 0, "prog_attach"))
1246 goto cleanup_target3;
1248 assert_mprog_count(target, 4);
1250 memset(prog_ids, 0, sizeof(prog_ids));
1251 optq.count = ARRAY_SIZE(prog_ids);
1253 err = bpf_prog_query_opts(loopback, target, &optq);
1254 if (!ASSERT_OK(err, "prog_query"))
1255 goto cleanup_target4;
1257 ASSERT_EQ(optq.count, 4, "count");
1258 ASSERT_EQ(optq.revision, 5, "revision");
1259 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1260 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1261 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1262 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1263 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1265 ASSERT_OK(system(ping_cmd), ping_cmd);
1267 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1268 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1269 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1270 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1273 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1274 ASSERT_OK(err, "prog_detach");
1275 assert_mprog_count(target, 3);
1278 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1279 ASSERT_OK(err, "prog_detach");
1280 assert_mprog_count(target, 2);
1283 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1284 ASSERT_OK(err, "prog_detach");
1285 assert_mprog_count(target, 1);
1288 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1289 ASSERT_OK(err, "prog_detach");
1290 assert_mprog_count(target, 0);
1293 test_tc_link__destroy(skel);
1296 void serial_test_tc_opts_append(void)
1298 test_tc_opts_append_target(BPF_TCX_INGRESS);
1299 test_tc_opts_append_target(BPF_TCX_EGRESS);
1302 static void test_tc_opts_dev_cleanup_target(int target)
1304 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1305 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1306 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1307 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1308 struct test_tc_link *skel;
1311 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1312 ifindex = if_nametoindex("tcx_opts1");
1313 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1315 skel = test_tc_link__open_and_load();
1316 if (!ASSERT_OK_PTR(skel, "skel_load"))
1319 fd1 = bpf_program__fd(skel->progs.tc1);
1320 fd2 = bpf_program__fd(skel->progs.tc2);
1321 fd3 = bpf_program__fd(skel->progs.tc3);
1322 fd4 = bpf_program__fd(skel->progs.tc4);
1324 id1 = id_from_prog_fd(fd1);
1325 id2 = id_from_prog_fd(fd2);
1326 id3 = id_from_prog_fd(fd3);
1327 id4 = id_from_prog_fd(fd4);
1329 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1330 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1331 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1333 assert_mprog_count_ifindex(ifindex, target, 0);
1335 err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);
1336 if (!ASSERT_EQ(err, 0, "prog_attach"))
1339 assert_mprog_count_ifindex(ifindex, target, 1);
1341 err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);
1342 if (!ASSERT_EQ(err, 0, "prog_attach"))
1345 assert_mprog_count_ifindex(ifindex, target, 2);
1347 err = bpf_prog_attach_opts(fd3, ifindex, target, &opta);
1348 if (!ASSERT_EQ(err, 0, "prog_attach"))
1351 assert_mprog_count_ifindex(ifindex, target, 3);
1353 err = bpf_prog_attach_opts(fd4, ifindex, target, &opta);
1354 if (!ASSERT_EQ(err, 0, "prog_attach"))
1357 assert_mprog_count_ifindex(ifindex, target, 4);
1359 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1360 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1361 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1364 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1365 ASSERT_OK(err, "prog_detach");
1367 assert_mprog_count_ifindex(ifindex, target, 2);
1369 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1370 ASSERT_OK(err, "prog_detach");
1372 assert_mprog_count_ifindex(ifindex, target, 1);
1374 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1375 ASSERT_OK(err, "prog_detach");
1377 assert_mprog_count_ifindex(ifindex, target, 0);
1379 test_tc_link__destroy(skel);
1381 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1382 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1383 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1386 void serial_test_tc_opts_dev_cleanup(void)
1388 test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS);
1389 test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS);
1392 static void test_tc_opts_mixed_target(int target)
1394 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1395 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1396 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1397 LIBBPF_OPTS(bpf_tcx_opts, optl);
1398 __u32 pid1, pid2, pid3, pid4, lid2, lid4;
1399 __u32 prog_flags[4], link_flags[4];
1400 __u32 prog_ids[4], link_ids[4];
1401 struct test_tc_link *skel;
1402 struct bpf_link *link;
1405 skel = test_tc_link__open();
1406 if (!ASSERT_OK_PTR(skel, "skel_open"))
1409 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1410 0, "tc1_attach_type");
1411 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1412 0, "tc2_attach_type");
1413 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1414 0, "tc3_attach_type");
1415 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1416 0, "tc4_attach_type");
1418 err = test_tc_link__load(skel);
1419 if (!ASSERT_OK(err, "skel_load"))
1422 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1423 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1424 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1425 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1427 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1428 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1429 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1431 assert_mprog_count(target, 0);
1433 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1434 loopback, target, &opta);
1435 if (!ASSERT_EQ(err, 0, "prog_attach"))
1438 detach_fd = bpf_program__fd(skel->progs.tc1);
1440 assert_mprog_count(target, 1);
1442 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1443 if (!ASSERT_OK_PTR(link, "link_attach"))
1445 skel->links.tc2 = link;
1447 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1449 assert_mprog_count(target, 2);
1451 LIBBPF_OPTS_RESET(opta,
1452 .flags = BPF_F_REPLACE,
1453 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1456 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1457 loopback, target, &opta);
1458 ASSERT_EQ(err, -EEXIST, "prog_attach");
1460 assert_mprog_count(target, 2);
1462 LIBBPF_OPTS_RESET(opta,
1463 .flags = BPF_F_REPLACE,
1464 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1467 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1468 loopback, target, &opta);
1469 ASSERT_EQ(err, -EEXIST, "prog_attach");
1471 assert_mprog_count(target, 2);
1473 LIBBPF_OPTS_RESET(opta,
1474 .flags = BPF_F_REPLACE,
1475 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1478 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1479 loopback, target, &opta);
1480 ASSERT_EQ(err, -EBUSY, "prog_attach");
1482 assert_mprog_count(target, 2);
1484 LIBBPF_OPTS_RESET(opta,
1485 .flags = BPF_F_REPLACE,
1486 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1489 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1490 loopback, target, &opta);
1491 if (!ASSERT_EQ(err, 0, "prog_attach"))
1494 detach_fd = bpf_program__fd(skel->progs.tc3);
1496 assert_mprog_count(target, 2);
1498 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1499 if (!ASSERT_OK_PTR(link, "link_attach"))
1501 skel->links.tc4 = link;
1503 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1505 assert_mprog_count(target, 3);
1507 LIBBPF_OPTS_RESET(opta,
1508 .flags = BPF_F_REPLACE,
1509 .replace_prog_fd = bpf_program__fd(skel->progs.tc4),
1512 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1513 loopback, target, &opta);
1514 ASSERT_EQ(err, -EEXIST, "prog_attach");
1516 optq.prog_ids = prog_ids;
1517 optq.prog_attach_flags = prog_flags;
1518 optq.link_ids = link_ids;
1519 optq.link_attach_flags = link_flags;
1521 memset(prog_ids, 0, sizeof(prog_ids));
1522 memset(prog_flags, 0, sizeof(prog_flags));
1523 memset(link_ids, 0, sizeof(link_ids));
1524 memset(link_flags, 0, sizeof(link_flags));
1525 optq.count = ARRAY_SIZE(prog_ids);
1527 err = bpf_prog_query_opts(loopback, target, &optq);
1528 if (!ASSERT_OK(err, "prog_query"))
1531 ASSERT_EQ(optq.count, 3, "count");
1532 ASSERT_EQ(optq.revision, 5, "revision");
1533 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
1534 ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
1535 ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]");
1536 ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]");
1537 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1538 ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
1539 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1540 ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]");
1541 ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]");
1542 ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
1543 ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]");
1544 ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]");
1545 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1546 ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]");
1547 ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]");
1548 ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]");
1550 ASSERT_OK(system(ping_cmd), ping_cmd);
1553 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
1554 ASSERT_OK(err, "prog_detach");
1555 assert_mprog_count(target, 2);
1558 test_tc_link__destroy(skel);
1559 assert_mprog_count(target, 0);
1562 void serial_test_tc_opts_mixed(void)
1564 test_tc_opts_mixed_target(BPF_TCX_INGRESS);
1565 test_tc_opts_mixed_target(BPF_TCX_EGRESS);
1568 static void test_tc_opts_demixed_target(int target)
1570 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1571 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1572 LIBBPF_OPTS(bpf_tcx_opts, optl);
1573 struct test_tc_link *skel;
1574 struct bpf_link *link;
1578 skel = test_tc_link__open();
1579 if (!ASSERT_OK_PTR(skel, "skel_open"))
1582 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1583 0, "tc1_attach_type");
1584 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1585 0, "tc2_attach_type");
1587 err = test_tc_link__load(skel);
1588 if (!ASSERT_OK(err, "skel_load"))
1591 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1592 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1593 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1595 assert_mprog_count(target, 0);
1597 err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1598 loopback, target, &opta);
1599 if (!ASSERT_EQ(err, 0, "prog_attach"))
1602 assert_mprog_count(target, 1);
1604 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1605 if (!ASSERT_OK_PTR(link, "link_attach"))
1607 skel->links.tc2 = link;
1609 assert_mprog_count(target, 2);
1611 LIBBPF_OPTS_RESET(optd,
1612 .flags = BPF_F_AFTER,
1615 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1616 ASSERT_EQ(err, -EBUSY, "prog_detach");
1618 assert_mprog_count(target, 2);
1620 LIBBPF_OPTS_RESET(optd,
1621 .flags = BPF_F_BEFORE,
1624 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1625 ASSERT_OK(err, "prog_detach");
1627 assert_mprog_count(target, 1);
1631 err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1),
1632 loopback, target, &optd);
1633 ASSERT_OK(err, "prog_detach");
1634 assert_mprog_count(target, 2);
1637 test_tc_link__destroy(skel);
1638 assert_mprog_count(target, 0);
1641 void serial_test_tc_opts_demixed(void)
1643 test_tc_opts_demixed_target(BPF_TCX_INGRESS);
1644 test_tc_opts_demixed_target(BPF_TCX_EGRESS);
1647 static void test_tc_opts_detach_target(int target)
1649 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1650 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1651 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1652 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1653 struct test_tc_link *skel;
1657 skel = test_tc_link__open_and_load();
1658 if (!ASSERT_OK_PTR(skel, "skel_load"))
1661 fd1 = bpf_program__fd(skel->progs.tc1);
1662 fd2 = bpf_program__fd(skel->progs.tc2);
1663 fd3 = bpf_program__fd(skel->progs.tc3);
1664 fd4 = bpf_program__fd(skel->progs.tc4);
1666 id1 = id_from_prog_fd(fd1);
1667 id2 = id_from_prog_fd(fd2);
1668 id3 = id_from_prog_fd(fd3);
1669 id4 = id_from_prog_fd(fd4);
1671 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1672 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1673 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1675 assert_mprog_count(target, 0);
1677 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1678 if (!ASSERT_EQ(err, 0, "prog_attach"))
1681 assert_mprog_count(target, 1);
1683 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1684 if (!ASSERT_EQ(err, 0, "prog_attach"))
1687 assert_mprog_count(target, 2);
1689 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1690 if (!ASSERT_EQ(err, 0, "prog_attach"))
1693 assert_mprog_count(target, 3);
1695 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1696 if (!ASSERT_EQ(err, 0, "prog_attach"))
1699 assert_mprog_count(target, 4);
1701 optq.prog_ids = prog_ids;
1703 memset(prog_ids, 0, sizeof(prog_ids));
1704 optq.count = ARRAY_SIZE(prog_ids);
1706 err = bpf_prog_query_opts(loopback, target, &optq);
1707 if (!ASSERT_OK(err, "prog_query"))
1710 ASSERT_EQ(optq.count, 4, "count");
1711 ASSERT_EQ(optq.revision, 5, "revision");
1712 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1713 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1714 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1715 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1716 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1718 LIBBPF_OPTS_RESET(optd,
1719 .flags = BPF_F_BEFORE,
1722 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1723 ASSERT_OK(err, "prog_detach");
1725 assert_mprog_count(target, 3);
1727 memset(prog_ids, 0, sizeof(prog_ids));
1728 optq.count = ARRAY_SIZE(prog_ids);
1730 err = bpf_prog_query_opts(loopback, target, &optq);
1731 if (!ASSERT_OK(err, "prog_query"))
1734 ASSERT_EQ(optq.count, 3, "count");
1735 ASSERT_EQ(optq.revision, 6, "revision");
1736 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1737 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1738 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1739 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1741 LIBBPF_OPTS_RESET(optd,
1742 .flags = BPF_F_AFTER,
1745 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1746 ASSERT_OK(err, "prog_detach");
1748 assert_mprog_count(target, 2);
1750 memset(prog_ids, 0, sizeof(prog_ids));
1751 optq.count = ARRAY_SIZE(prog_ids);
1753 err = bpf_prog_query_opts(loopback, target, &optq);
1754 if (!ASSERT_OK(err, "prog_query"))
1757 ASSERT_EQ(optq.count, 2, "count");
1758 ASSERT_EQ(optq.revision, 7, "revision");
1759 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1760 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1761 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1763 LIBBPF_OPTS_RESET(optd);
1765 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1766 ASSERT_OK(err, "prog_detach");
1767 assert_mprog_count(target, 1);
1769 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1770 ASSERT_OK(err, "prog_detach");
1771 assert_mprog_count(target, 0);
1773 LIBBPF_OPTS_RESET(optd,
1774 .flags = BPF_F_BEFORE,
1777 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1778 ASSERT_EQ(err, -ENOENT, "prog_detach");
1780 LIBBPF_OPTS_RESET(optd,
1781 .flags = BPF_F_AFTER,
1784 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1785 ASSERT_EQ(err, -ENOENT, "prog_detach");
1789 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1790 ASSERT_OK(err, "prog_detach");
1791 assert_mprog_count(target, 3);
1794 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1795 ASSERT_OK(err, "prog_detach");
1796 assert_mprog_count(target, 2);
1799 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1800 ASSERT_OK(err, "prog_detach");
1801 assert_mprog_count(target, 1);
1804 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1805 ASSERT_OK(err, "prog_detach");
1806 assert_mprog_count(target, 0);
1809 test_tc_link__destroy(skel);
1812 void serial_test_tc_opts_detach(void)
1814 test_tc_opts_detach_target(BPF_TCX_INGRESS);
1815 test_tc_opts_detach_target(BPF_TCX_EGRESS);
1818 static void test_tc_opts_detach_before_target(int target)
1820 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1821 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1822 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1823 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1824 struct test_tc_link *skel;
1828 skel = test_tc_link__open_and_load();
1829 if (!ASSERT_OK_PTR(skel, "skel_load"))
1832 fd1 = bpf_program__fd(skel->progs.tc1);
1833 fd2 = bpf_program__fd(skel->progs.tc2);
1834 fd3 = bpf_program__fd(skel->progs.tc3);
1835 fd4 = bpf_program__fd(skel->progs.tc4);
1837 id1 = id_from_prog_fd(fd1);
1838 id2 = id_from_prog_fd(fd2);
1839 id3 = id_from_prog_fd(fd3);
1840 id4 = id_from_prog_fd(fd4);
1842 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1843 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1844 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1846 assert_mprog_count(target, 0);
1848 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1849 if (!ASSERT_EQ(err, 0, "prog_attach"))
1852 assert_mprog_count(target, 1);
1854 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1855 if (!ASSERT_EQ(err, 0, "prog_attach"))
1858 assert_mprog_count(target, 2);
1860 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1861 if (!ASSERT_EQ(err, 0, "prog_attach"))
1864 assert_mprog_count(target, 3);
1866 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1867 if (!ASSERT_EQ(err, 0, "prog_attach"))
1870 assert_mprog_count(target, 4);
1872 optq.prog_ids = prog_ids;
1874 memset(prog_ids, 0, sizeof(prog_ids));
1875 optq.count = ARRAY_SIZE(prog_ids);
1877 err = bpf_prog_query_opts(loopback, target, &optq);
1878 if (!ASSERT_OK(err, "prog_query"))
1881 ASSERT_EQ(optq.count, 4, "count");
1882 ASSERT_EQ(optq.revision, 5, "revision");
1883 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1884 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1885 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1886 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1887 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1889 LIBBPF_OPTS_RESET(optd,
1890 .flags = BPF_F_BEFORE,
1894 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1895 ASSERT_OK(err, "prog_detach");
1897 assert_mprog_count(target, 3);
1899 memset(prog_ids, 0, sizeof(prog_ids));
1900 optq.count = ARRAY_SIZE(prog_ids);
1902 err = bpf_prog_query_opts(loopback, target, &optq);
1903 if (!ASSERT_OK(err, "prog_query"))
1906 ASSERT_EQ(optq.count, 3, "count");
1907 ASSERT_EQ(optq.revision, 6, "revision");
1908 ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1909 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1910 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1911 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1913 LIBBPF_OPTS_RESET(optd,
1914 .flags = BPF_F_BEFORE,
1918 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1919 ASSERT_EQ(err, -ENOENT, "prog_detach");
1920 assert_mprog_count(target, 3);
1922 LIBBPF_OPTS_RESET(optd,
1923 .flags = BPF_F_BEFORE,
1927 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1928 ASSERT_EQ(err, -ERANGE, "prog_detach");
1929 assert_mprog_count(target, 3);
1931 LIBBPF_OPTS_RESET(optd,
1932 .flags = BPF_F_BEFORE,
1936 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1937 ASSERT_EQ(err, -ENOENT, "prog_detach");
1938 assert_mprog_count(target, 3);
1940 LIBBPF_OPTS_RESET(optd,
1941 .flags = BPF_F_BEFORE,
1945 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1946 ASSERT_OK(err, "prog_detach");
1948 assert_mprog_count(target, 2);
1950 memset(prog_ids, 0, sizeof(prog_ids));
1951 optq.count = ARRAY_SIZE(prog_ids);
1953 err = bpf_prog_query_opts(loopback, target, &optq);
1954 if (!ASSERT_OK(err, "prog_query"))
1957 ASSERT_EQ(optq.count, 2, "count");
1958 ASSERT_EQ(optq.revision, 7, "revision");
1959 ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
1960 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
1961 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1963 LIBBPF_OPTS_RESET(optd,
1964 .flags = BPF_F_BEFORE,
1968 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1969 ASSERT_OK(err, "prog_detach");
1971 assert_mprog_count(target, 1);
1973 memset(prog_ids, 0, sizeof(prog_ids));
1974 optq.count = ARRAY_SIZE(prog_ids);
1976 err = bpf_prog_query_opts(loopback, target, &optq);
1977 if (!ASSERT_OK(err, "prog_query"))
1980 ASSERT_EQ(optq.count, 1, "count");
1981 ASSERT_EQ(optq.revision, 8, "revision");
1982 ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1983 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
1985 LIBBPF_OPTS_RESET(optd,
1986 .flags = BPF_F_BEFORE,
1989 err = bpf_prog_detach_opts(0, loopback, target, &optd);
1990 ASSERT_OK(err, "prog_detach");
1992 assert_mprog_count(target, 0);
1996 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1997 ASSERT_OK(err, "prog_detach");
1998 assert_mprog_count(target, 3);
2001 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2002 ASSERT_OK(err, "prog_detach");
2003 assert_mprog_count(target, 2);
2006 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2007 ASSERT_OK(err, "prog_detach");
2008 assert_mprog_count(target, 1);
2011 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2012 ASSERT_OK(err, "prog_detach");
2013 assert_mprog_count(target, 0);
2016 test_tc_link__destroy(skel);
2019 void serial_test_tc_opts_detach_before(void)
2021 test_tc_opts_detach_before_target(BPF_TCX_INGRESS);
2022 test_tc_opts_detach_before_target(BPF_TCX_EGRESS);
2025 static void test_tc_opts_detach_after_target(int target)
2027 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2028 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2029 LIBBPF_OPTS(bpf_prog_query_opts, optq);
2030 __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
2031 struct test_tc_link *skel;
2035 skel = test_tc_link__open_and_load();
2036 if (!ASSERT_OK_PTR(skel, "skel_load"))
2039 fd1 = bpf_program__fd(skel->progs.tc1);
2040 fd2 = bpf_program__fd(skel->progs.tc2);
2041 fd3 = bpf_program__fd(skel->progs.tc3);
2042 fd4 = bpf_program__fd(skel->progs.tc4);
2044 id1 = id_from_prog_fd(fd1);
2045 id2 = id_from_prog_fd(fd2);
2046 id3 = id_from_prog_fd(fd3);
2047 id4 = id_from_prog_fd(fd4);
2049 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2050 ASSERT_NEQ(id3, id4, "prog_ids_3_4");
2051 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2053 assert_mprog_count(target, 0);
2055 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2056 if (!ASSERT_EQ(err, 0, "prog_attach"))
2059 assert_mprog_count(target, 1);
2061 err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
2062 if (!ASSERT_EQ(err, 0, "prog_attach"))
2065 assert_mprog_count(target, 2);
2067 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2068 if (!ASSERT_EQ(err, 0, "prog_attach"))
2071 assert_mprog_count(target, 3);
2073 err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
2074 if (!ASSERT_EQ(err, 0, "prog_attach"))
2077 assert_mprog_count(target, 4);
2079 optq.prog_ids = prog_ids;
2081 memset(prog_ids, 0, sizeof(prog_ids));
2082 optq.count = ARRAY_SIZE(prog_ids);
2084 err = bpf_prog_query_opts(loopback, target, &optq);
2085 if (!ASSERT_OK(err, "prog_query"))
2088 ASSERT_EQ(optq.count, 4, "count");
2089 ASSERT_EQ(optq.revision, 5, "revision");
2090 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2091 ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
2092 ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
2093 ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
2094 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
2096 LIBBPF_OPTS_RESET(optd,
2097 .flags = BPF_F_AFTER,
2101 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2102 ASSERT_OK(err, "prog_detach");
2104 assert_mprog_count(target, 3);
2106 memset(prog_ids, 0, sizeof(prog_ids));
2107 optq.count = ARRAY_SIZE(prog_ids);
2109 err = bpf_prog_query_opts(loopback, target, &optq);
2110 if (!ASSERT_OK(err, "prog_query"))
2113 ASSERT_EQ(optq.count, 3, "count");
2114 ASSERT_EQ(optq.revision, 6, "revision");
2115 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2116 ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
2117 ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
2118 ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
2120 LIBBPF_OPTS_RESET(optd,
2121 .flags = BPF_F_AFTER,
2125 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2126 ASSERT_EQ(err, -ENOENT, "prog_detach");
2127 assert_mprog_count(target, 3);
2129 LIBBPF_OPTS_RESET(optd,
2130 .flags = BPF_F_AFTER,
2134 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2135 ASSERT_EQ(err, -ERANGE, "prog_detach");
2136 assert_mprog_count(target, 3);
2138 LIBBPF_OPTS_RESET(optd,
2139 .flags = BPF_F_AFTER,
2143 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2144 ASSERT_EQ(err, -ERANGE, "prog_detach");
2145 assert_mprog_count(target, 3);
2147 LIBBPF_OPTS_RESET(optd,
2148 .flags = BPF_F_AFTER,
2152 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2153 ASSERT_EQ(err, -ERANGE, "prog_detach");
2154 assert_mprog_count(target, 3);
2156 LIBBPF_OPTS_RESET(optd,
2157 .flags = BPF_F_AFTER,
2161 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2162 ASSERT_OK(err, "prog_detach");
2164 assert_mprog_count(target, 2);
2166 memset(prog_ids, 0, sizeof(prog_ids));
2167 optq.count = ARRAY_SIZE(prog_ids);
2169 err = bpf_prog_query_opts(loopback, target, &optq);
2170 if (!ASSERT_OK(err, "prog_query"))
2173 ASSERT_EQ(optq.count, 2, "count");
2174 ASSERT_EQ(optq.revision, 7, "revision");
2175 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2176 ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
2177 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
2179 LIBBPF_OPTS_RESET(optd,
2180 .flags = BPF_F_AFTER,
2184 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2185 ASSERT_OK(err, "prog_detach");
2187 assert_mprog_count(target, 1);
2189 memset(prog_ids, 0, sizeof(prog_ids));
2190 optq.count = ARRAY_SIZE(prog_ids);
2192 err = bpf_prog_query_opts(loopback, target, &optq);
2193 if (!ASSERT_OK(err, "prog_query"))
2196 ASSERT_EQ(optq.count, 1, "count");
2197 ASSERT_EQ(optq.revision, 8, "revision");
2198 ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2199 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
2201 LIBBPF_OPTS_RESET(optd,
2202 .flags = BPF_F_AFTER,
2205 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2206 ASSERT_OK(err, "prog_detach");
2208 assert_mprog_count(target, 0);
2212 err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2213 ASSERT_OK(err, "prog_detach");
2214 assert_mprog_count(target, 3);
2217 err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2218 ASSERT_OK(err, "prog_detach");
2219 assert_mprog_count(target, 2);
2222 err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2223 ASSERT_OK(err, "prog_detach");
2224 assert_mprog_count(target, 1);
2227 err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2228 ASSERT_OK(err, "prog_detach");
2229 assert_mprog_count(target, 0);
2232 test_tc_link__destroy(skel);
2235 void serial_test_tc_opts_detach_after(void)
2237 test_tc_opts_detach_after_target(BPF_TCX_INGRESS);
2238 test_tc_opts_detach_after_target(BPF_TCX_EGRESS);
2241 static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
2243 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2244 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2247 assert_mprog_count(target, 0);
2249 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2250 BPF_TC_INGRESS : BPF_TC_EGRESS;
2251 err = bpf_tc_hook_create(&tc_hook);
2252 ASSERT_OK(err, "bpf_tc_hook_create");
2253 __assert_mprog_count(target, 0, true, loopback);
2255 err = bpf_prog_detach_opts(0, loopback, target, &optd);
2256 ASSERT_EQ(err, -ENOENT, "prog_detach");
2258 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2259 bpf_tc_hook_destroy(&tc_hook);
2261 assert_mprog_count(target, 0);
2264 void serial_test_tc_opts_delete_empty(void)
2266 test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);
2267 test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);
2268 test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);
2269 test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);
2272 static void test_tc_chain_mixed(int target)
2274 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
2275 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2276 LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2277 LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2278 __u32 fd1, fd2, fd3, id1, id2, id3;
2279 struct test_tc_link *skel;
2282 skel = test_tc_link__open_and_load();
2283 if (!ASSERT_OK_PTR(skel, "skel_load"))
2286 fd1 = bpf_program__fd(skel->progs.tc4);
2287 fd2 = bpf_program__fd(skel->progs.tc5);
2288 fd3 = bpf_program__fd(skel->progs.tc6);
2290 id1 = id_from_prog_fd(fd1);
2291 id2 = id_from_prog_fd(fd2);
2292 id3 = id_from_prog_fd(fd3);
2294 ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2295 ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2297 assert_mprog_count(target, 0);
2299 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2300 BPF_TC_INGRESS : BPF_TC_EGRESS;
2301 err = bpf_tc_hook_create(&tc_hook);
2302 err = err == -EEXIST ? 0 : err;
2303 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
2306 tc_opts.prog_fd = fd2;
2307 err = bpf_tc_attach(&tc_hook, &tc_opts);
2308 if (!ASSERT_OK(err, "bpf_tc_attach"))
2311 err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2312 if (!ASSERT_EQ(err, 0, "prog_attach"))
2313 goto cleanup_filter;
2317 assert_mprog_count(target, 1);
2319 ASSERT_OK(system(ping_cmd), ping_cmd);
2321 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2322 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
2323 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
2325 skel->bss->seen_tc4 = false;
2326 skel->bss->seen_tc5 = false;
2327 skel->bss->seen_tc6 = false;
2329 LIBBPF_OPTS_RESET(opta,
2330 .flags = BPF_F_REPLACE,
2331 .replace_prog_fd = fd3,
2334 err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2335 if (!ASSERT_EQ(err, 0, "prog_attach"))
2340 assert_mprog_count(target, 1);
2342 ASSERT_OK(system(ping_cmd), ping_cmd);
2344 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
2345 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2346 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2348 skel->bss->seen_tc4 = false;
2349 skel->bss->seen_tc5 = false;
2350 skel->bss->seen_tc6 = false;
2353 err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
2354 ASSERT_OK(err, "prog_detach");
2355 __assert_mprog_count(target, 0, true, loopback);
2357 ASSERT_OK(system(ping_cmd), ping_cmd);
2359 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2360 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2361 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2364 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
2365 err = bpf_tc_detach(&tc_hook, &tc_opts);
2366 ASSERT_OK(err, "bpf_tc_detach");
2369 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2370 bpf_tc_hook_destroy(&tc_hook);
2373 test_tc_link__destroy(skel);
2376 void serial_test_tc_opts_chain_mixed(void)
2378 test_tc_chain_mixed(BPF_TCX_INGRESS);
2379 test_tc_chain_mixed(BPF_TCX_EGRESS);