1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Isovalent */
3 #include <uapi/linux/if_link.h>
4 #include <uapi/linux/pkt_sched.h>
6 #include <test_progs.h>
9 #define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"
11 #include "test_tc_link.skel.h"
13 #include "netlink_helpers.h"
14 #include "tc_helpers.h"
16 void serial_test_tc_links_basic(void)
18 LIBBPF_OPTS(bpf_prog_query_opts, optq);
19 LIBBPF_OPTS(bpf_tcx_opts, optl);
20 __u32 prog_ids[2], link_ids[2];
21 __u32 pid1, pid2, lid1, lid2;
22 struct test_tc_link *skel;
23 struct bpf_link *link;
26 skel = test_tc_link__open_and_load();
27 if (!ASSERT_OK_PTR(skel, "skel_load"))
30 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
31 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
33 ASSERT_NEQ(pid1, pid2, "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 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
42 if (!ASSERT_OK_PTR(link, "link_attach"))
45 skel->links.tc1 = link;
47 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
49 assert_mprog_count(BPF_TCX_INGRESS, 1);
50 assert_mprog_count(BPF_TCX_EGRESS, 0);
52 optq.prog_ids = prog_ids;
53 optq.link_ids = link_ids;
55 memset(prog_ids, 0, sizeof(prog_ids));
56 memset(link_ids, 0, sizeof(link_ids));
57 optq.count = ARRAY_SIZE(prog_ids);
59 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);
60 if (!ASSERT_OK(err, "prog_query"))
63 ASSERT_EQ(optq.count, 1, "count");
64 ASSERT_EQ(optq.revision, 2, "revision");
65 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
66 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
67 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
68 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
70 tc_skel_reset_all_seen(skel);
71 ASSERT_OK(system(ping_cmd), ping_cmd);
73 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
74 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
76 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
77 if (!ASSERT_OK_PTR(link, "link_attach"))
80 skel->links.tc2 = link;
82 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
83 ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
85 assert_mprog_count(BPF_TCX_INGRESS, 1);
86 assert_mprog_count(BPF_TCX_EGRESS, 1);
88 memset(prog_ids, 0, sizeof(prog_ids));
89 memset(link_ids, 0, sizeof(link_ids));
90 optq.count = ARRAY_SIZE(prog_ids);
92 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
93 if (!ASSERT_OK(err, "prog_query"))
96 ASSERT_EQ(optq.count, 1, "count");
97 ASSERT_EQ(optq.revision, 2, "revision");
98 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
99 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
100 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
101 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
103 tc_skel_reset_all_seen(skel);
104 ASSERT_OK(system(ping_cmd), ping_cmd);
106 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
107 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
109 test_tc_link__destroy(skel);
111 assert_mprog_count(BPF_TCX_INGRESS, 0);
112 assert_mprog_count(BPF_TCX_EGRESS, 0);
115 static void test_tc_links_before_target(int target)
117 LIBBPF_OPTS(bpf_prog_query_opts, optq);
118 LIBBPF_OPTS(bpf_tcx_opts, optl);
119 __u32 prog_ids[5], link_ids[5];
120 __u32 pid1, pid2, pid3, pid4;
121 __u32 lid1, lid2, lid3, lid4;
122 struct test_tc_link *skel;
123 struct bpf_link *link;
126 skel = test_tc_link__open();
127 if (!ASSERT_OK_PTR(skel, "skel_open"))
130 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
131 0, "tc1_attach_type");
132 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
133 0, "tc2_attach_type");
134 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
135 0, "tc3_attach_type");
136 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
137 0, "tc4_attach_type");
139 err = test_tc_link__load(skel);
140 if (!ASSERT_OK(err, "skel_load"))
143 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
144 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
145 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
146 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
148 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
149 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
150 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
152 assert_mprog_count(target, 0);
154 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
155 if (!ASSERT_OK_PTR(link, "link_attach"))
158 skel->links.tc1 = link;
160 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
162 assert_mprog_count(target, 1);
164 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
165 if (!ASSERT_OK_PTR(link, "link_attach"))
168 skel->links.tc2 = link;
170 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
172 assert_mprog_count(target, 2);
174 optq.prog_ids = prog_ids;
175 optq.link_ids = link_ids;
177 memset(prog_ids, 0, sizeof(prog_ids));
178 memset(link_ids, 0, sizeof(link_ids));
179 optq.count = ARRAY_SIZE(prog_ids);
181 err = bpf_prog_query_opts(loopback, target, &optq);
182 if (!ASSERT_OK(err, "prog_query"))
185 ASSERT_EQ(optq.count, 2, "count");
186 ASSERT_EQ(optq.revision, 3, "revision");
187 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
188 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
189 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
190 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
191 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
192 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
194 tc_skel_reset_all_seen(skel);
195 ASSERT_OK(system(ping_cmd), ping_cmd);
197 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
198 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
199 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
200 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
202 LIBBPF_OPTS_RESET(optl,
203 .flags = BPF_F_BEFORE,
204 .relative_fd = bpf_program__fd(skel->progs.tc2),
207 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
208 if (!ASSERT_OK_PTR(link, "link_attach"))
211 skel->links.tc3 = link;
213 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
215 LIBBPF_OPTS_RESET(optl,
216 .flags = BPF_F_BEFORE | BPF_F_LINK,
220 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
221 if (!ASSERT_OK_PTR(link, "link_attach"))
224 skel->links.tc4 = link;
226 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
228 assert_mprog_count(target, 4);
230 memset(prog_ids, 0, sizeof(prog_ids));
231 memset(link_ids, 0, sizeof(link_ids));
232 optq.count = ARRAY_SIZE(prog_ids);
234 err = bpf_prog_query_opts(loopback, target, &optq);
235 if (!ASSERT_OK(err, "prog_query"))
238 ASSERT_EQ(optq.count, 4, "count");
239 ASSERT_EQ(optq.revision, 5, "revision");
240 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
241 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
242 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
243 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
244 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
245 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
246 ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]");
247 ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]");
248 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
249 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
251 tc_skel_reset_all_seen(skel);
252 ASSERT_OK(system(ping_cmd), ping_cmd);
254 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
255 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
256 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
257 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
259 test_tc_link__destroy(skel);
260 assert_mprog_count(target, 0);
263 void serial_test_tc_links_before(void)
265 test_tc_links_before_target(BPF_TCX_INGRESS);
266 test_tc_links_before_target(BPF_TCX_EGRESS);
269 static void test_tc_links_after_target(int target)
271 LIBBPF_OPTS(bpf_prog_query_opts, optq);
272 LIBBPF_OPTS(bpf_tcx_opts, optl);
273 __u32 prog_ids[5], link_ids[5];
274 __u32 pid1, pid2, pid3, pid4;
275 __u32 lid1, lid2, lid3, lid4;
276 struct test_tc_link *skel;
277 struct bpf_link *link;
280 skel = test_tc_link__open();
281 if (!ASSERT_OK_PTR(skel, "skel_open"))
284 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
285 0, "tc1_attach_type");
286 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
287 0, "tc2_attach_type");
288 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
289 0, "tc3_attach_type");
290 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
291 0, "tc4_attach_type");
293 err = test_tc_link__load(skel);
294 if (!ASSERT_OK(err, "skel_load"))
297 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
298 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
299 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
300 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
302 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
303 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
304 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
306 assert_mprog_count(target, 0);
308 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
309 if (!ASSERT_OK_PTR(link, "link_attach"))
312 skel->links.tc1 = link;
314 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
316 assert_mprog_count(target, 1);
318 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
319 if (!ASSERT_OK_PTR(link, "link_attach"))
322 skel->links.tc2 = link;
324 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
326 assert_mprog_count(target, 2);
328 optq.prog_ids = prog_ids;
329 optq.link_ids = link_ids;
331 memset(prog_ids, 0, sizeof(prog_ids));
332 memset(link_ids, 0, sizeof(link_ids));
333 optq.count = ARRAY_SIZE(prog_ids);
335 err = bpf_prog_query_opts(loopback, target, &optq);
336 if (!ASSERT_OK(err, "prog_query"))
339 ASSERT_EQ(optq.count, 2, "count");
340 ASSERT_EQ(optq.revision, 3, "revision");
341 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
342 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
343 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
344 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
345 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
346 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
348 tc_skel_reset_all_seen(skel);
349 ASSERT_OK(system(ping_cmd), ping_cmd);
351 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
352 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
353 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
354 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
356 LIBBPF_OPTS_RESET(optl,
357 .flags = BPF_F_AFTER,
358 .relative_fd = bpf_program__fd(skel->progs.tc1),
361 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
362 if (!ASSERT_OK_PTR(link, "link_attach"))
365 skel->links.tc3 = link;
367 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
369 LIBBPF_OPTS_RESET(optl,
370 .flags = BPF_F_AFTER | BPF_F_LINK,
371 .relative_fd = bpf_link__fd(skel->links.tc2),
374 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
375 if (!ASSERT_OK_PTR(link, "link_attach"))
378 skel->links.tc4 = link;
380 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
382 assert_mprog_count(target, 4);
384 memset(prog_ids, 0, sizeof(prog_ids));
385 memset(link_ids, 0, sizeof(link_ids));
386 optq.count = ARRAY_SIZE(prog_ids);
388 err = bpf_prog_query_opts(loopback, target, &optq);
389 if (!ASSERT_OK(err, "prog_query"))
392 ASSERT_EQ(optq.count, 4, "count");
393 ASSERT_EQ(optq.revision, 5, "revision");
394 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
395 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
396 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
397 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
398 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
399 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
400 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
401 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
402 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
403 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
405 tc_skel_reset_all_seen(skel);
406 ASSERT_OK(system(ping_cmd), ping_cmd);
408 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
409 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
410 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
411 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
413 test_tc_link__destroy(skel);
414 assert_mprog_count(target, 0);
417 void serial_test_tc_links_after(void)
419 test_tc_links_after_target(BPF_TCX_INGRESS);
420 test_tc_links_after_target(BPF_TCX_EGRESS);
423 static void test_tc_links_revision_target(int target)
425 LIBBPF_OPTS(bpf_prog_query_opts, optq);
426 LIBBPF_OPTS(bpf_tcx_opts, optl);
427 __u32 prog_ids[3], link_ids[3];
428 __u32 pid1, pid2, lid1, lid2;
429 struct test_tc_link *skel;
430 struct bpf_link *link;
433 skel = test_tc_link__open();
434 if (!ASSERT_OK_PTR(skel, "skel_open"))
437 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
438 0, "tc1_attach_type");
439 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
440 0, "tc2_attach_type");
442 err = test_tc_link__load(skel);
443 if (!ASSERT_OK(err, "skel_load"))
446 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
447 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
449 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
451 assert_mprog_count(target, 0);
453 optl.expected_revision = 1;
455 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
456 if (!ASSERT_OK_PTR(link, "link_attach"))
459 skel->links.tc1 = link;
461 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
463 assert_mprog_count(target, 1);
465 optl.expected_revision = 1;
467 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
468 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
469 bpf_link__destroy(link);
473 assert_mprog_count(target, 1);
475 optl.expected_revision = 2;
477 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
478 if (!ASSERT_OK_PTR(link, "link_attach"))
481 skel->links.tc2 = link;
483 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
485 assert_mprog_count(target, 2);
487 optq.prog_ids = prog_ids;
488 optq.link_ids = link_ids;
490 memset(prog_ids, 0, sizeof(prog_ids));
491 memset(link_ids, 0, sizeof(link_ids));
492 optq.count = ARRAY_SIZE(prog_ids);
494 err = bpf_prog_query_opts(loopback, target, &optq);
495 if (!ASSERT_OK(err, "prog_query"))
498 ASSERT_EQ(optq.count, 2, "count");
499 ASSERT_EQ(optq.revision, 3, "revision");
500 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
501 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
502 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
503 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
504 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
505 ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");
507 tc_skel_reset_all_seen(skel);
508 ASSERT_OK(system(ping_cmd), ping_cmd);
510 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
511 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
513 test_tc_link__destroy(skel);
514 assert_mprog_count(target, 0);
517 void serial_test_tc_links_revision(void)
519 test_tc_links_revision_target(BPF_TCX_INGRESS);
520 test_tc_links_revision_target(BPF_TCX_EGRESS);
523 static void test_tc_chain_classic(int target, bool chain_tc_old)
525 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
526 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
527 bool hook_created = false, tc_attached = false;
528 LIBBPF_OPTS(bpf_tcx_opts, optl);
529 __u32 pid1, pid2, pid3;
530 struct test_tc_link *skel;
531 struct bpf_link *link;
534 skel = test_tc_link__open();
535 if (!ASSERT_OK_PTR(skel, "skel_open"))
538 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
539 0, "tc1_attach_type");
540 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
541 0, "tc2_attach_type");
543 err = test_tc_link__load(skel);
544 if (!ASSERT_OK(err, "skel_load"))
547 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
548 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
549 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
551 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
552 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
554 assert_mprog_count(target, 0);
557 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
558 BPF_TC_INGRESS : BPF_TC_EGRESS;
559 err = bpf_tc_hook_create(&tc_hook);
562 err = err == -EEXIST ? 0 : err;
563 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
566 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
567 err = bpf_tc_attach(&tc_hook, &tc_opts);
568 if (!ASSERT_OK(err, "bpf_tc_attach"))
573 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
574 if (!ASSERT_OK_PTR(link, "link_attach"))
577 skel->links.tc1 = link;
579 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
580 if (!ASSERT_OK_PTR(link, "link_attach"))
583 skel->links.tc2 = link;
585 assert_mprog_count(target, 2);
587 tc_skel_reset_all_seen(skel);
588 ASSERT_OK(system(ping_cmd), ping_cmd);
590 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
591 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
592 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
594 err = bpf_link__detach(skel->links.tc2);
595 if (!ASSERT_OK(err, "prog_detach"))
598 assert_mprog_count(target, 1);
600 tc_skel_reset_all_seen(skel);
601 ASSERT_OK(system(ping_cmd), ping_cmd);
603 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
604 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
605 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
608 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
609 err = bpf_tc_detach(&tc_hook, &tc_opts);
610 ASSERT_OK(err, "bpf_tc_detach");
613 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
614 bpf_tc_hook_destroy(&tc_hook);
616 assert_mprog_count(target, 1);
617 test_tc_link__destroy(skel);
618 assert_mprog_count(target, 0);
621 void serial_test_tc_links_chain_classic(void)
623 test_tc_chain_classic(BPF_TCX_INGRESS, false);
624 test_tc_chain_classic(BPF_TCX_EGRESS, false);
625 test_tc_chain_classic(BPF_TCX_INGRESS, true);
626 test_tc_chain_classic(BPF_TCX_EGRESS, true);
629 static void test_tc_links_replace_target(int target)
631 LIBBPF_OPTS(bpf_prog_query_opts, optq);
632 LIBBPF_OPTS(bpf_tcx_opts, optl);
633 __u32 pid1, pid2, pid3, lid1, lid2;
634 __u32 prog_ids[4], link_ids[4];
635 struct test_tc_link *skel;
636 struct bpf_link *link;
639 skel = test_tc_link__open();
640 if (!ASSERT_OK_PTR(skel, "skel_open"))
643 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
644 0, "tc1_attach_type");
645 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
646 0, "tc2_attach_type");
647 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
648 0, "tc3_attach_type");
650 err = test_tc_link__load(skel);
651 if (!ASSERT_OK(err, "skel_load"))
654 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
655 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
656 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
658 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
659 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
661 assert_mprog_count(target, 0);
663 optl.expected_revision = 1;
665 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
666 if (!ASSERT_OK_PTR(link, "link_attach"))
669 skel->links.tc1 = link;
671 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
673 assert_mprog_count(target, 1);
675 LIBBPF_OPTS_RESET(optl,
676 .flags = BPF_F_BEFORE,
678 .expected_revision = 2,
681 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
682 if (!ASSERT_OK_PTR(link, "link_attach"))
685 skel->links.tc2 = link;
687 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
689 assert_mprog_count(target, 2);
691 optq.prog_ids = prog_ids;
692 optq.link_ids = link_ids;
694 memset(prog_ids, 0, sizeof(prog_ids));
695 memset(link_ids, 0, sizeof(link_ids));
696 optq.count = ARRAY_SIZE(prog_ids);
698 err = bpf_prog_query_opts(loopback, target, &optq);
699 if (!ASSERT_OK(err, "prog_query"))
702 ASSERT_EQ(optq.count, 2, "count");
703 ASSERT_EQ(optq.revision, 3, "revision");
704 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
705 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
706 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
707 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
708 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
709 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
711 tc_skel_reset_all_seen(skel);
712 ASSERT_OK(system(ping_cmd), ping_cmd);
714 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
715 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
716 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
718 LIBBPF_OPTS_RESET(optl,
719 .flags = BPF_F_REPLACE,
720 .relative_fd = bpf_program__fd(skel->progs.tc2),
721 .expected_revision = 3,
724 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
725 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
726 bpf_link__destroy(link);
730 assert_mprog_count(target, 2);
732 LIBBPF_OPTS_RESET(optl,
733 .flags = BPF_F_REPLACE | BPF_F_LINK,
734 .relative_fd = bpf_link__fd(skel->links.tc2),
735 .expected_revision = 3,
738 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
739 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
740 bpf_link__destroy(link);
744 assert_mprog_count(target, 2);
746 LIBBPF_OPTS_RESET(optl,
747 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,
751 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
752 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
753 bpf_link__destroy(link);
757 assert_mprog_count(target, 2);
759 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);
760 if (!ASSERT_OK(err, "link_update"))
763 assert_mprog_count(target, 2);
765 memset(prog_ids, 0, sizeof(prog_ids));
766 memset(link_ids, 0, sizeof(link_ids));
767 optq.count = ARRAY_SIZE(prog_ids);
769 err = bpf_prog_query_opts(loopback, target, &optq);
770 if (!ASSERT_OK(err, "prog_query"))
773 ASSERT_EQ(optq.count, 2, "count");
774 ASSERT_EQ(optq.revision, 4, "revision");
775 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
776 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
777 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
778 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
779 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
780 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
782 tc_skel_reset_all_seen(skel);
783 ASSERT_OK(system(ping_cmd), ping_cmd);
785 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
786 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
787 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
789 err = bpf_link__detach(skel->links.tc2);
790 if (!ASSERT_OK(err, "link_detach"))
793 assert_mprog_count(target, 1);
795 memset(prog_ids, 0, sizeof(prog_ids));
796 memset(link_ids, 0, sizeof(link_ids));
797 optq.count = ARRAY_SIZE(prog_ids);
799 err = bpf_prog_query_opts(loopback, target, &optq);
800 if (!ASSERT_OK(err, "prog_query"))
803 ASSERT_EQ(optq.count, 1, "count");
804 ASSERT_EQ(optq.revision, 5, "revision");
805 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
806 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
807 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
808 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
810 tc_skel_reset_all_seen(skel);
811 ASSERT_OK(system(ping_cmd), ping_cmd);
813 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
814 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
815 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
817 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
818 if (!ASSERT_OK(err, "link_update_self"))
821 assert_mprog_count(target, 1);
823 memset(prog_ids, 0, sizeof(prog_ids));
824 memset(link_ids, 0, sizeof(link_ids));
825 optq.count = ARRAY_SIZE(prog_ids);
827 err = bpf_prog_query_opts(loopback, target, &optq);
828 if (!ASSERT_OK(err, "prog_query"))
831 ASSERT_EQ(optq.count, 1, "count");
832 ASSERT_EQ(optq.revision, 5, "revision");
833 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
834 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
835 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
836 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
838 tc_skel_reset_all_seen(skel);
839 ASSERT_OK(system(ping_cmd), ping_cmd);
841 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
842 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
843 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
845 test_tc_link__destroy(skel);
846 assert_mprog_count(target, 0);
849 void serial_test_tc_links_replace(void)
851 test_tc_links_replace_target(BPF_TCX_INGRESS);
852 test_tc_links_replace_target(BPF_TCX_EGRESS);
855 static void test_tc_links_invalid_target(int target)
857 LIBBPF_OPTS(bpf_prog_query_opts, optq);
858 LIBBPF_OPTS(bpf_tcx_opts, optl);
859 __u32 pid1, pid2, lid1;
860 struct test_tc_link *skel;
861 struct bpf_link *link;
864 skel = test_tc_link__open();
865 if (!ASSERT_OK_PTR(skel, "skel_open"))
868 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
869 0, "tc1_attach_type");
870 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
871 0, "tc2_attach_type");
873 err = test_tc_link__load(skel);
874 if (!ASSERT_OK(err, "skel_load"))
877 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
878 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
880 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
882 assert_mprog_count(target, 0);
884 optl.flags = BPF_F_BEFORE | BPF_F_AFTER;
886 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
887 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
888 bpf_link__destroy(link);
892 assert_mprog_count(target, 0);
894 LIBBPF_OPTS_RESET(optl,
895 .flags = BPF_F_BEFORE | BPF_F_ID,
898 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
899 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
900 bpf_link__destroy(link);
904 assert_mprog_count(target, 0);
906 LIBBPF_OPTS_RESET(optl,
907 .flags = BPF_F_AFTER | BPF_F_ID,
910 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
911 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
912 bpf_link__destroy(link);
916 assert_mprog_count(target, 0);
918 LIBBPF_OPTS_RESET(optl,
922 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
923 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
924 bpf_link__destroy(link);
928 assert_mprog_count(target, 0);
930 LIBBPF_OPTS_RESET(optl,
932 .relative_fd = bpf_program__fd(skel->progs.tc2),
935 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
936 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
937 bpf_link__destroy(link);
941 assert_mprog_count(target, 0);
943 LIBBPF_OPTS_RESET(optl,
947 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
948 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
949 bpf_link__destroy(link);
953 assert_mprog_count(target, 0);
955 LIBBPF_OPTS_RESET(optl,
956 .relative_fd = bpf_program__fd(skel->progs.tc2),
959 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
960 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
961 bpf_link__destroy(link);
965 assert_mprog_count(target, 0);
967 LIBBPF_OPTS_RESET(optl,
968 .flags = BPF_F_BEFORE | BPF_F_AFTER,
969 .relative_fd = bpf_program__fd(skel->progs.tc2),
972 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
973 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
974 bpf_link__destroy(link);
978 assert_mprog_count(target, 0);
980 LIBBPF_OPTS_RESET(optl,
981 .flags = BPF_F_BEFORE,
982 .relative_fd = bpf_program__fd(skel->progs.tc1),
985 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
986 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
987 bpf_link__destroy(link);
991 assert_mprog_count(target, 0);
993 LIBBPF_OPTS_RESET(optl,
998 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
999 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1000 bpf_link__destroy(link);
1004 assert_mprog_count(target, 0);
1006 LIBBPF_OPTS_RESET(optl,
1011 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1012 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1013 bpf_link__destroy(link);
1017 assert_mprog_count(target, 0);
1019 LIBBPF_OPTS_RESET(optl,
1020 .flags = BPF_F_BEFORE,
1021 .relative_fd = bpf_program__fd(skel->progs.tc1),
1024 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1025 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1026 bpf_link__destroy(link);
1030 assert_mprog_count(target, 0);
1032 LIBBPF_OPTS_RESET(optl,
1033 .flags = BPF_F_BEFORE | BPF_F_LINK,
1034 .relative_fd = bpf_program__fd(skel->progs.tc1),
1037 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1038 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1039 bpf_link__destroy(link);
1043 assert_mprog_count(target, 0);
1045 LIBBPF_OPTS_RESET(optl,
1046 .flags = BPF_F_AFTER,
1047 .relative_fd = bpf_program__fd(skel->progs.tc1),
1050 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1051 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1052 bpf_link__destroy(link);
1056 assert_mprog_count(target, 0);
1058 LIBBPF_OPTS_RESET(optl);
1060 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl);
1061 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1062 bpf_link__destroy(link);
1066 assert_mprog_count(target, 0);
1068 LIBBPF_OPTS_RESET(optl,
1069 .flags = BPF_F_AFTER | BPF_F_LINK,
1070 .relative_fd = bpf_program__fd(skel->progs.tc1),
1073 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1074 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1075 bpf_link__destroy(link);
1079 assert_mprog_count(target, 0);
1081 LIBBPF_OPTS_RESET(optl);
1083 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1084 if (!ASSERT_OK_PTR(link, "link_attach"))
1087 skel->links.tc1 = link;
1089 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1091 assert_mprog_count(target, 1);
1093 LIBBPF_OPTS_RESET(optl,
1094 .flags = BPF_F_AFTER | BPF_F_LINK,
1095 .relative_fd = bpf_program__fd(skel->progs.tc1),
1098 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1099 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1100 bpf_link__destroy(link);
1104 assert_mprog_count(target, 1);
1106 LIBBPF_OPTS_RESET(optl,
1107 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1111 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1112 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1113 bpf_link__destroy(link);
1117 assert_mprog_count(target, 1);
1119 LIBBPF_OPTS_RESET(optl,
1120 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1121 .relative_id = lid1,
1124 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1125 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1126 bpf_link__destroy(link);
1130 assert_mprog_count(target, 1);
1132 LIBBPF_OPTS_RESET(optl,
1133 .flags = BPF_F_BEFORE | BPF_F_ID,
1134 .relative_id = pid1,
1137 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1138 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1139 bpf_link__destroy(link);
1142 assert_mprog_count(target, 1);
1144 LIBBPF_OPTS_RESET(optl,
1145 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1146 .relative_id = lid1,
1149 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1150 if (!ASSERT_OK_PTR(link, "link_attach"))
1153 skel->links.tc2 = link;
1155 assert_mprog_count(target, 2);
1157 test_tc_link__destroy(skel);
1158 assert_mprog_count(target, 0);
1161 void serial_test_tc_links_invalid(void)
1163 test_tc_links_invalid_target(BPF_TCX_INGRESS);
1164 test_tc_links_invalid_target(BPF_TCX_EGRESS);
1167 static void test_tc_links_prepend_target(int target)
1169 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1170 LIBBPF_OPTS(bpf_tcx_opts, optl);
1171 __u32 prog_ids[5], link_ids[5];
1172 __u32 pid1, pid2, pid3, pid4;
1173 __u32 lid1, lid2, lid3, lid4;
1174 struct test_tc_link *skel;
1175 struct bpf_link *link;
1178 skel = test_tc_link__open();
1179 if (!ASSERT_OK_PTR(skel, "skel_open"))
1182 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1183 0, "tc1_attach_type");
1184 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1185 0, "tc2_attach_type");
1186 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1187 0, "tc3_attach_type");
1188 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1189 0, "tc4_attach_type");
1191 err = test_tc_link__load(skel);
1192 if (!ASSERT_OK(err, "skel_load"))
1195 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1196 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1197 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1198 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1200 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1201 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1202 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1204 assert_mprog_count(target, 0);
1206 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1207 if (!ASSERT_OK_PTR(link, "link_attach"))
1210 skel->links.tc1 = link;
1212 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1214 assert_mprog_count(target, 1);
1216 LIBBPF_OPTS_RESET(optl,
1217 .flags = BPF_F_BEFORE,
1220 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1221 if (!ASSERT_OK_PTR(link, "link_attach"))
1224 skel->links.tc2 = link;
1226 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1228 assert_mprog_count(target, 2);
1230 optq.prog_ids = prog_ids;
1231 optq.link_ids = link_ids;
1233 memset(prog_ids, 0, sizeof(prog_ids));
1234 memset(link_ids, 0, sizeof(link_ids));
1235 optq.count = ARRAY_SIZE(prog_ids);
1237 err = bpf_prog_query_opts(loopback, target, &optq);
1238 if (!ASSERT_OK(err, "prog_query"))
1241 ASSERT_EQ(optq.count, 2, "count");
1242 ASSERT_EQ(optq.revision, 3, "revision");
1243 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
1244 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
1245 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
1246 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
1247 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1248 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1250 tc_skel_reset_all_seen(skel);
1251 ASSERT_OK(system(ping_cmd), ping_cmd);
1253 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1254 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1255 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1256 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1258 LIBBPF_OPTS_RESET(optl,
1259 .flags = BPF_F_BEFORE,
1262 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1263 if (!ASSERT_OK_PTR(link, "link_attach"))
1266 skel->links.tc3 = link;
1268 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1270 LIBBPF_OPTS_RESET(optl,
1271 .flags = BPF_F_BEFORE,
1274 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1275 if (!ASSERT_OK_PTR(link, "link_attach"))
1278 skel->links.tc4 = link;
1280 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1282 assert_mprog_count(target, 4);
1284 memset(prog_ids, 0, sizeof(prog_ids));
1285 memset(link_ids, 0, sizeof(link_ids));
1286 optq.count = ARRAY_SIZE(prog_ids);
1288 err = bpf_prog_query_opts(loopback, target, &optq);
1289 if (!ASSERT_OK(err, "prog_query"))
1292 ASSERT_EQ(optq.count, 4, "count");
1293 ASSERT_EQ(optq.revision, 5, "revision");
1294 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
1295 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
1296 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
1297 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
1298 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
1299 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
1300 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]");
1301 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]");
1302 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1303 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1305 tc_skel_reset_all_seen(skel);
1306 ASSERT_OK(system(ping_cmd), ping_cmd);
1308 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1309 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1310 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1311 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1313 test_tc_link__destroy(skel);
1314 assert_mprog_count(target, 0);
1317 void serial_test_tc_links_prepend(void)
1319 test_tc_links_prepend_target(BPF_TCX_INGRESS);
1320 test_tc_links_prepend_target(BPF_TCX_EGRESS);
1323 static void test_tc_links_append_target(int target)
1325 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1326 LIBBPF_OPTS(bpf_tcx_opts, optl);
1327 __u32 prog_ids[5], link_ids[5];
1328 __u32 pid1, pid2, pid3, pid4;
1329 __u32 lid1, lid2, lid3, lid4;
1330 struct test_tc_link *skel;
1331 struct bpf_link *link;
1334 skel = test_tc_link__open();
1335 if (!ASSERT_OK_PTR(skel, "skel_open"))
1338 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1339 0, "tc1_attach_type");
1340 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1341 0, "tc2_attach_type");
1342 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1343 0, "tc3_attach_type");
1344 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1345 0, "tc4_attach_type");
1347 err = test_tc_link__load(skel);
1348 if (!ASSERT_OK(err, "skel_load"))
1351 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1352 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1353 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1354 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1356 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1357 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1358 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1360 assert_mprog_count(target, 0);
1362 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1363 if (!ASSERT_OK_PTR(link, "link_attach"))
1366 skel->links.tc1 = link;
1368 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1370 assert_mprog_count(target, 1);
1372 LIBBPF_OPTS_RESET(optl,
1373 .flags = BPF_F_AFTER,
1376 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1377 if (!ASSERT_OK_PTR(link, "link_attach"))
1380 skel->links.tc2 = link;
1382 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1384 assert_mprog_count(target, 2);
1386 optq.prog_ids = prog_ids;
1387 optq.link_ids = link_ids;
1389 memset(prog_ids, 0, sizeof(prog_ids));
1390 memset(link_ids, 0, sizeof(link_ids));
1391 optq.count = ARRAY_SIZE(prog_ids);
1393 err = bpf_prog_query_opts(loopback, target, &optq);
1394 if (!ASSERT_OK(err, "prog_query"))
1397 ASSERT_EQ(optq.count, 2, "count");
1398 ASSERT_EQ(optq.revision, 3, "revision");
1399 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1400 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1401 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1402 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1403 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1404 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1406 tc_skel_reset_all_seen(skel);
1407 ASSERT_OK(system(ping_cmd), ping_cmd);
1409 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1410 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1411 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1412 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1414 LIBBPF_OPTS_RESET(optl,
1415 .flags = BPF_F_AFTER,
1418 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1419 if (!ASSERT_OK_PTR(link, "link_attach"))
1422 skel->links.tc3 = link;
1424 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1426 LIBBPF_OPTS_RESET(optl,
1427 .flags = BPF_F_AFTER,
1430 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1431 if (!ASSERT_OK_PTR(link, "link_attach"))
1434 skel->links.tc4 = link;
1436 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1438 assert_mprog_count(target, 4);
1440 memset(prog_ids, 0, sizeof(prog_ids));
1441 memset(link_ids, 0, sizeof(link_ids));
1442 optq.count = ARRAY_SIZE(prog_ids);
1444 err = bpf_prog_query_opts(loopback, target, &optq);
1445 if (!ASSERT_OK(err, "prog_query"))
1448 ASSERT_EQ(optq.count, 4, "count");
1449 ASSERT_EQ(optq.revision, 5, "revision");
1450 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1451 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1452 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1453 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1454 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
1455 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
1456 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
1457 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
1458 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1459 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1461 tc_skel_reset_all_seen(skel);
1462 ASSERT_OK(system(ping_cmd), ping_cmd);
1464 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1465 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1466 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1467 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1469 test_tc_link__destroy(skel);
1470 assert_mprog_count(target, 0);
1473 void serial_test_tc_links_append(void)
1475 test_tc_links_append_target(BPF_TCX_INGRESS);
1476 test_tc_links_append_target(BPF_TCX_EGRESS);
1479 static void test_tc_links_dev_cleanup_target(int target)
1481 LIBBPF_OPTS(bpf_tcx_opts, optl);
1482 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1483 __u32 pid1, pid2, pid3, pid4;
1484 struct test_tc_link *skel;
1485 struct bpf_link *link;
1488 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1489 ifindex = if_nametoindex("tcx_opts1");
1490 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1492 skel = test_tc_link__open();
1493 if (!ASSERT_OK_PTR(skel, "skel_open"))
1496 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1497 0, "tc1_attach_type");
1498 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1499 0, "tc2_attach_type");
1500 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1501 0, "tc3_attach_type");
1502 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1503 0, "tc4_attach_type");
1505 err = test_tc_link__load(skel);
1506 if (!ASSERT_OK(err, "skel_load"))
1509 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1510 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1511 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1512 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1514 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1515 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1516 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1518 assert_mprog_count(target, 0);
1520 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1521 if (!ASSERT_OK_PTR(link, "link_attach"))
1524 skel->links.tc1 = link;
1526 assert_mprog_count_ifindex(ifindex, target, 1);
1528 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1529 if (!ASSERT_OK_PTR(link, "link_attach"))
1532 skel->links.tc2 = link;
1534 assert_mprog_count_ifindex(ifindex, target, 2);
1536 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1537 if (!ASSERT_OK_PTR(link, "link_attach"))
1540 skel->links.tc3 = link;
1542 assert_mprog_count_ifindex(ifindex, target, 3);
1544 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1545 if (!ASSERT_OK_PTR(link, "link_attach"))
1548 skel->links.tc4 = link;
1550 assert_mprog_count_ifindex(ifindex, target, 4);
1552 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1553 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1554 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1556 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1557 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1558 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1559 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1561 test_tc_link__destroy(skel);
1564 test_tc_link__destroy(skel);
1566 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1567 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1568 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1571 void serial_test_tc_links_dev_cleanup(void)
1573 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);
1574 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);
1577 static void test_tc_chain_mixed(int target)
1579 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1580 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
1581 LIBBPF_OPTS(bpf_tcx_opts, optl);
1582 struct test_tc_link *skel;
1583 struct bpf_link *link;
1584 __u32 pid1, pid2, pid3;
1587 skel = test_tc_link__open();
1588 if (!ASSERT_OK_PTR(skel, "skel_open"))
1591 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1592 0, "tc4_attach_type");
1593 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),
1594 0, "tc5_attach_type");
1595 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),
1596 0, "tc6_attach_type");
1598 err = test_tc_link__load(skel);
1599 if (!ASSERT_OK(err, "skel_load"))
1602 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1603 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));
1604 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));
1606 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1607 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1609 assert_mprog_count(target, 0);
1611 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1612 BPF_TC_INGRESS : BPF_TC_EGRESS;
1613 err = bpf_tc_hook_create(&tc_hook);
1614 err = err == -EEXIST ? 0 : err;
1615 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1618 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1619 err = bpf_tc_attach(&tc_hook, &tc_opts);
1620 if (!ASSERT_OK(err, "bpf_tc_attach"))
1623 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);
1624 if (!ASSERT_OK_PTR(link, "link_attach"))
1627 skel->links.tc6 = link;
1629 assert_mprog_count(target, 1);
1631 tc_skel_reset_all_seen(skel);
1632 ASSERT_OK(system(ping_cmd), ping_cmd);
1634 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1635 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
1636 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
1638 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
1639 if (!ASSERT_OK(err, "link_update"))
1642 assert_mprog_count(target, 1);
1644 tc_skel_reset_all_seen(skel);
1645 ASSERT_OK(system(ping_cmd), ping_cmd);
1647 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1648 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1649 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1651 err = bpf_link__detach(skel->links.tc6);
1652 if (!ASSERT_OK(err, "prog_detach"))
1655 assert_mprog_count(target, 0);
1657 tc_skel_reset_all_seen(skel);
1658 ASSERT_OK(system(ping_cmd), ping_cmd);
1660 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1661 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1662 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1665 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1666 err = bpf_tc_detach(&tc_hook, &tc_opts);
1667 ASSERT_OK(err, "bpf_tc_detach");
1669 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
1670 bpf_tc_hook_destroy(&tc_hook);
1672 test_tc_link__destroy(skel);
1675 void serial_test_tc_links_chain_mixed(void)
1677 test_tc_chain_mixed(BPF_TCX_INGRESS);
1678 test_tc_chain_mixed(BPF_TCX_EGRESS);
1681 static void test_tc_links_ingress(int target, bool chain_tc_old,
1682 bool tcx_teardown_first)
1684 LIBBPF_OPTS(bpf_tc_opts, tc_opts,
1688 LIBBPF_OPTS(bpf_tc_hook, tc_hook,
1689 .ifindex = loopback,
1690 .attach_point = BPF_TC_CUSTOM,
1691 .parent = TC_H_INGRESS,
1693 bool hook_created = false, tc_attached = false;
1694 LIBBPF_OPTS(bpf_tcx_opts, optl);
1695 __u32 pid1, pid2, pid3;
1696 struct test_tc_link *skel;
1697 struct bpf_link *link;
1700 skel = test_tc_link__open();
1701 if (!ASSERT_OK_PTR(skel, "skel_open"))
1704 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1705 0, "tc1_attach_type");
1706 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1707 0, "tc2_attach_type");
1709 err = test_tc_link__load(skel);
1710 if (!ASSERT_OK(err, "skel_load"))
1713 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1714 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1715 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1717 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1718 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1720 assert_mprog_count(target, 0);
1723 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");
1724 hook_created = true;
1726 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
1727 err = bpf_tc_attach(&tc_hook, &tc_opts);
1728 if (!ASSERT_OK(err, "bpf_tc_attach"))
1733 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1734 if (!ASSERT_OK_PTR(link, "link_attach"))
1737 skel->links.tc1 = link;
1739 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1740 if (!ASSERT_OK_PTR(link, "link_attach"))
1743 skel->links.tc2 = link;
1745 assert_mprog_count(target, 2);
1747 tc_skel_reset_all_seen(skel);
1748 ASSERT_OK(system(ping_cmd), ping_cmd);
1750 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1751 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1752 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1754 err = bpf_link__detach(skel->links.tc2);
1755 if (!ASSERT_OK(err, "prog_detach"))
1758 assert_mprog_count(target, 1);
1760 tc_skel_reset_all_seen(skel);
1761 ASSERT_OK(system(ping_cmd), ping_cmd);
1763 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1764 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
1765 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1768 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1769 err = bpf_tc_detach(&tc_hook, &tc_opts);
1770 ASSERT_OK(err, "bpf_tc_detach");
1772 ASSERT_OK(system(ping_cmd), ping_cmd);
1773 assert_mprog_count(target, 1);
1774 if (hook_created && tcx_teardown_first)
1775 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1776 ASSERT_OK(system(ping_cmd), ping_cmd);
1777 test_tc_link__destroy(skel);
1778 ASSERT_OK(system(ping_cmd), ping_cmd);
1779 if (hook_created && !tcx_teardown_first)
1780 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1781 ASSERT_OK(system(ping_cmd), ping_cmd);
1782 assert_mprog_count(target, 0);
1785 void serial_test_tc_links_ingress(void)
1787 test_tc_links_ingress(BPF_TCX_INGRESS, true, true);
1788 test_tc_links_ingress(BPF_TCX_INGRESS, true, false);
1789 test_tc_links_ingress(BPF_TCX_INGRESS, false, false);
1798 static int qdisc_replace(int ifindex, const char *kind, bool block)
1800 struct rtnl_handle rth = { .fd = -1 };
1801 struct qdisc_req req;
1804 err = rtnl_open(&rth, 0);
1805 if (!ASSERT_OK(err, "open_rtnetlink"))
1808 memset(&req, 0, sizeof(req));
1809 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
1810 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST;
1811 req.n.nlmsg_type = RTM_NEWQDISC;
1812 req.t.tcm_family = AF_UNSPEC;
1813 req.t.tcm_ifindex = ifindex;
1814 req.t.tcm_parent = 0xfffffff1;
1816 addattr_l(&req.n, sizeof(req), TCA_KIND, kind, strlen(kind) + 1);
1818 addattr32(&req.n, sizeof(req), TCA_INGRESS_BLOCK, 1);
1820 err = rtnl_talk(&rth, &req.n, NULL);
1821 ASSERT_OK(err, "talk_rtnetlink");
1826 void serial_test_tc_links_dev_chain0(void)
1830 ASSERT_OK(system("ip link add dev foo type veth peer name bar"), "add veth");
1831 ifindex = if_nametoindex("foo");
1832 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1833 err = qdisc_replace(ifindex, "ingress", true);
1834 if (!ASSERT_OK(err, "attaching ingress"))
1836 ASSERT_OK(system("tc filter add block 1 matchall action skbmod swap mac"), "add block");
1837 err = qdisc_replace(ifindex, "clsact", false);
1838 if (!ASSERT_OK(err, "attaching clsact"))
1840 /* Heuristic: kern_sync_rcu() alone does not work; a wait-time of ~5s
1841 * triggered the issue without the fix reliably 100% of the time.
1844 ASSERT_OK(system("tc filter add dev foo ingress matchall action skbmod swap mac"), "add filter");
1846 ASSERT_OK(system("ip link del dev foo"), "del veth");
1847 ASSERT_EQ(if_nametoindex("foo"), 0, "foo removed");
1848 ASSERT_EQ(if_nametoindex("bar"), 0, "bar removed");
1851 static void test_tc_links_dev_mixed(int target)
1853 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1854 LIBBPF_OPTS(bpf_tc_hook, tc_hook);
1855 LIBBPF_OPTS(bpf_tcx_opts, optl);
1856 __u32 pid1, pid2, pid3, pid4;
1857 struct test_tc_link *skel;
1858 struct bpf_link *link;
1861 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1862 ifindex = if_nametoindex("tcx_opts1");
1863 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1865 skel = test_tc_link__open();
1866 if (!ASSERT_OK_PTR(skel, "skel_open"))
1869 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1870 0, "tc1_attach_type");
1871 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1872 0, "tc2_attach_type");
1873 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1874 0, "tc3_attach_type");
1875 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1876 0, "tc4_attach_type");
1878 err = test_tc_link__load(skel);
1879 if (!ASSERT_OK(err, "skel_load"))
1882 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1883 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1884 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1885 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1887 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1888 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1889 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1891 assert_mprog_count(target, 0);
1893 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1894 if (!ASSERT_OK_PTR(link, "link_attach"))
1897 skel->links.tc1 = link;
1899 assert_mprog_count_ifindex(ifindex, target, 1);
1901 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1902 if (!ASSERT_OK_PTR(link, "link_attach"))
1905 skel->links.tc2 = link;
1907 assert_mprog_count_ifindex(ifindex, target, 2);
1909 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1910 if (!ASSERT_OK_PTR(link, "link_attach"))
1913 skel->links.tc3 = link;
1915 assert_mprog_count_ifindex(ifindex, target, 3);
1917 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1918 if (!ASSERT_OK_PTR(link, "link_attach"))
1921 skel->links.tc4 = link;
1923 assert_mprog_count_ifindex(ifindex, target, 4);
1925 tc_hook.ifindex = ifindex;
1926 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1927 BPF_TC_INGRESS : BPF_TC_EGRESS;
1929 err = bpf_tc_hook_create(&tc_hook);
1930 err = err == -EEXIST ? 0 : err;
1931 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1934 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1935 err = bpf_tc_attach(&tc_hook, &tc_opts);
1936 if (!ASSERT_OK(err, "bpf_tc_attach"))
1939 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1940 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1941 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1943 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1944 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1945 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1946 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1948 test_tc_link__destroy(skel);
1951 test_tc_link__destroy(skel);
1953 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1954 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1955 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1958 void serial_test_tc_links_dev_mixed(void)
1960 test_tc_links_dev_mixed(BPF_TCX_INGRESS);
1961 test_tc_links_dev_mixed(BPF_TCX_EGRESS);