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"
12 #include "tc_helpers.h"
14 void serial_test_tc_links_basic(void)
16 LIBBPF_OPTS(bpf_prog_query_opts, optq);
17 LIBBPF_OPTS(bpf_tcx_opts, optl);
18 __u32 prog_ids[2], link_ids[2];
19 __u32 pid1, pid2, lid1, lid2;
20 struct test_tc_link *skel;
21 struct bpf_link *link;
24 skel = test_tc_link__open_and_load();
25 if (!ASSERT_OK_PTR(skel, "skel_load"))
28 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
29 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
31 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
33 assert_mprog_count(BPF_TCX_INGRESS, 0);
34 assert_mprog_count(BPF_TCX_EGRESS, 0);
36 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
37 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
39 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
40 if (!ASSERT_OK_PTR(link, "link_attach"))
43 skel->links.tc1 = link;
45 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
47 assert_mprog_count(BPF_TCX_INGRESS, 1);
48 assert_mprog_count(BPF_TCX_EGRESS, 0);
50 optq.prog_ids = prog_ids;
51 optq.link_ids = link_ids;
53 memset(prog_ids, 0, sizeof(prog_ids));
54 memset(link_ids, 0, sizeof(link_ids));
55 optq.count = ARRAY_SIZE(prog_ids);
57 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);
58 if (!ASSERT_OK(err, "prog_query"))
61 ASSERT_EQ(optq.count, 1, "count");
62 ASSERT_EQ(optq.revision, 2, "revision");
63 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
64 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
65 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
66 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
68 tc_skel_reset_all_seen(skel);
69 ASSERT_OK(system(ping_cmd), ping_cmd);
71 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
72 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
74 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
75 if (!ASSERT_OK_PTR(link, "link_attach"))
78 skel->links.tc2 = link;
80 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
81 ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
83 assert_mprog_count(BPF_TCX_INGRESS, 1);
84 assert_mprog_count(BPF_TCX_EGRESS, 1);
86 memset(prog_ids, 0, sizeof(prog_ids));
87 memset(link_ids, 0, sizeof(link_ids));
88 optq.count = ARRAY_SIZE(prog_ids);
90 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
91 if (!ASSERT_OK(err, "prog_query"))
94 ASSERT_EQ(optq.count, 1, "count");
95 ASSERT_EQ(optq.revision, 2, "revision");
96 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
97 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
98 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
99 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
101 tc_skel_reset_all_seen(skel);
102 ASSERT_OK(system(ping_cmd), ping_cmd);
104 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
105 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
107 test_tc_link__destroy(skel);
109 assert_mprog_count(BPF_TCX_INGRESS, 0);
110 assert_mprog_count(BPF_TCX_EGRESS, 0);
113 static void test_tc_links_before_target(int target)
115 LIBBPF_OPTS(bpf_prog_query_opts, optq);
116 LIBBPF_OPTS(bpf_tcx_opts, optl);
117 __u32 prog_ids[5], link_ids[5];
118 __u32 pid1, pid2, pid3, pid4;
119 __u32 lid1, lid2, lid3, lid4;
120 struct test_tc_link *skel;
121 struct bpf_link *link;
124 skel = test_tc_link__open();
125 if (!ASSERT_OK_PTR(skel, "skel_open"))
128 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
129 0, "tc1_attach_type");
130 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
131 0, "tc2_attach_type");
132 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
133 0, "tc3_attach_type");
134 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
135 0, "tc4_attach_type");
137 err = test_tc_link__load(skel);
138 if (!ASSERT_OK(err, "skel_load"))
141 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
142 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
143 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
144 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
146 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
147 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
148 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
150 assert_mprog_count(target, 0);
152 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
153 if (!ASSERT_OK_PTR(link, "link_attach"))
156 skel->links.tc1 = link;
158 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
160 assert_mprog_count(target, 1);
162 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
163 if (!ASSERT_OK_PTR(link, "link_attach"))
166 skel->links.tc2 = link;
168 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
170 assert_mprog_count(target, 2);
172 optq.prog_ids = prog_ids;
173 optq.link_ids = link_ids;
175 memset(prog_ids, 0, sizeof(prog_ids));
176 memset(link_ids, 0, sizeof(link_ids));
177 optq.count = ARRAY_SIZE(prog_ids);
179 err = bpf_prog_query_opts(loopback, target, &optq);
180 if (!ASSERT_OK(err, "prog_query"))
183 ASSERT_EQ(optq.count, 2, "count");
184 ASSERT_EQ(optq.revision, 3, "revision");
185 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
186 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
187 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
188 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
189 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
190 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
192 tc_skel_reset_all_seen(skel);
193 ASSERT_OK(system(ping_cmd), ping_cmd);
195 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
196 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
197 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
198 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
200 LIBBPF_OPTS_RESET(optl,
201 .flags = BPF_F_BEFORE,
202 .relative_fd = bpf_program__fd(skel->progs.tc2),
205 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
206 if (!ASSERT_OK_PTR(link, "link_attach"))
209 skel->links.tc3 = link;
211 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
213 LIBBPF_OPTS_RESET(optl,
214 .flags = BPF_F_BEFORE | BPF_F_LINK,
218 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
219 if (!ASSERT_OK_PTR(link, "link_attach"))
222 skel->links.tc4 = link;
224 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
226 assert_mprog_count(target, 4);
228 memset(prog_ids, 0, sizeof(prog_ids));
229 memset(link_ids, 0, sizeof(link_ids));
230 optq.count = ARRAY_SIZE(prog_ids);
232 err = bpf_prog_query_opts(loopback, target, &optq);
233 if (!ASSERT_OK(err, "prog_query"))
236 ASSERT_EQ(optq.count, 4, "count");
237 ASSERT_EQ(optq.revision, 5, "revision");
238 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
239 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
240 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
241 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
242 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
243 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
244 ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]");
245 ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]");
246 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
247 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
249 tc_skel_reset_all_seen(skel);
250 ASSERT_OK(system(ping_cmd), ping_cmd);
252 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
253 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
254 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
255 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
257 test_tc_link__destroy(skel);
258 assert_mprog_count(target, 0);
261 void serial_test_tc_links_before(void)
263 test_tc_links_before_target(BPF_TCX_INGRESS);
264 test_tc_links_before_target(BPF_TCX_EGRESS);
267 static void test_tc_links_after_target(int target)
269 LIBBPF_OPTS(bpf_prog_query_opts, optq);
270 LIBBPF_OPTS(bpf_tcx_opts, optl);
271 __u32 prog_ids[5], link_ids[5];
272 __u32 pid1, pid2, pid3, pid4;
273 __u32 lid1, lid2, lid3, lid4;
274 struct test_tc_link *skel;
275 struct bpf_link *link;
278 skel = test_tc_link__open();
279 if (!ASSERT_OK_PTR(skel, "skel_open"))
282 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
283 0, "tc1_attach_type");
284 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
285 0, "tc2_attach_type");
286 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
287 0, "tc3_attach_type");
288 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
289 0, "tc4_attach_type");
291 err = test_tc_link__load(skel);
292 if (!ASSERT_OK(err, "skel_load"))
295 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
296 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
297 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
298 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
300 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
301 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
302 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
304 assert_mprog_count(target, 0);
306 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
307 if (!ASSERT_OK_PTR(link, "link_attach"))
310 skel->links.tc1 = link;
312 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
314 assert_mprog_count(target, 1);
316 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
317 if (!ASSERT_OK_PTR(link, "link_attach"))
320 skel->links.tc2 = link;
322 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
324 assert_mprog_count(target, 2);
326 optq.prog_ids = prog_ids;
327 optq.link_ids = link_ids;
329 memset(prog_ids, 0, sizeof(prog_ids));
330 memset(link_ids, 0, sizeof(link_ids));
331 optq.count = ARRAY_SIZE(prog_ids);
333 err = bpf_prog_query_opts(loopback, target, &optq);
334 if (!ASSERT_OK(err, "prog_query"))
337 ASSERT_EQ(optq.count, 2, "count");
338 ASSERT_EQ(optq.revision, 3, "revision");
339 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
340 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
341 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
342 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
343 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
344 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
346 tc_skel_reset_all_seen(skel);
347 ASSERT_OK(system(ping_cmd), ping_cmd);
349 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
350 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
351 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
352 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
354 LIBBPF_OPTS_RESET(optl,
355 .flags = BPF_F_AFTER,
356 .relative_fd = bpf_program__fd(skel->progs.tc1),
359 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
360 if (!ASSERT_OK_PTR(link, "link_attach"))
363 skel->links.tc3 = link;
365 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
367 LIBBPF_OPTS_RESET(optl,
368 .flags = BPF_F_AFTER | BPF_F_LINK,
369 .relative_fd = bpf_link__fd(skel->links.tc2),
372 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
373 if (!ASSERT_OK_PTR(link, "link_attach"))
376 skel->links.tc4 = link;
378 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
380 assert_mprog_count(target, 4);
382 memset(prog_ids, 0, sizeof(prog_ids));
383 memset(link_ids, 0, sizeof(link_ids));
384 optq.count = ARRAY_SIZE(prog_ids);
386 err = bpf_prog_query_opts(loopback, target, &optq);
387 if (!ASSERT_OK(err, "prog_query"))
390 ASSERT_EQ(optq.count, 4, "count");
391 ASSERT_EQ(optq.revision, 5, "revision");
392 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
393 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
394 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
395 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
396 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
397 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
398 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
399 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
400 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
401 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
403 tc_skel_reset_all_seen(skel);
404 ASSERT_OK(system(ping_cmd), ping_cmd);
406 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
407 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
408 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
409 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
411 test_tc_link__destroy(skel);
412 assert_mprog_count(target, 0);
415 void serial_test_tc_links_after(void)
417 test_tc_links_after_target(BPF_TCX_INGRESS);
418 test_tc_links_after_target(BPF_TCX_EGRESS);
421 static void test_tc_links_revision_target(int target)
423 LIBBPF_OPTS(bpf_prog_query_opts, optq);
424 LIBBPF_OPTS(bpf_tcx_opts, optl);
425 __u32 prog_ids[3], link_ids[3];
426 __u32 pid1, pid2, lid1, lid2;
427 struct test_tc_link *skel;
428 struct bpf_link *link;
431 skel = test_tc_link__open();
432 if (!ASSERT_OK_PTR(skel, "skel_open"))
435 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
436 0, "tc1_attach_type");
437 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
438 0, "tc2_attach_type");
440 err = test_tc_link__load(skel);
441 if (!ASSERT_OK(err, "skel_load"))
444 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
445 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
447 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
449 assert_mprog_count(target, 0);
451 optl.expected_revision = 1;
453 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
454 if (!ASSERT_OK_PTR(link, "link_attach"))
457 skel->links.tc1 = link;
459 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
461 assert_mprog_count(target, 1);
463 optl.expected_revision = 1;
465 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
466 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
467 bpf_link__destroy(link);
471 assert_mprog_count(target, 1);
473 optl.expected_revision = 2;
475 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
476 if (!ASSERT_OK_PTR(link, "link_attach"))
479 skel->links.tc2 = link;
481 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
483 assert_mprog_count(target, 2);
485 optq.prog_ids = prog_ids;
486 optq.link_ids = link_ids;
488 memset(prog_ids, 0, sizeof(prog_ids));
489 memset(link_ids, 0, sizeof(link_ids));
490 optq.count = ARRAY_SIZE(prog_ids);
492 err = bpf_prog_query_opts(loopback, target, &optq);
493 if (!ASSERT_OK(err, "prog_query"))
496 ASSERT_EQ(optq.count, 2, "count");
497 ASSERT_EQ(optq.revision, 3, "revision");
498 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
499 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
500 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
501 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
502 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
503 ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");
505 tc_skel_reset_all_seen(skel);
506 ASSERT_OK(system(ping_cmd), ping_cmd);
508 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
509 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
511 test_tc_link__destroy(skel);
512 assert_mprog_count(target, 0);
515 void serial_test_tc_links_revision(void)
517 test_tc_links_revision_target(BPF_TCX_INGRESS);
518 test_tc_links_revision_target(BPF_TCX_EGRESS);
521 static void test_tc_chain_classic(int target, bool chain_tc_old)
523 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
524 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
525 bool hook_created = false, tc_attached = false;
526 LIBBPF_OPTS(bpf_tcx_opts, optl);
527 __u32 pid1, pid2, pid3;
528 struct test_tc_link *skel;
529 struct bpf_link *link;
532 skel = test_tc_link__open();
533 if (!ASSERT_OK_PTR(skel, "skel_open"))
536 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
537 0, "tc1_attach_type");
538 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
539 0, "tc2_attach_type");
541 err = test_tc_link__load(skel);
542 if (!ASSERT_OK(err, "skel_load"))
545 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
546 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
547 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
549 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
550 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
552 assert_mprog_count(target, 0);
555 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
556 BPF_TC_INGRESS : BPF_TC_EGRESS;
557 err = bpf_tc_hook_create(&tc_hook);
560 err = err == -EEXIST ? 0 : err;
561 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
564 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
565 err = bpf_tc_attach(&tc_hook, &tc_opts);
566 if (!ASSERT_OK(err, "bpf_tc_attach"))
571 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
572 if (!ASSERT_OK_PTR(link, "link_attach"))
575 skel->links.tc1 = link;
577 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
578 if (!ASSERT_OK_PTR(link, "link_attach"))
581 skel->links.tc2 = link;
583 assert_mprog_count(target, 2);
585 tc_skel_reset_all_seen(skel);
586 ASSERT_OK(system(ping_cmd), ping_cmd);
588 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
589 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
590 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
592 err = bpf_link__detach(skel->links.tc2);
593 if (!ASSERT_OK(err, "prog_detach"))
596 assert_mprog_count(target, 1);
598 tc_skel_reset_all_seen(skel);
599 ASSERT_OK(system(ping_cmd), ping_cmd);
601 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
602 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
603 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
606 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
607 err = bpf_tc_detach(&tc_hook, &tc_opts);
608 ASSERT_OK(err, "bpf_tc_detach");
611 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
612 bpf_tc_hook_destroy(&tc_hook);
614 assert_mprog_count(target, 1);
615 test_tc_link__destroy(skel);
616 assert_mprog_count(target, 0);
619 void serial_test_tc_links_chain_classic(void)
621 test_tc_chain_classic(BPF_TCX_INGRESS, false);
622 test_tc_chain_classic(BPF_TCX_EGRESS, false);
623 test_tc_chain_classic(BPF_TCX_INGRESS, true);
624 test_tc_chain_classic(BPF_TCX_EGRESS, true);
627 static void test_tc_links_replace_target(int target)
629 LIBBPF_OPTS(bpf_prog_query_opts, optq);
630 LIBBPF_OPTS(bpf_tcx_opts, optl);
631 __u32 pid1, pid2, pid3, lid1, lid2;
632 __u32 prog_ids[4], link_ids[4];
633 struct test_tc_link *skel;
634 struct bpf_link *link;
637 skel = test_tc_link__open();
638 if (!ASSERT_OK_PTR(skel, "skel_open"))
641 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
642 0, "tc1_attach_type");
643 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
644 0, "tc2_attach_type");
645 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
646 0, "tc3_attach_type");
648 err = test_tc_link__load(skel);
649 if (!ASSERT_OK(err, "skel_load"))
652 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
653 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
654 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
656 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
657 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
659 assert_mprog_count(target, 0);
661 optl.expected_revision = 1;
663 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
664 if (!ASSERT_OK_PTR(link, "link_attach"))
667 skel->links.tc1 = link;
669 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
671 assert_mprog_count(target, 1);
673 LIBBPF_OPTS_RESET(optl,
674 .flags = BPF_F_BEFORE,
676 .expected_revision = 2,
679 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
680 if (!ASSERT_OK_PTR(link, "link_attach"))
683 skel->links.tc2 = link;
685 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
687 assert_mprog_count(target, 2);
689 optq.prog_ids = prog_ids;
690 optq.link_ids = link_ids;
692 memset(prog_ids, 0, sizeof(prog_ids));
693 memset(link_ids, 0, sizeof(link_ids));
694 optq.count = ARRAY_SIZE(prog_ids);
696 err = bpf_prog_query_opts(loopback, target, &optq);
697 if (!ASSERT_OK(err, "prog_query"))
700 ASSERT_EQ(optq.count, 2, "count");
701 ASSERT_EQ(optq.revision, 3, "revision");
702 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
703 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
704 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
705 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
706 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
707 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
709 tc_skel_reset_all_seen(skel);
710 ASSERT_OK(system(ping_cmd), ping_cmd);
712 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
713 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
714 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
716 LIBBPF_OPTS_RESET(optl,
717 .flags = BPF_F_REPLACE,
718 .relative_fd = bpf_program__fd(skel->progs.tc2),
719 .expected_revision = 3,
722 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
723 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
724 bpf_link__destroy(link);
728 assert_mprog_count(target, 2);
730 LIBBPF_OPTS_RESET(optl,
731 .flags = BPF_F_REPLACE | BPF_F_LINK,
732 .relative_fd = bpf_link__fd(skel->links.tc2),
733 .expected_revision = 3,
736 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
737 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
738 bpf_link__destroy(link);
742 assert_mprog_count(target, 2);
744 LIBBPF_OPTS_RESET(optl,
745 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,
749 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
750 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
751 bpf_link__destroy(link);
755 assert_mprog_count(target, 2);
757 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);
758 if (!ASSERT_OK(err, "link_update"))
761 assert_mprog_count(target, 2);
763 memset(prog_ids, 0, sizeof(prog_ids));
764 memset(link_ids, 0, sizeof(link_ids));
765 optq.count = ARRAY_SIZE(prog_ids);
767 err = bpf_prog_query_opts(loopback, target, &optq);
768 if (!ASSERT_OK(err, "prog_query"))
771 ASSERT_EQ(optq.count, 2, "count");
772 ASSERT_EQ(optq.revision, 4, "revision");
773 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
774 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
775 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
776 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
777 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
778 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
780 tc_skel_reset_all_seen(skel);
781 ASSERT_OK(system(ping_cmd), ping_cmd);
783 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
784 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
785 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
787 err = bpf_link__detach(skel->links.tc2);
788 if (!ASSERT_OK(err, "link_detach"))
791 assert_mprog_count(target, 1);
793 memset(prog_ids, 0, sizeof(prog_ids));
794 memset(link_ids, 0, sizeof(link_ids));
795 optq.count = ARRAY_SIZE(prog_ids);
797 err = bpf_prog_query_opts(loopback, target, &optq);
798 if (!ASSERT_OK(err, "prog_query"))
801 ASSERT_EQ(optq.count, 1, "count");
802 ASSERT_EQ(optq.revision, 5, "revision");
803 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
804 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
805 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
806 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
808 tc_skel_reset_all_seen(skel);
809 ASSERT_OK(system(ping_cmd), ping_cmd);
811 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
812 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
813 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
815 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
816 if (!ASSERT_OK(err, "link_update_self"))
819 assert_mprog_count(target, 1);
821 memset(prog_ids, 0, sizeof(prog_ids));
822 memset(link_ids, 0, sizeof(link_ids));
823 optq.count = ARRAY_SIZE(prog_ids);
825 err = bpf_prog_query_opts(loopback, target, &optq);
826 if (!ASSERT_OK(err, "prog_query"))
829 ASSERT_EQ(optq.count, 1, "count");
830 ASSERT_EQ(optq.revision, 5, "revision");
831 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
832 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
833 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
834 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
836 tc_skel_reset_all_seen(skel);
837 ASSERT_OK(system(ping_cmd), ping_cmd);
839 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
840 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
841 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
843 test_tc_link__destroy(skel);
844 assert_mprog_count(target, 0);
847 void serial_test_tc_links_replace(void)
849 test_tc_links_replace_target(BPF_TCX_INGRESS);
850 test_tc_links_replace_target(BPF_TCX_EGRESS);
853 static void test_tc_links_invalid_target(int target)
855 LIBBPF_OPTS(bpf_prog_query_opts, optq);
856 LIBBPF_OPTS(bpf_tcx_opts, optl);
857 __u32 pid1, pid2, lid1;
858 struct test_tc_link *skel;
859 struct bpf_link *link;
862 skel = test_tc_link__open();
863 if (!ASSERT_OK_PTR(skel, "skel_open"))
866 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
867 0, "tc1_attach_type");
868 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
869 0, "tc2_attach_type");
871 err = test_tc_link__load(skel);
872 if (!ASSERT_OK(err, "skel_load"))
875 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
876 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
878 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
880 assert_mprog_count(target, 0);
882 optl.flags = BPF_F_BEFORE | BPF_F_AFTER;
884 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
885 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
886 bpf_link__destroy(link);
890 assert_mprog_count(target, 0);
892 LIBBPF_OPTS_RESET(optl,
893 .flags = BPF_F_BEFORE | BPF_F_ID,
896 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
897 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
898 bpf_link__destroy(link);
902 assert_mprog_count(target, 0);
904 LIBBPF_OPTS_RESET(optl,
905 .flags = BPF_F_AFTER | BPF_F_ID,
908 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
909 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
910 bpf_link__destroy(link);
914 assert_mprog_count(target, 0);
916 LIBBPF_OPTS_RESET(optl,
920 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
921 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
922 bpf_link__destroy(link);
926 assert_mprog_count(target, 0);
928 LIBBPF_OPTS_RESET(optl,
930 .relative_fd = bpf_program__fd(skel->progs.tc2),
933 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
934 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
935 bpf_link__destroy(link);
939 assert_mprog_count(target, 0);
941 LIBBPF_OPTS_RESET(optl,
945 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
946 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
947 bpf_link__destroy(link);
951 assert_mprog_count(target, 0);
953 LIBBPF_OPTS_RESET(optl,
954 .relative_fd = bpf_program__fd(skel->progs.tc2),
957 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
958 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
959 bpf_link__destroy(link);
963 assert_mprog_count(target, 0);
965 LIBBPF_OPTS_RESET(optl,
966 .flags = BPF_F_BEFORE | BPF_F_AFTER,
967 .relative_fd = bpf_program__fd(skel->progs.tc2),
970 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
971 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
972 bpf_link__destroy(link);
976 assert_mprog_count(target, 0);
978 LIBBPF_OPTS_RESET(optl,
979 .flags = BPF_F_BEFORE,
980 .relative_fd = bpf_program__fd(skel->progs.tc1),
983 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
984 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
985 bpf_link__destroy(link);
989 assert_mprog_count(target, 0);
991 LIBBPF_OPTS_RESET(optl,
996 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
997 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
998 bpf_link__destroy(link);
1002 assert_mprog_count(target, 0);
1004 LIBBPF_OPTS_RESET(optl,
1009 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1010 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1011 bpf_link__destroy(link);
1015 assert_mprog_count(target, 0);
1017 LIBBPF_OPTS_RESET(optl,
1018 .flags = BPF_F_BEFORE,
1019 .relative_fd = bpf_program__fd(skel->progs.tc1),
1022 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1023 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1024 bpf_link__destroy(link);
1028 assert_mprog_count(target, 0);
1030 LIBBPF_OPTS_RESET(optl,
1031 .flags = BPF_F_BEFORE | BPF_F_LINK,
1032 .relative_fd = bpf_program__fd(skel->progs.tc1),
1035 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1036 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1037 bpf_link__destroy(link);
1041 assert_mprog_count(target, 0);
1043 LIBBPF_OPTS_RESET(optl,
1044 .flags = BPF_F_AFTER,
1045 .relative_fd = bpf_program__fd(skel->progs.tc1),
1048 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1049 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1050 bpf_link__destroy(link);
1054 assert_mprog_count(target, 0);
1056 LIBBPF_OPTS_RESET(optl);
1058 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl);
1059 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1060 bpf_link__destroy(link);
1064 assert_mprog_count(target, 0);
1066 LIBBPF_OPTS_RESET(optl,
1067 .flags = BPF_F_AFTER | BPF_F_LINK,
1068 .relative_fd = bpf_program__fd(skel->progs.tc1),
1071 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1072 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1073 bpf_link__destroy(link);
1077 assert_mprog_count(target, 0);
1079 LIBBPF_OPTS_RESET(optl);
1081 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1082 if (!ASSERT_OK_PTR(link, "link_attach"))
1085 skel->links.tc1 = link;
1087 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1089 assert_mprog_count(target, 1);
1091 LIBBPF_OPTS_RESET(optl,
1092 .flags = BPF_F_AFTER | BPF_F_LINK,
1093 .relative_fd = bpf_program__fd(skel->progs.tc1),
1096 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1097 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1098 bpf_link__destroy(link);
1102 assert_mprog_count(target, 1);
1104 LIBBPF_OPTS_RESET(optl,
1105 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1109 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1110 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1111 bpf_link__destroy(link);
1115 assert_mprog_count(target, 1);
1117 LIBBPF_OPTS_RESET(optl,
1118 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1119 .relative_id = lid1,
1122 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1123 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1124 bpf_link__destroy(link);
1128 assert_mprog_count(target, 1);
1130 LIBBPF_OPTS_RESET(optl,
1131 .flags = BPF_F_BEFORE | BPF_F_ID,
1132 .relative_id = pid1,
1135 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1136 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1137 bpf_link__destroy(link);
1140 assert_mprog_count(target, 1);
1142 LIBBPF_OPTS_RESET(optl,
1143 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1144 .relative_id = lid1,
1147 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1148 if (!ASSERT_OK_PTR(link, "link_attach"))
1151 skel->links.tc2 = link;
1153 assert_mprog_count(target, 2);
1155 test_tc_link__destroy(skel);
1156 assert_mprog_count(target, 0);
1159 void serial_test_tc_links_invalid(void)
1161 test_tc_links_invalid_target(BPF_TCX_INGRESS);
1162 test_tc_links_invalid_target(BPF_TCX_EGRESS);
1165 static void test_tc_links_prepend_target(int target)
1167 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1168 LIBBPF_OPTS(bpf_tcx_opts, optl);
1169 __u32 prog_ids[5], link_ids[5];
1170 __u32 pid1, pid2, pid3, pid4;
1171 __u32 lid1, lid2, lid3, lid4;
1172 struct test_tc_link *skel;
1173 struct bpf_link *link;
1176 skel = test_tc_link__open();
1177 if (!ASSERT_OK_PTR(skel, "skel_open"))
1180 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1181 0, "tc1_attach_type");
1182 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1183 0, "tc2_attach_type");
1184 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1185 0, "tc3_attach_type");
1186 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1187 0, "tc4_attach_type");
1189 err = test_tc_link__load(skel);
1190 if (!ASSERT_OK(err, "skel_load"))
1193 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1194 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1195 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1196 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1198 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1199 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1200 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1202 assert_mprog_count(target, 0);
1204 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1205 if (!ASSERT_OK_PTR(link, "link_attach"))
1208 skel->links.tc1 = link;
1210 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1212 assert_mprog_count(target, 1);
1214 LIBBPF_OPTS_RESET(optl,
1215 .flags = BPF_F_BEFORE,
1218 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1219 if (!ASSERT_OK_PTR(link, "link_attach"))
1222 skel->links.tc2 = link;
1224 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1226 assert_mprog_count(target, 2);
1228 optq.prog_ids = prog_ids;
1229 optq.link_ids = link_ids;
1231 memset(prog_ids, 0, sizeof(prog_ids));
1232 memset(link_ids, 0, sizeof(link_ids));
1233 optq.count = ARRAY_SIZE(prog_ids);
1235 err = bpf_prog_query_opts(loopback, target, &optq);
1236 if (!ASSERT_OK(err, "prog_query"))
1239 ASSERT_EQ(optq.count, 2, "count");
1240 ASSERT_EQ(optq.revision, 3, "revision");
1241 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
1242 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
1243 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
1244 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
1245 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1246 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1248 tc_skel_reset_all_seen(skel);
1249 ASSERT_OK(system(ping_cmd), ping_cmd);
1251 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1252 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1253 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1254 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1256 LIBBPF_OPTS_RESET(optl,
1257 .flags = BPF_F_BEFORE,
1260 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1261 if (!ASSERT_OK_PTR(link, "link_attach"))
1264 skel->links.tc3 = link;
1266 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1268 LIBBPF_OPTS_RESET(optl,
1269 .flags = BPF_F_BEFORE,
1272 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1273 if (!ASSERT_OK_PTR(link, "link_attach"))
1276 skel->links.tc4 = link;
1278 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1280 assert_mprog_count(target, 4);
1282 memset(prog_ids, 0, sizeof(prog_ids));
1283 memset(link_ids, 0, sizeof(link_ids));
1284 optq.count = ARRAY_SIZE(prog_ids);
1286 err = bpf_prog_query_opts(loopback, target, &optq);
1287 if (!ASSERT_OK(err, "prog_query"))
1290 ASSERT_EQ(optq.count, 4, "count");
1291 ASSERT_EQ(optq.revision, 5, "revision");
1292 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
1293 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
1294 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
1295 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
1296 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
1297 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
1298 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]");
1299 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]");
1300 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1301 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1303 tc_skel_reset_all_seen(skel);
1304 ASSERT_OK(system(ping_cmd), ping_cmd);
1306 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1307 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1308 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1309 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1311 test_tc_link__destroy(skel);
1312 assert_mprog_count(target, 0);
1315 void serial_test_tc_links_prepend(void)
1317 test_tc_links_prepend_target(BPF_TCX_INGRESS);
1318 test_tc_links_prepend_target(BPF_TCX_EGRESS);
1321 static void test_tc_links_append_target(int target)
1323 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1324 LIBBPF_OPTS(bpf_tcx_opts, optl);
1325 __u32 prog_ids[5], link_ids[5];
1326 __u32 pid1, pid2, pid3, pid4;
1327 __u32 lid1, lid2, lid3, lid4;
1328 struct test_tc_link *skel;
1329 struct bpf_link *link;
1332 skel = test_tc_link__open();
1333 if (!ASSERT_OK_PTR(skel, "skel_open"))
1336 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1337 0, "tc1_attach_type");
1338 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1339 0, "tc2_attach_type");
1340 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1341 0, "tc3_attach_type");
1342 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1343 0, "tc4_attach_type");
1345 err = test_tc_link__load(skel);
1346 if (!ASSERT_OK(err, "skel_load"))
1349 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1350 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1351 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1352 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1354 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1355 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1356 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1358 assert_mprog_count(target, 0);
1360 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1361 if (!ASSERT_OK_PTR(link, "link_attach"))
1364 skel->links.tc1 = link;
1366 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1368 assert_mprog_count(target, 1);
1370 LIBBPF_OPTS_RESET(optl,
1371 .flags = BPF_F_AFTER,
1374 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1375 if (!ASSERT_OK_PTR(link, "link_attach"))
1378 skel->links.tc2 = link;
1380 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1382 assert_mprog_count(target, 2);
1384 optq.prog_ids = prog_ids;
1385 optq.link_ids = link_ids;
1387 memset(prog_ids, 0, sizeof(prog_ids));
1388 memset(link_ids, 0, sizeof(link_ids));
1389 optq.count = ARRAY_SIZE(prog_ids);
1391 err = bpf_prog_query_opts(loopback, target, &optq);
1392 if (!ASSERT_OK(err, "prog_query"))
1395 ASSERT_EQ(optq.count, 2, "count");
1396 ASSERT_EQ(optq.revision, 3, "revision");
1397 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1398 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1399 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1400 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1401 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1402 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1404 tc_skel_reset_all_seen(skel);
1405 ASSERT_OK(system(ping_cmd), ping_cmd);
1407 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1408 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1409 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1410 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1412 LIBBPF_OPTS_RESET(optl,
1413 .flags = BPF_F_AFTER,
1416 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1417 if (!ASSERT_OK_PTR(link, "link_attach"))
1420 skel->links.tc3 = link;
1422 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1424 LIBBPF_OPTS_RESET(optl,
1425 .flags = BPF_F_AFTER,
1428 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1429 if (!ASSERT_OK_PTR(link, "link_attach"))
1432 skel->links.tc4 = link;
1434 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1436 assert_mprog_count(target, 4);
1438 memset(prog_ids, 0, sizeof(prog_ids));
1439 memset(link_ids, 0, sizeof(link_ids));
1440 optq.count = ARRAY_SIZE(prog_ids);
1442 err = bpf_prog_query_opts(loopback, target, &optq);
1443 if (!ASSERT_OK(err, "prog_query"))
1446 ASSERT_EQ(optq.count, 4, "count");
1447 ASSERT_EQ(optq.revision, 5, "revision");
1448 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1449 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1450 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1451 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1452 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
1453 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
1454 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
1455 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
1456 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1457 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1459 tc_skel_reset_all_seen(skel);
1460 ASSERT_OK(system(ping_cmd), ping_cmd);
1462 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1463 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1464 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1465 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1467 test_tc_link__destroy(skel);
1468 assert_mprog_count(target, 0);
1471 void serial_test_tc_links_append(void)
1473 test_tc_links_append_target(BPF_TCX_INGRESS);
1474 test_tc_links_append_target(BPF_TCX_EGRESS);
1477 static void test_tc_links_dev_cleanup_target(int target)
1479 LIBBPF_OPTS(bpf_tcx_opts, optl);
1480 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1481 __u32 pid1, pid2, pid3, pid4;
1482 struct test_tc_link *skel;
1483 struct bpf_link *link;
1486 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1487 ifindex = if_nametoindex("tcx_opts1");
1488 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1490 skel = test_tc_link__open();
1491 if (!ASSERT_OK_PTR(skel, "skel_open"))
1494 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1495 0, "tc1_attach_type");
1496 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1497 0, "tc2_attach_type");
1498 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1499 0, "tc3_attach_type");
1500 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1501 0, "tc4_attach_type");
1503 err = test_tc_link__load(skel);
1504 if (!ASSERT_OK(err, "skel_load"))
1507 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1508 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1509 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1510 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1512 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1513 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1514 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1516 assert_mprog_count(target, 0);
1518 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1519 if (!ASSERT_OK_PTR(link, "link_attach"))
1522 skel->links.tc1 = link;
1524 assert_mprog_count_ifindex(ifindex, target, 1);
1526 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1527 if (!ASSERT_OK_PTR(link, "link_attach"))
1530 skel->links.tc2 = link;
1532 assert_mprog_count_ifindex(ifindex, target, 2);
1534 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1535 if (!ASSERT_OK_PTR(link, "link_attach"))
1538 skel->links.tc3 = link;
1540 assert_mprog_count_ifindex(ifindex, target, 3);
1542 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1543 if (!ASSERT_OK_PTR(link, "link_attach"))
1546 skel->links.tc4 = link;
1548 assert_mprog_count_ifindex(ifindex, target, 4);
1550 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1551 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1552 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1554 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1555 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1556 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1557 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1559 test_tc_link__destroy(skel);
1562 test_tc_link__destroy(skel);
1564 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1565 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1566 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1569 void serial_test_tc_links_dev_cleanup(void)
1571 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);
1572 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);
1575 static void test_tc_chain_mixed(int target)
1577 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1578 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
1579 LIBBPF_OPTS(bpf_tcx_opts, optl);
1580 struct test_tc_link *skel;
1581 struct bpf_link *link;
1582 __u32 pid1, pid2, pid3;
1585 skel = test_tc_link__open();
1586 if (!ASSERT_OK_PTR(skel, "skel_open"))
1589 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1590 0, "tc4_attach_type");
1591 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),
1592 0, "tc5_attach_type");
1593 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),
1594 0, "tc6_attach_type");
1596 err = test_tc_link__load(skel);
1597 if (!ASSERT_OK(err, "skel_load"))
1600 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1601 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));
1602 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));
1604 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1605 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1607 assert_mprog_count(target, 0);
1609 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1610 BPF_TC_INGRESS : BPF_TC_EGRESS;
1611 err = bpf_tc_hook_create(&tc_hook);
1612 err = err == -EEXIST ? 0 : err;
1613 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1616 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1617 err = bpf_tc_attach(&tc_hook, &tc_opts);
1618 if (!ASSERT_OK(err, "bpf_tc_attach"))
1621 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);
1622 if (!ASSERT_OK_PTR(link, "link_attach"))
1625 skel->links.tc6 = link;
1627 assert_mprog_count(target, 1);
1629 tc_skel_reset_all_seen(skel);
1630 ASSERT_OK(system(ping_cmd), ping_cmd);
1632 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1633 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
1634 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
1636 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
1637 if (!ASSERT_OK(err, "link_update"))
1640 assert_mprog_count(target, 1);
1642 tc_skel_reset_all_seen(skel);
1643 ASSERT_OK(system(ping_cmd), ping_cmd);
1645 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1646 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1647 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1649 err = bpf_link__detach(skel->links.tc6);
1650 if (!ASSERT_OK(err, "prog_detach"))
1653 assert_mprog_count(target, 0);
1655 tc_skel_reset_all_seen(skel);
1656 ASSERT_OK(system(ping_cmd), ping_cmd);
1658 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1659 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1660 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1663 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1664 err = bpf_tc_detach(&tc_hook, &tc_opts);
1665 ASSERT_OK(err, "bpf_tc_detach");
1667 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
1668 bpf_tc_hook_destroy(&tc_hook);
1670 test_tc_link__destroy(skel);
1673 void serial_test_tc_links_chain_mixed(void)
1675 test_tc_chain_mixed(BPF_TCX_INGRESS);
1676 test_tc_chain_mixed(BPF_TCX_EGRESS);
1679 static void test_tc_links_ingress(int target, bool chain_tc_old,
1680 bool tcx_teardown_first)
1682 LIBBPF_OPTS(bpf_tc_opts, tc_opts,
1686 LIBBPF_OPTS(bpf_tc_hook, tc_hook,
1687 .ifindex = loopback,
1688 .attach_point = BPF_TC_CUSTOM,
1689 .parent = TC_H_INGRESS,
1691 bool hook_created = false, tc_attached = false;
1692 LIBBPF_OPTS(bpf_tcx_opts, optl);
1693 __u32 pid1, pid2, pid3;
1694 struct test_tc_link *skel;
1695 struct bpf_link *link;
1698 skel = test_tc_link__open();
1699 if (!ASSERT_OK_PTR(skel, "skel_open"))
1702 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1703 0, "tc1_attach_type");
1704 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1705 0, "tc2_attach_type");
1707 err = test_tc_link__load(skel);
1708 if (!ASSERT_OK(err, "skel_load"))
1711 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1712 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1713 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1715 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1716 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1718 assert_mprog_count(target, 0);
1721 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");
1722 hook_created = true;
1724 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
1725 err = bpf_tc_attach(&tc_hook, &tc_opts);
1726 if (!ASSERT_OK(err, "bpf_tc_attach"))
1731 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1732 if (!ASSERT_OK_PTR(link, "link_attach"))
1735 skel->links.tc1 = link;
1737 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1738 if (!ASSERT_OK_PTR(link, "link_attach"))
1741 skel->links.tc2 = link;
1743 assert_mprog_count(target, 2);
1745 tc_skel_reset_all_seen(skel);
1746 ASSERT_OK(system(ping_cmd), ping_cmd);
1748 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1749 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1750 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1752 err = bpf_link__detach(skel->links.tc2);
1753 if (!ASSERT_OK(err, "prog_detach"))
1756 assert_mprog_count(target, 1);
1758 tc_skel_reset_all_seen(skel);
1759 ASSERT_OK(system(ping_cmd), ping_cmd);
1761 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1762 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
1763 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1766 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1767 err = bpf_tc_detach(&tc_hook, &tc_opts);
1768 ASSERT_OK(err, "bpf_tc_detach");
1770 ASSERT_OK(system(ping_cmd), ping_cmd);
1771 assert_mprog_count(target, 1);
1772 if (hook_created && tcx_teardown_first)
1773 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1774 ASSERT_OK(system(ping_cmd), ping_cmd);
1775 test_tc_link__destroy(skel);
1776 ASSERT_OK(system(ping_cmd), ping_cmd);
1777 if (hook_created && !tcx_teardown_first)
1778 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1779 ASSERT_OK(system(ping_cmd), ping_cmd);
1780 assert_mprog_count(target, 0);
1783 void serial_test_tc_links_ingress(void)
1785 test_tc_links_ingress(BPF_TCX_INGRESS, true, true);
1786 test_tc_links_ingress(BPF_TCX_INGRESS, true, false);
1787 test_tc_links_ingress(BPF_TCX_INGRESS, false, false);
1790 static void test_tc_links_dev_mixed(int target)
1792 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1793 LIBBPF_OPTS(bpf_tc_hook, tc_hook);
1794 LIBBPF_OPTS(bpf_tcx_opts, optl);
1795 __u32 pid1, pid2, pid3, pid4;
1796 struct test_tc_link *skel;
1797 struct bpf_link *link;
1800 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1801 ifindex = if_nametoindex("tcx_opts1");
1802 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1804 skel = test_tc_link__open();
1805 if (!ASSERT_OK_PTR(skel, "skel_open"))
1808 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1809 0, "tc1_attach_type");
1810 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1811 0, "tc2_attach_type");
1812 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1813 0, "tc3_attach_type");
1814 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1815 0, "tc4_attach_type");
1817 err = test_tc_link__load(skel);
1818 if (!ASSERT_OK(err, "skel_load"))
1821 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1822 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1823 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1824 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1826 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1827 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1828 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1830 assert_mprog_count(target, 0);
1832 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1833 if (!ASSERT_OK_PTR(link, "link_attach"))
1836 skel->links.tc1 = link;
1838 assert_mprog_count_ifindex(ifindex, target, 1);
1840 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1841 if (!ASSERT_OK_PTR(link, "link_attach"))
1844 skel->links.tc2 = link;
1846 assert_mprog_count_ifindex(ifindex, target, 2);
1848 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1849 if (!ASSERT_OK_PTR(link, "link_attach"))
1852 skel->links.tc3 = link;
1854 assert_mprog_count_ifindex(ifindex, target, 3);
1856 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1857 if (!ASSERT_OK_PTR(link, "link_attach"))
1860 skel->links.tc4 = link;
1862 assert_mprog_count_ifindex(ifindex, target, 4);
1864 tc_hook.ifindex = ifindex;
1865 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1866 BPF_TC_INGRESS : BPF_TC_EGRESS;
1868 err = bpf_tc_hook_create(&tc_hook);
1869 err = err == -EEXIST ? 0 : err;
1870 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1873 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1874 err = bpf_tc_attach(&tc_hook, &tc_opts);
1875 if (!ASSERT_OK(err, "bpf_tc_attach"))
1878 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1879 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1880 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1882 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1883 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1884 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1885 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1887 test_tc_link__destroy(skel);
1890 test_tc_link__destroy(skel);
1892 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1893 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1894 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1897 void serial_test_tc_links_dev_mixed(void)
1899 test_tc_links_dev_mixed(BPF_TCX_INGRESS);
1900 test_tc_links_dev_mixed(BPF_TCX_EGRESS);