Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2023 Isovalent */
3#include <uapi/linux/if_link.h>
4#include <uapi/linux/pkt_sched.h>
5#include <net/if.h>
6#include <test_progs.h>
7
8#define loopback 1
9#define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"
10
11#include "test_tc_link.skel.h"
12#include "tc_helpers.h"
13
14void serial_test_tc_links_basic(void)
15{
16 LIBBPF_OPTS(bpf_prog_query_opts, optq);
17 LIBBPF_OPTS(bpf_tcx_opts, optl);
18 __u32 prog_ids[2], link_ids[2];
19 __u32 pid1, pid2, lid1, lid2;
20 struct test_tc_link *skel;
21 struct bpf_link *link;
22 int err;
23
24 skel = test_tc_link__open_and_load();
25 if (!ASSERT_OK_PTR(skel, "skel_load"))
26 goto cleanup;
27
28 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
29 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
30
31 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
32
33 assert_mprog_count(BPF_TCX_INGRESS, 0);
34 assert_mprog_count(BPF_TCX_EGRESS, 0);
35
36 ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
37 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
38
39 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
40 if (!ASSERT_OK_PTR(link, "link_attach"))
41 goto cleanup;
42
43 skel->links.tc1 = link;
44
45 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
46
47 assert_mprog_count(BPF_TCX_INGRESS, 1);
48 assert_mprog_count(BPF_TCX_EGRESS, 0);
49
50 optq.prog_ids = prog_ids;
51 optq.link_ids = link_ids;
52
53 memset(prog_ids, 0, sizeof(prog_ids));
54 memset(link_ids, 0, sizeof(link_ids));
55 optq.count = ARRAY_SIZE(prog_ids);
56
57 err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);
58 if (!ASSERT_OK(err, "prog_query"))
59 goto cleanup;
60
61 ASSERT_EQ(optq.count, 1, "count");
62 ASSERT_EQ(optq.revision, 2, "revision");
63 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
64 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
65 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
66 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
67
68 ASSERT_OK(system(ping_cmd), ping_cmd);
69
70 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
71 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
72
73 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
74 if (!ASSERT_OK_PTR(link, "link_attach"))
75 goto cleanup;
76
77 skel->links.tc2 = link;
78
79 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
80 ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
81
82 assert_mprog_count(BPF_TCX_INGRESS, 1);
83 assert_mprog_count(BPF_TCX_EGRESS, 1);
84
85 memset(prog_ids, 0, sizeof(prog_ids));
86 memset(link_ids, 0, sizeof(link_ids));
87 optq.count = ARRAY_SIZE(prog_ids);
88
89 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
90 if (!ASSERT_OK(err, "prog_query"))
91 goto cleanup;
92
93 ASSERT_EQ(optq.count, 1, "count");
94 ASSERT_EQ(optq.revision, 2, "revision");
95 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
96 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
97 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
98 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
99
100 ASSERT_OK(system(ping_cmd), ping_cmd);
101
102 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
103 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
104cleanup:
105 test_tc_link__destroy(skel);
106
107 assert_mprog_count(BPF_TCX_INGRESS, 0);
108 assert_mprog_count(BPF_TCX_EGRESS, 0);
109}
110
111static void test_tc_links_before_target(int target)
112{
113 LIBBPF_OPTS(bpf_prog_query_opts, optq);
114 LIBBPF_OPTS(bpf_tcx_opts, optl);
115 __u32 prog_ids[5], link_ids[5];
116 __u32 pid1, pid2, pid3, pid4;
117 __u32 lid1, lid2, lid3, lid4;
118 struct test_tc_link *skel;
119 struct bpf_link *link;
120 int err;
121
122 skel = test_tc_link__open();
123 if (!ASSERT_OK_PTR(skel, "skel_open"))
124 goto cleanup;
125
126 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
127 0, "tc1_attach_type");
128 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
129 0, "tc2_attach_type");
130 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
131 0, "tc3_attach_type");
132 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
133 0, "tc4_attach_type");
134
135 err = test_tc_link__load(skel);
136 if (!ASSERT_OK(err, "skel_load"))
137 goto cleanup;
138
139 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
140 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
141 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
142 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
143
144 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
145 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
146 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
147
148 assert_mprog_count(target, 0);
149
150 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
151 if (!ASSERT_OK_PTR(link, "link_attach"))
152 goto cleanup;
153
154 skel->links.tc1 = link;
155
156 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
157
158 assert_mprog_count(target, 1);
159
160 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
161 if (!ASSERT_OK_PTR(link, "link_attach"))
162 goto cleanup;
163
164 skel->links.tc2 = link;
165
166 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
167
168 assert_mprog_count(target, 2);
169
170 optq.prog_ids = prog_ids;
171 optq.link_ids = link_ids;
172
173 memset(prog_ids, 0, sizeof(prog_ids));
174 memset(link_ids, 0, sizeof(link_ids));
175 optq.count = ARRAY_SIZE(prog_ids);
176
177 err = bpf_prog_query_opts(loopback, target, &optq);
178 if (!ASSERT_OK(err, "prog_query"))
179 goto cleanup;
180
181 ASSERT_EQ(optq.count, 2, "count");
182 ASSERT_EQ(optq.revision, 3, "revision");
183 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
184 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
185 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
186 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
187 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
188 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
189
190 ASSERT_OK(system(ping_cmd), ping_cmd);
191
192 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
193 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
194 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
195 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
196
197 skel->bss->seen_tc1 = false;
198 skel->bss->seen_tc2 = false;
199
200 LIBBPF_OPTS_RESET(optl,
201 .flags = BPF_F_BEFORE,
202 .relative_fd = bpf_program__fd(skel->progs.tc2),
203 );
204
205 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
206 if (!ASSERT_OK_PTR(link, "link_attach"))
207 goto cleanup;
208
209 skel->links.tc3 = link;
210
211 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
212
213 LIBBPF_OPTS_RESET(optl,
214 .flags = BPF_F_BEFORE | BPF_F_LINK,
215 .relative_id = lid1,
216 );
217
218 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
219 if (!ASSERT_OK_PTR(link, "link_attach"))
220 goto cleanup;
221
222 skel->links.tc4 = link;
223
224 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
225
226 assert_mprog_count(target, 4);
227
228 memset(prog_ids, 0, sizeof(prog_ids));
229 memset(link_ids, 0, sizeof(link_ids));
230 optq.count = ARRAY_SIZE(prog_ids);
231
232 err = bpf_prog_query_opts(loopback, target, &optq);
233 if (!ASSERT_OK(err, "prog_query"))
234 goto cleanup;
235
236 ASSERT_EQ(optq.count, 4, "count");
237 ASSERT_EQ(optq.revision, 5, "revision");
238 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
239 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
240 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
241 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
242 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
243 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
244 ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]");
245 ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]");
246 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
247 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
248
249 ASSERT_OK(system(ping_cmd), ping_cmd);
250
251 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
252 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
253 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
254 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
255cleanup:
256 test_tc_link__destroy(skel);
257 assert_mprog_count(target, 0);
258}
259
260void serial_test_tc_links_before(void)
261{
262 test_tc_links_before_target(BPF_TCX_INGRESS);
263 test_tc_links_before_target(BPF_TCX_EGRESS);
264}
265
266static void test_tc_links_after_target(int target)
267{
268 LIBBPF_OPTS(bpf_prog_query_opts, optq);
269 LIBBPF_OPTS(bpf_tcx_opts, optl);
270 __u32 prog_ids[5], link_ids[5];
271 __u32 pid1, pid2, pid3, pid4;
272 __u32 lid1, lid2, lid3, lid4;
273 struct test_tc_link *skel;
274 struct bpf_link *link;
275 int err;
276
277 skel = test_tc_link__open();
278 if (!ASSERT_OK_PTR(skel, "skel_open"))
279 goto cleanup;
280
281 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
282 0, "tc1_attach_type");
283 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
284 0, "tc2_attach_type");
285 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
286 0, "tc3_attach_type");
287 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
288 0, "tc4_attach_type");
289
290 err = test_tc_link__load(skel);
291 if (!ASSERT_OK(err, "skel_load"))
292 goto cleanup;
293
294 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
295 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
296 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
297 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
298
299 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
300 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
301 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
302
303 assert_mprog_count(target, 0);
304
305 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
306 if (!ASSERT_OK_PTR(link, "link_attach"))
307 goto cleanup;
308
309 skel->links.tc1 = link;
310
311 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
312
313 assert_mprog_count(target, 1);
314
315 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
316 if (!ASSERT_OK_PTR(link, "link_attach"))
317 goto cleanup;
318
319 skel->links.tc2 = link;
320
321 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
322
323 assert_mprog_count(target, 2);
324
325 optq.prog_ids = prog_ids;
326 optq.link_ids = link_ids;
327
328 memset(prog_ids, 0, sizeof(prog_ids));
329 memset(link_ids, 0, sizeof(link_ids));
330 optq.count = ARRAY_SIZE(prog_ids);
331
332 err = bpf_prog_query_opts(loopback, target, &optq);
333 if (!ASSERT_OK(err, "prog_query"))
334 goto cleanup;
335
336 ASSERT_EQ(optq.count, 2, "count");
337 ASSERT_EQ(optq.revision, 3, "revision");
338 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
339 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
340 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
341 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
342 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
343 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
344
345 ASSERT_OK(system(ping_cmd), ping_cmd);
346
347 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
348 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
349 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
350 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
351
352 skel->bss->seen_tc1 = false;
353 skel->bss->seen_tc2 = false;
354
355 LIBBPF_OPTS_RESET(optl,
356 .flags = BPF_F_AFTER,
357 .relative_fd = bpf_program__fd(skel->progs.tc1),
358 );
359
360 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
361 if (!ASSERT_OK_PTR(link, "link_attach"))
362 goto cleanup;
363
364 skel->links.tc3 = link;
365
366 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
367
368 LIBBPF_OPTS_RESET(optl,
369 .flags = BPF_F_AFTER | BPF_F_LINK,
370 .relative_fd = bpf_link__fd(skel->links.tc2),
371 );
372
373 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
374 if (!ASSERT_OK_PTR(link, "link_attach"))
375 goto cleanup;
376
377 skel->links.tc4 = link;
378
379 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
380
381 assert_mprog_count(target, 4);
382
383 memset(prog_ids, 0, sizeof(prog_ids));
384 memset(link_ids, 0, sizeof(link_ids));
385 optq.count = ARRAY_SIZE(prog_ids);
386
387 err = bpf_prog_query_opts(loopback, target, &optq);
388 if (!ASSERT_OK(err, "prog_query"))
389 goto cleanup;
390
391 ASSERT_EQ(optq.count, 4, "count");
392 ASSERT_EQ(optq.revision, 5, "revision");
393 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
394 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
395 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
396 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
397 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
398 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
399 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
400 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
401 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
402 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
403
404 ASSERT_OK(system(ping_cmd), ping_cmd);
405
406 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
407 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
408 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
409 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
410cleanup:
411 test_tc_link__destroy(skel);
412 assert_mprog_count(target, 0);
413}
414
415void serial_test_tc_links_after(void)
416{
417 test_tc_links_after_target(BPF_TCX_INGRESS);
418 test_tc_links_after_target(BPF_TCX_EGRESS);
419}
420
421static void test_tc_links_revision_target(int target)
422{
423 LIBBPF_OPTS(bpf_prog_query_opts, optq);
424 LIBBPF_OPTS(bpf_tcx_opts, optl);
425 __u32 prog_ids[3], link_ids[3];
426 __u32 pid1, pid2, lid1, lid2;
427 struct test_tc_link *skel;
428 struct bpf_link *link;
429 int err;
430
431 skel = test_tc_link__open();
432 if (!ASSERT_OK_PTR(skel, "skel_open"))
433 goto cleanup;
434
435 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
436 0, "tc1_attach_type");
437 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
438 0, "tc2_attach_type");
439
440 err = test_tc_link__load(skel);
441 if (!ASSERT_OK(err, "skel_load"))
442 goto cleanup;
443
444 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
445 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
446
447 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
448
449 assert_mprog_count(target, 0);
450
451 optl.expected_revision = 1;
452
453 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
454 if (!ASSERT_OK_PTR(link, "link_attach"))
455 goto cleanup;
456
457 skel->links.tc1 = link;
458
459 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
460
461 assert_mprog_count(target, 1);
462
463 optl.expected_revision = 1;
464
465 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
466 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
467 bpf_link__destroy(link);
468 goto cleanup;
469 }
470
471 assert_mprog_count(target, 1);
472
473 optl.expected_revision = 2;
474
475 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
476 if (!ASSERT_OK_PTR(link, "link_attach"))
477 goto cleanup;
478
479 skel->links.tc2 = link;
480
481 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
482
483 assert_mprog_count(target, 2);
484
485 optq.prog_ids = prog_ids;
486 optq.link_ids = link_ids;
487
488 memset(prog_ids, 0, sizeof(prog_ids));
489 memset(link_ids, 0, sizeof(link_ids));
490 optq.count = ARRAY_SIZE(prog_ids);
491
492 err = bpf_prog_query_opts(loopback, target, &optq);
493 if (!ASSERT_OK(err, "prog_query"))
494 goto cleanup;
495
496 ASSERT_EQ(optq.count, 2, "count");
497 ASSERT_EQ(optq.revision, 3, "revision");
498 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
499 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
500 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
501 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
502 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
503 ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");
504
505 ASSERT_OK(system(ping_cmd), ping_cmd);
506
507 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
508 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
509cleanup:
510 test_tc_link__destroy(skel);
511 assert_mprog_count(target, 0);
512}
513
514void serial_test_tc_links_revision(void)
515{
516 test_tc_links_revision_target(BPF_TCX_INGRESS);
517 test_tc_links_revision_target(BPF_TCX_EGRESS);
518}
519
520static void test_tc_chain_classic(int target, bool chain_tc_old)
521{
522 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
523 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
524 bool hook_created = false, tc_attached = false;
525 LIBBPF_OPTS(bpf_tcx_opts, optl);
526 __u32 pid1, pid2, pid3;
527 struct test_tc_link *skel;
528 struct bpf_link *link;
529 int err;
530
531 skel = test_tc_link__open();
532 if (!ASSERT_OK_PTR(skel, "skel_open"))
533 goto cleanup;
534
535 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
536 0, "tc1_attach_type");
537 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
538 0, "tc2_attach_type");
539
540 err = test_tc_link__load(skel);
541 if (!ASSERT_OK(err, "skel_load"))
542 goto cleanup;
543
544 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
545 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
546 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
547
548 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
549 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
550
551 assert_mprog_count(target, 0);
552
553 if (chain_tc_old) {
554 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
555 BPF_TC_INGRESS : BPF_TC_EGRESS;
556 err = bpf_tc_hook_create(&tc_hook);
557 if (err == 0)
558 hook_created = true;
559 err = err == -EEXIST ? 0 : err;
560 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
561 goto cleanup;
562
563 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
564 err = bpf_tc_attach(&tc_hook, &tc_opts);
565 if (!ASSERT_OK(err, "bpf_tc_attach"))
566 goto cleanup;
567 tc_attached = true;
568 }
569
570 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
571 if (!ASSERT_OK_PTR(link, "link_attach"))
572 goto cleanup;
573
574 skel->links.tc1 = link;
575
576 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
577 if (!ASSERT_OK_PTR(link, "link_attach"))
578 goto cleanup;
579
580 skel->links.tc2 = link;
581
582 assert_mprog_count(target, 2);
583
584 ASSERT_OK(system(ping_cmd), ping_cmd);
585
586 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
587 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
588 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
589
590 skel->bss->seen_tc1 = false;
591 skel->bss->seen_tc2 = false;
592 skel->bss->seen_tc3 = false;
593
594 err = bpf_link__detach(skel->links.tc2);
595 if (!ASSERT_OK(err, "prog_detach"))
596 goto cleanup;
597
598 assert_mprog_count(target, 1);
599
600 ASSERT_OK(system(ping_cmd), ping_cmd);
601
602 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
603 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
604 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
605cleanup:
606 if (tc_attached) {
607 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
608 err = bpf_tc_detach(&tc_hook, &tc_opts);
609 ASSERT_OK(err, "bpf_tc_detach");
610 }
611 if (hook_created) {
612 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
613 bpf_tc_hook_destroy(&tc_hook);
614 }
615 assert_mprog_count(target, 1);
616 test_tc_link__destroy(skel);
617 assert_mprog_count(target, 0);
618}
619
620void serial_test_tc_links_chain_classic(void)
621{
622 test_tc_chain_classic(BPF_TCX_INGRESS, false);
623 test_tc_chain_classic(BPF_TCX_EGRESS, false);
624 test_tc_chain_classic(BPF_TCX_INGRESS, true);
625 test_tc_chain_classic(BPF_TCX_EGRESS, true);
626}
627
628static void test_tc_links_replace_target(int target)
629{
630 LIBBPF_OPTS(bpf_prog_query_opts, optq);
631 LIBBPF_OPTS(bpf_tcx_opts, optl);
632 __u32 pid1, pid2, pid3, lid1, lid2;
633 __u32 prog_ids[4], link_ids[4];
634 struct test_tc_link *skel;
635 struct bpf_link *link;
636 int err;
637
638 skel = test_tc_link__open();
639 if (!ASSERT_OK_PTR(skel, "skel_open"))
640 goto cleanup;
641
642 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
643 0, "tc1_attach_type");
644 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
645 0, "tc2_attach_type");
646 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
647 0, "tc3_attach_type");
648
649 err = test_tc_link__load(skel);
650 if (!ASSERT_OK(err, "skel_load"))
651 goto cleanup;
652
653 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
654 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
655 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
656
657 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
658 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
659
660 assert_mprog_count(target, 0);
661
662 optl.expected_revision = 1;
663
664 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
665 if (!ASSERT_OK_PTR(link, "link_attach"))
666 goto cleanup;
667
668 skel->links.tc1 = link;
669
670 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
671
672 assert_mprog_count(target, 1);
673
674 LIBBPF_OPTS_RESET(optl,
675 .flags = BPF_F_BEFORE,
676 .relative_id = pid1,
677 .expected_revision = 2,
678 );
679
680 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
681 if (!ASSERT_OK_PTR(link, "link_attach"))
682 goto cleanup;
683
684 skel->links.tc2 = link;
685
686 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
687
688 assert_mprog_count(target, 2);
689
690 optq.prog_ids = prog_ids;
691 optq.link_ids = link_ids;
692
693 memset(prog_ids, 0, sizeof(prog_ids));
694 memset(link_ids, 0, sizeof(link_ids));
695 optq.count = ARRAY_SIZE(prog_ids);
696
697 err = bpf_prog_query_opts(loopback, target, &optq);
698 if (!ASSERT_OK(err, "prog_query"))
699 goto cleanup;
700
701 ASSERT_EQ(optq.count, 2, "count");
702 ASSERT_EQ(optq.revision, 3, "revision");
703 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
704 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
705 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
706 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
707 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
708 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
709
710 ASSERT_OK(system(ping_cmd), ping_cmd);
711
712 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
713 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
714 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
715
716 skel->bss->seen_tc1 = false;
717 skel->bss->seen_tc2 = false;
718 skel->bss->seen_tc3 = false;
719
720 LIBBPF_OPTS_RESET(optl,
721 .flags = BPF_F_REPLACE,
722 .relative_fd = bpf_program__fd(skel->progs.tc2),
723 .expected_revision = 3,
724 );
725
726 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
727 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
728 bpf_link__destroy(link);
729 goto cleanup;
730 }
731
732 assert_mprog_count(target, 2);
733
734 LIBBPF_OPTS_RESET(optl,
735 .flags = BPF_F_REPLACE | BPF_F_LINK,
736 .relative_fd = bpf_link__fd(skel->links.tc2),
737 .expected_revision = 3,
738 );
739
740 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
741 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
742 bpf_link__destroy(link);
743 goto cleanup;
744 }
745
746 assert_mprog_count(target, 2);
747
748 LIBBPF_OPTS_RESET(optl,
749 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,
750 .relative_id = lid2,
751 );
752
753 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
754 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
755 bpf_link__destroy(link);
756 goto cleanup;
757 }
758
759 assert_mprog_count(target, 2);
760
761 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);
762 if (!ASSERT_OK(err, "link_update"))
763 goto cleanup;
764
765 assert_mprog_count(target, 2);
766
767 memset(prog_ids, 0, sizeof(prog_ids));
768 memset(link_ids, 0, sizeof(link_ids));
769 optq.count = ARRAY_SIZE(prog_ids);
770
771 err = bpf_prog_query_opts(loopback, target, &optq);
772 if (!ASSERT_OK(err, "prog_query"))
773 goto cleanup;
774
775 ASSERT_EQ(optq.count, 2, "count");
776 ASSERT_EQ(optq.revision, 4, "revision");
777 ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
778 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
779 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
780 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
781 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
782 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
783
784 ASSERT_OK(system(ping_cmd), ping_cmd);
785
786 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
787 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
788 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
789
790 skel->bss->seen_tc1 = false;
791 skel->bss->seen_tc2 = false;
792 skel->bss->seen_tc3 = false;
793
794 err = bpf_link__detach(skel->links.tc2);
795 if (!ASSERT_OK(err, "link_detach"))
796 goto cleanup;
797
798 assert_mprog_count(target, 1);
799
800 memset(prog_ids, 0, sizeof(prog_ids));
801 memset(link_ids, 0, sizeof(link_ids));
802 optq.count = ARRAY_SIZE(prog_ids);
803
804 err = bpf_prog_query_opts(loopback, target, &optq);
805 if (!ASSERT_OK(err, "prog_query"))
806 goto cleanup;
807
808 ASSERT_EQ(optq.count, 1, "count");
809 ASSERT_EQ(optq.revision, 5, "revision");
810 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
811 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
812 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
813 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
814
815 ASSERT_OK(system(ping_cmd), ping_cmd);
816
817 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
818 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
819 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
820
821 skel->bss->seen_tc1 = false;
822 skel->bss->seen_tc2 = false;
823 skel->bss->seen_tc3 = false;
824
825 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
826 if (!ASSERT_OK(err, "link_update_self"))
827 goto cleanup;
828
829 assert_mprog_count(target, 1);
830
831 memset(prog_ids, 0, sizeof(prog_ids));
832 memset(link_ids, 0, sizeof(link_ids));
833 optq.count = ARRAY_SIZE(prog_ids);
834
835 err = bpf_prog_query_opts(loopback, target, &optq);
836 if (!ASSERT_OK(err, "prog_query"))
837 goto cleanup;
838
839 ASSERT_EQ(optq.count, 1, "count");
840 ASSERT_EQ(optq.revision, 5, "revision");
841 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
842 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
843 ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
844 ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
845
846 ASSERT_OK(system(ping_cmd), ping_cmd);
847
848 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
849 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
850 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
851cleanup:
852 test_tc_link__destroy(skel);
853 assert_mprog_count(target, 0);
854}
855
856void serial_test_tc_links_replace(void)
857{
858 test_tc_links_replace_target(BPF_TCX_INGRESS);
859 test_tc_links_replace_target(BPF_TCX_EGRESS);
860}
861
862static void test_tc_links_invalid_target(int target)
863{
864 LIBBPF_OPTS(bpf_prog_query_opts, optq);
865 LIBBPF_OPTS(bpf_tcx_opts, optl);
866 __u32 pid1, pid2, lid1;
867 struct test_tc_link *skel;
868 struct bpf_link *link;
869 int err;
870
871 skel = test_tc_link__open();
872 if (!ASSERT_OK_PTR(skel, "skel_open"))
873 goto cleanup;
874
875 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
876 0, "tc1_attach_type");
877 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
878 0, "tc2_attach_type");
879
880 err = test_tc_link__load(skel);
881 if (!ASSERT_OK(err, "skel_load"))
882 goto cleanup;
883
884 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
885 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
886
887 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
888
889 assert_mprog_count(target, 0);
890
891 optl.flags = BPF_F_BEFORE | BPF_F_AFTER;
892
893 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
894 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
895 bpf_link__destroy(link);
896 goto cleanup;
897 }
898
899 assert_mprog_count(target, 0);
900
901 LIBBPF_OPTS_RESET(optl,
902 .flags = BPF_F_BEFORE | BPF_F_ID,
903 );
904
905 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
906 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
907 bpf_link__destroy(link);
908 goto cleanup;
909 }
910
911 assert_mprog_count(target, 0);
912
913 LIBBPF_OPTS_RESET(optl,
914 .flags = BPF_F_AFTER | BPF_F_ID,
915 );
916
917 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
918 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
919 bpf_link__destroy(link);
920 goto cleanup;
921 }
922
923 assert_mprog_count(target, 0);
924
925 LIBBPF_OPTS_RESET(optl,
926 .flags = BPF_F_ID,
927 );
928
929 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
930 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
931 bpf_link__destroy(link);
932 goto cleanup;
933 }
934
935 assert_mprog_count(target, 0);
936
937 LIBBPF_OPTS_RESET(optl,
938 .flags = BPF_F_LINK,
939 .relative_fd = bpf_program__fd(skel->progs.tc2),
940 );
941
942 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
943 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
944 bpf_link__destroy(link);
945 goto cleanup;
946 }
947
948 assert_mprog_count(target, 0);
949
950 LIBBPF_OPTS_RESET(optl,
951 .flags = BPF_F_LINK,
952 );
953
954 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
955 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
956 bpf_link__destroy(link);
957 goto cleanup;
958 }
959
960 assert_mprog_count(target, 0);
961
962 LIBBPF_OPTS_RESET(optl,
963 .relative_fd = bpf_program__fd(skel->progs.tc2),
964 );
965
966 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
967 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
968 bpf_link__destroy(link);
969 goto cleanup;
970 }
971
972 assert_mprog_count(target, 0);
973
974 LIBBPF_OPTS_RESET(optl,
975 .flags = BPF_F_BEFORE | BPF_F_AFTER,
976 .relative_fd = bpf_program__fd(skel->progs.tc2),
977 );
978
979 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
980 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
981 bpf_link__destroy(link);
982 goto cleanup;
983 }
984
985 assert_mprog_count(target, 0);
986
987 LIBBPF_OPTS_RESET(optl,
988 .flags = BPF_F_BEFORE,
989 .relative_fd = bpf_program__fd(skel->progs.tc1),
990 );
991
992 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
993 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
994 bpf_link__destroy(link);
995 goto cleanup;
996 }
997
998 assert_mprog_count(target, 0);
999
1000 LIBBPF_OPTS_RESET(optl,
1001 .flags = BPF_F_ID,
1002 .relative_id = pid2,
1003 );
1004
1005 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1006 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1007 bpf_link__destroy(link);
1008 goto cleanup;
1009 }
1010
1011 assert_mprog_count(target, 0);
1012
1013 LIBBPF_OPTS_RESET(optl,
1014 .flags = BPF_F_ID,
1015 .relative_id = 42,
1016 );
1017
1018 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1019 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1020 bpf_link__destroy(link);
1021 goto cleanup;
1022 }
1023
1024 assert_mprog_count(target, 0);
1025
1026 LIBBPF_OPTS_RESET(optl,
1027 .flags = BPF_F_BEFORE,
1028 .relative_fd = bpf_program__fd(skel->progs.tc1),
1029 );
1030
1031 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1032 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1033 bpf_link__destroy(link);
1034 goto cleanup;
1035 }
1036
1037 assert_mprog_count(target, 0);
1038
1039 LIBBPF_OPTS_RESET(optl,
1040 .flags = BPF_F_BEFORE | BPF_F_LINK,
1041 .relative_fd = bpf_program__fd(skel->progs.tc1),
1042 );
1043
1044 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1045 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1046 bpf_link__destroy(link);
1047 goto cleanup;
1048 }
1049
1050 assert_mprog_count(target, 0);
1051
1052 LIBBPF_OPTS_RESET(optl,
1053 .flags = BPF_F_AFTER,
1054 .relative_fd = bpf_program__fd(skel->progs.tc1),
1055 );
1056
1057 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1058 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1059 bpf_link__destroy(link);
1060 goto cleanup;
1061 }
1062
1063 assert_mprog_count(target, 0);
1064
1065 LIBBPF_OPTS_RESET(optl);
1066
1067 link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl);
1068 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1069 bpf_link__destroy(link);
1070 goto cleanup;
1071 }
1072
1073 assert_mprog_count(target, 0);
1074
1075 LIBBPF_OPTS_RESET(optl,
1076 .flags = BPF_F_AFTER | BPF_F_LINK,
1077 .relative_fd = bpf_program__fd(skel->progs.tc1),
1078 );
1079
1080 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1081 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1082 bpf_link__destroy(link);
1083 goto cleanup;
1084 }
1085
1086 assert_mprog_count(target, 0);
1087
1088 LIBBPF_OPTS_RESET(optl);
1089
1090 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1091 if (!ASSERT_OK_PTR(link, "link_attach"))
1092 goto cleanup;
1093
1094 skel->links.tc1 = link;
1095
1096 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1097
1098 assert_mprog_count(target, 1);
1099
1100 LIBBPF_OPTS_RESET(optl,
1101 .flags = BPF_F_AFTER | BPF_F_LINK,
1102 .relative_fd = bpf_program__fd(skel->progs.tc1),
1103 );
1104
1105 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1106 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1107 bpf_link__destroy(link);
1108 goto cleanup;
1109 }
1110
1111 assert_mprog_count(target, 1);
1112
1113 LIBBPF_OPTS_RESET(optl,
1114 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1115 .relative_id = ~0,
1116 );
1117
1118 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1119 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1120 bpf_link__destroy(link);
1121 goto cleanup;
1122 }
1123
1124 assert_mprog_count(target, 1);
1125
1126 LIBBPF_OPTS_RESET(optl,
1127 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1128 .relative_id = lid1,
1129 );
1130
1131 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1132 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1133 bpf_link__destroy(link);
1134 goto cleanup;
1135 }
1136
1137 assert_mprog_count(target, 1);
1138
1139 LIBBPF_OPTS_RESET(optl,
1140 .flags = BPF_F_BEFORE | BPF_F_ID,
1141 .relative_id = pid1,
1142 );
1143
1144 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1145 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
1146 bpf_link__destroy(link);
1147 goto cleanup;
1148 }
1149 assert_mprog_count(target, 1);
1150
1151 LIBBPF_OPTS_RESET(optl,
1152 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1153 .relative_id = lid1,
1154 );
1155
1156 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1157 if (!ASSERT_OK_PTR(link, "link_attach"))
1158 goto cleanup;
1159
1160 skel->links.tc2 = link;
1161
1162 assert_mprog_count(target, 2);
1163cleanup:
1164 test_tc_link__destroy(skel);
1165 assert_mprog_count(target, 0);
1166}
1167
1168void serial_test_tc_links_invalid(void)
1169{
1170 test_tc_links_invalid_target(BPF_TCX_INGRESS);
1171 test_tc_links_invalid_target(BPF_TCX_EGRESS);
1172}
1173
1174static void test_tc_links_prepend_target(int target)
1175{
1176 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1177 LIBBPF_OPTS(bpf_tcx_opts, optl);
1178 __u32 prog_ids[5], link_ids[5];
1179 __u32 pid1, pid2, pid3, pid4;
1180 __u32 lid1, lid2, lid3, lid4;
1181 struct test_tc_link *skel;
1182 struct bpf_link *link;
1183 int err;
1184
1185 skel = test_tc_link__open();
1186 if (!ASSERT_OK_PTR(skel, "skel_open"))
1187 goto cleanup;
1188
1189 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1190 0, "tc1_attach_type");
1191 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1192 0, "tc2_attach_type");
1193 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1194 0, "tc3_attach_type");
1195 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1196 0, "tc4_attach_type");
1197
1198 err = test_tc_link__load(skel);
1199 if (!ASSERT_OK(err, "skel_load"))
1200 goto cleanup;
1201
1202 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1203 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1204 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1205 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1206
1207 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1208 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1209 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1210
1211 assert_mprog_count(target, 0);
1212
1213 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1214 if (!ASSERT_OK_PTR(link, "link_attach"))
1215 goto cleanup;
1216
1217 skel->links.tc1 = link;
1218
1219 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1220
1221 assert_mprog_count(target, 1);
1222
1223 LIBBPF_OPTS_RESET(optl,
1224 .flags = BPF_F_BEFORE,
1225 );
1226
1227 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1228 if (!ASSERT_OK_PTR(link, "link_attach"))
1229 goto cleanup;
1230
1231 skel->links.tc2 = link;
1232
1233 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1234
1235 assert_mprog_count(target, 2);
1236
1237 optq.prog_ids = prog_ids;
1238 optq.link_ids = link_ids;
1239
1240 memset(prog_ids, 0, sizeof(prog_ids));
1241 memset(link_ids, 0, sizeof(link_ids));
1242 optq.count = ARRAY_SIZE(prog_ids);
1243
1244 err = bpf_prog_query_opts(loopback, target, &optq);
1245 if (!ASSERT_OK(err, "prog_query"))
1246 goto cleanup;
1247
1248 ASSERT_EQ(optq.count, 2, "count");
1249 ASSERT_EQ(optq.revision, 3, "revision");
1250 ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
1251 ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
1252 ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
1253 ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
1254 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1255 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1256
1257 ASSERT_OK(system(ping_cmd), ping_cmd);
1258
1259 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1260 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1261 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1262 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1263
1264 skel->bss->seen_tc1 = false;
1265 skel->bss->seen_tc2 = false;
1266
1267 LIBBPF_OPTS_RESET(optl,
1268 .flags = BPF_F_BEFORE,
1269 );
1270
1271 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1272 if (!ASSERT_OK_PTR(link, "link_attach"))
1273 goto cleanup;
1274
1275 skel->links.tc3 = link;
1276
1277 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1278
1279 LIBBPF_OPTS_RESET(optl,
1280 .flags = BPF_F_BEFORE,
1281 );
1282
1283 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1284 if (!ASSERT_OK_PTR(link, "link_attach"))
1285 goto cleanup;
1286
1287 skel->links.tc4 = link;
1288
1289 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1290
1291 assert_mprog_count(target, 4);
1292
1293 memset(prog_ids, 0, sizeof(prog_ids));
1294 memset(link_ids, 0, sizeof(link_ids));
1295 optq.count = ARRAY_SIZE(prog_ids);
1296
1297 err = bpf_prog_query_opts(loopback, target, &optq);
1298 if (!ASSERT_OK(err, "prog_query"))
1299 goto cleanup;
1300
1301 ASSERT_EQ(optq.count, 4, "count");
1302 ASSERT_EQ(optq.revision, 5, "revision");
1303 ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");
1304 ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");
1305 ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");
1306 ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");
1307 ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");
1308 ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");
1309 ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]");
1310 ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]");
1311 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1312 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1313
1314 ASSERT_OK(system(ping_cmd), ping_cmd);
1315
1316 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1317 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1318 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1319 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1320cleanup:
1321 test_tc_link__destroy(skel);
1322 assert_mprog_count(target, 0);
1323}
1324
1325void serial_test_tc_links_prepend(void)
1326{
1327 test_tc_links_prepend_target(BPF_TCX_INGRESS);
1328 test_tc_links_prepend_target(BPF_TCX_EGRESS);
1329}
1330
1331static void test_tc_links_append_target(int target)
1332{
1333 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1334 LIBBPF_OPTS(bpf_tcx_opts, optl);
1335 __u32 prog_ids[5], link_ids[5];
1336 __u32 pid1, pid2, pid3, pid4;
1337 __u32 lid1, lid2, lid3, lid4;
1338 struct test_tc_link *skel;
1339 struct bpf_link *link;
1340 int err;
1341
1342 skel = test_tc_link__open();
1343 if (!ASSERT_OK_PTR(skel, "skel_open"))
1344 goto cleanup;
1345
1346 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1347 0, "tc1_attach_type");
1348 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1349 0, "tc2_attach_type");
1350 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1351 0, "tc3_attach_type");
1352 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1353 0, "tc4_attach_type");
1354
1355 err = test_tc_link__load(skel);
1356 if (!ASSERT_OK(err, "skel_load"))
1357 goto cleanup;
1358
1359 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1360 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1361 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1362 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1363
1364 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1365 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1366 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1367
1368 assert_mprog_count(target, 0);
1369
1370 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1371 if (!ASSERT_OK_PTR(link, "link_attach"))
1372 goto cleanup;
1373
1374 skel->links.tc1 = link;
1375
1376 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1377
1378 assert_mprog_count(target, 1);
1379
1380 LIBBPF_OPTS_RESET(optl,
1381 .flags = BPF_F_AFTER,
1382 );
1383
1384 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1385 if (!ASSERT_OK_PTR(link, "link_attach"))
1386 goto cleanup;
1387
1388 skel->links.tc2 = link;
1389
1390 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1391
1392 assert_mprog_count(target, 2);
1393
1394 optq.prog_ids = prog_ids;
1395 optq.link_ids = link_ids;
1396
1397 memset(prog_ids, 0, sizeof(prog_ids));
1398 memset(link_ids, 0, sizeof(link_ids));
1399 optq.count = ARRAY_SIZE(prog_ids);
1400
1401 err = bpf_prog_query_opts(loopback, target, &optq);
1402 if (!ASSERT_OK(err, "prog_query"))
1403 goto cleanup;
1404
1405 ASSERT_EQ(optq.count, 2, "count");
1406 ASSERT_EQ(optq.revision, 3, "revision");
1407 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1408 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1409 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1410 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1411 ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1412 ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
1413
1414 ASSERT_OK(system(ping_cmd), ping_cmd);
1415
1416 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1417 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1418 ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1419 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1420
1421 skel->bss->seen_tc1 = false;
1422 skel->bss->seen_tc2 = false;
1423
1424 LIBBPF_OPTS_RESET(optl,
1425 .flags = BPF_F_AFTER,
1426 );
1427
1428 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1429 if (!ASSERT_OK_PTR(link, "link_attach"))
1430 goto cleanup;
1431
1432 skel->links.tc3 = link;
1433
1434 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1435
1436 LIBBPF_OPTS_RESET(optl,
1437 .flags = BPF_F_AFTER,
1438 );
1439
1440 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1441 if (!ASSERT_OK_PTR(link, "link_attach"))
1442 goto cleanup;
1443
1444 skel->links.tc4 = link;
1445
1446 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1447
1448 assert_mprog_count(target, 4);
1449
1450 memset(prog_ids, 0, sizeof(prog_ids));
1451 memset(link_ids, 0, sizeof(link_ids));
1452 optq.count = ARRAY_SIZE(prog_ids);
1453
1454 err = bpf_prog_query_opts(loopback, target, &optq);
1455 if (!ASSERT_OK(err, "prog_query"))
1456 goto cleanup;
1457
1458 ASSERT_EQ(optq.count, 4, "count");
1459 ASSERT_EQ(optq.revision, 5, "revision");
1460 ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
1461 ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
1462 ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1463 ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1464 ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");
1465 ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");
1466 ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");
1467 ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");
1468 ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1469 ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
1470
1471 ASSERT_OK(system(ping_cmd), ping_cmd);
1472
1473 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1474 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1475 ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1476 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1477cleanup:
1478 test_tc_link__destroy(skel);
1479 assert_mprog_count(target, 0);
1480}
1481
1482void serial_test_tc_links_append(void)
1483{
1484 test_tc_links_append_target(BPF_TCX_INGRESS);
1485 test_tc_links_append_target(BPF_TCX_EGRESS);
1486}
1487
1488static void test_tc_links_dev_cleanup_target(int target)
1489{
1490 LIBBPF_OPTS(bpf_tcx_opts, optl);
1491 LIBBPF_OPTS(bpf_prog_query_opts, optq);
1492 __u32 pid1, pid2, pid3, pid4;
1493 struct test_tc_link *skel;
1494 struct bpf_link *link;
1495 int err, ifindex;
1496
1497 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1498 ifindex = if_nametoindex("tcx_opts1");
1499 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1500
1501 skel = test_tc_link__open();
1502 if (!ASSERT_OK_PTR(skel, "skel_open"))
1503 goto cleanup;
1504
1505 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1506 0, "tc1_attach_type");
1507 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1508 0, "tc2_attach_type");
1509 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1510 0, "tc3_attach_type");
1511 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1512 0, "tc4_attach_type");
1513
1514 err = test_tc_link__load(skel);
1515 if (!ASSERT_OK(err, "skel_load"))
1516 goto cleanup;
1517
1518 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1519 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1520 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1521 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1522
1523 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1524 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1525 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1526
1527 assert_mprog_count(target, 0);
1528
1529 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1530 if (!ASSERT_OK_PTR(link, "link_attach"))
1531 goto cleanup;
1532
1533 skel->links.tc1 = link;
1534
1535 assert_mprog_count_ifindex(ifindex, target, 1);
1536
1537 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1538 if (!ASSERT_OK_PTR(link, "link_attach"))
1539 goto cleanup;
1540
1541 skel->links.tc2 = link;
1542
1543 assert_mprog_count_ifindex(ifindex, target, 2);
1544
1545 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1546 if (!ASSERT_OK_PTR(link, "link_attach"))
1547 goto cleanup;
1548
1549 skel->links.tc3 = link;
1550
1551 assert_mprog_count_ifindex(ifindex, target, 3);
1552
1553 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1554 if (!ASSERT_OK_PTR(link, "link_attach"))
1555 goto cleanup;
1556
1557 skel->links.tc4 = link;
1558
1559 assert_mprog_count_ifindex(ifindex, target, 4);
1560
1561 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1562 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1563 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1564
1565 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1566 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1567 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1568 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1569
1570 test_tc_link__destroy(skel);
1571 return;
1572cleanup:
1573 test_tc_link__destroy(skel);
1574
1575 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1576 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1577 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1578}
1579
1580void serial_test_tc_links_dev_cleanup(void)
1581{
1582 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);
1583 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);
1584}
1585
1586static void test_tc_chain_mixed(int target)
1587{
1588 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1589 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
1590 LIBBPF_OPTS(bpf_tcx_opts, optl);
1591 struct test_tc_link *skel;
1592 struct bpf_link *link;
1593 __u32 pid1, pid2, pid3;
1594 int err;
1595
1596 skel = test_tc_link__open();
1597 if (!ASSERT_OK_PTR(skel, "skel_open"))
1598 goto cleanup;
1599
1600 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1601 0, "tc4_attach_type");
1602 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),
1603 0, "tc5_attach_type");
1604 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),
1605 0, "tc6_attach_type");
1606
1607 err = test_tc_link__load(skel);
1608 if (!ASSERT_OK(err, "skel_load"))
1609 goto cleanup;
1610
1611 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1612 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));
1613 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));
1614
1615 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1616 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1617
1618 assert_mprog_count(target, 0);
1619
1620 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1621 BPF_TC_INGRESS : BPF_TC_EGRESS;
1622 err = bpf_tc_hook_create(&tc_hook);
1623 err = err == -EEXIST ? 0 : err;
1624 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1625 goto cleanup;
1626
1627 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1628 err = bpf_tc_attach(&tc_hook, &tc_opts);
1629 if (!ASSERT_OK(err, "bpf_tc_attach"))
1630 goto cleanup;
1631
1632 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);
1633 if (!ASSERT_OK_PTR(link, "link_attach"))
1634 goto cleanup;
1635
1636 skel->links.tc6 = link;
1637
1638 assert_mprog_count(target, 1);
1639
1640 ASSERT_OK(system(ping_cmd), ping_cmd);
1641
1642 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1643 ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
1644 ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
1645
1646 skel->bss->seen_tc4 = false;
1647 skel->bss->seen_tc5 = false;
1648 skel->bss->seen_tc6 = false;
1649
1650 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
1651 if (!ASSERT_OK(err, "link_update"))
1652 goto cleanup;
1653
1654 assert_mprog_count(target, 1);
1655
1656 ASSERT_OK(system(ping_cmd), ping_cmd);
1657
1658 ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1659 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1660 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1661
1662 skel->bss->seen_tc4 = false;
1663 skel->bss->seen_tc5 = false;
1664 skel->bss->seen_tc6 = false;
1665
1666 err = bpf_link__detach(skel->links.tc6);
1667 if (!ASSERT_OK(err, "prog_detach"))
1668 goto cleanup;
1669
1670 __assert_mprog_count(target, 0, true, loopback);
1671
1672 ASSERT_OK(system(ping_cmd), ping_cmd);
1673
1674 ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1675 ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
1676 ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
1677
1678cleanup:
1679 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1680 err = bpf_tc_detach(&tc_hook, &tc_opts);
1681 ASSERT_OK(err, "bpf_tc_detach");
1682
1683 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
1684 bpf_tc_hook_destroy(&tc_hook);
1685
1686 test_tc_link__destroy(skel);
1687}
1688
1689void serial_test_tc_links_chain_mixed(void)
1690{
1691 test_tc_chain_mixed(BPF_TCX_INGRESS);
1692 test_tc_chain_mixed(BPF_TCX_EGRESS);
1693}
1694
1695static void test_tc_links_ingress(int target, bool chain_tc_old,
1696 bool tcx_teardown_first)
1697{
1698 LIBBPF_OPTS(bpf_tc_opts, tc_opts,
1699 .handle = 1,
1700 .priority = 1,
1701 );
1702 LIBBPF_OPTS(bpf_tc_hook, tc_hook,
1703 .ifindex = loopback,
1704 .attach_point = BPF_TC_CUSTOM,
1705 .parent = TC_H_INGRESS,
1706 );
1707 bool hook_created = false, tc_attached = false;
1708 LIBBPF_OPTS(bpf_tcx_opts, optl);
1709 __u32 pid1, pid2, pid3;
1710 struct test_tc_link *skel;
1711 struct bpf_link *link;
1712 int err;
1713
1714 skel = test_tc_link__open();
1715 if (!ASSERT_OK_PTR(skel, "skel_open"))
1716 goto cleanup;
1717
1718 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1719 0, "tc1_attach_type");
1720 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1721 0, "tc2_attach_type");
1722
1723 err = test_tc_link__load(skel);
1724 if (!ASSERT_OK(err, "skel_load"))
1725 goto cleanup;
1726
1727 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1728 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1729 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1730
1731 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1732 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1733
1734 assert_mprog_count(target, 0);
1735
1736 if (chain_tc_old) {
1737 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");
1738 hook_created = true;
1739
1740 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
1741 err = bpf_tc_attach(&tc_hook, &tc_opts);
1742 if (!ASSERT_OK(err, "bpf_tc_attach"))
1743 goto cleanup;
1744 tc_attached = true;
1745 }
1746
1747 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1748 if (!ASSERT_OK_PTR(link, "link_attach"))
1749 goto cleanup;
1750
1751 skel->links.tc1 = link;
1752
1753 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1754 if (!ASSERT_OK_PTR(link, "link_attach"))
1755 goto cleanup;
1756
1757 skel->links.tc2 = link;
1758
1759 assert_mprog_count(target, 2);
1760
1761 ASSERT_OK(system(ping_cmd), ping_cmd);
1762
1763 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1764 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1765 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1766
1767 skel->bss->seen_tc1 = false;
1768 skel->bss->seen_tc2 = false;
1769 skel->bss->seen_tc3 = false;
1770
1771 err = bpf_link__detach(skel->links.tc2);
1772 if (!ASSERT_OK(err, "prog_detach"))
1773 goto cleanup;
1774
1775 assert_mprog_count(target, 1);
1776
1777 ASSERT_OK(system(ping_cmd), ping_cmd);
1778
1779 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1780 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
1781 ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
1782cleanup:
1783 if (tc_attached) {
1784 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
1785 err = bpf_tc_detach(&tc_hook, &tc_opts);
1786 ASSERT_OK(err, "bpf_tc_detach");
1787 }
1788 ASSERT_OK(system(ping_cmd), ping_cmd);
1789 assert_mprog_count(target, 1);
1790 if (hook_created && tcx_teardown_first)
1791 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1792 ASSERT_OK(system(ping_cmd), ping_cmd);
1793 test_tc_link__destroy(skel);
1794 ASSERT_OK(system(ping_cmd), ping_cmd);
1795 if (hook_created && !tcx_teardown_first)
1796 ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
1797 ASSERT_OK(system(ping_cmd), ping_cmd);
1798 assert_mprog_count(target, 0);
1799}
1800
1801void serial_test_tc_links_ingress(void)
1802{
1803 test_tc_links_ingress(BPF_TCX_INGRESS, true, true);
1804 test_tc_links_ingress(BPF_TCX_INGRESS, true, false);
1805 test_tc_links_ingress(BPF_TCX_INGRESS, false, false);
1806}
1807
1808static void test_tc_links_dev_mixed(int target)
1809{
1810 LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
1811 LIBBPF_OPTS(bpf_tc_hook, tc_hook);
1812 LIBBPF_OPTS(bpf_tcx_opts, optl);
1813 __u32 pid1, pid2, pid3, pid4;
1814 struct test_tc_link *skel;
1815 struct bpf_link *link;
1816 int err, ifindex;
1817
1818 ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1819 ifindex = if_nametoindex("tcx_opts1");
1820 ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1821
1822 skel = test_tc_link__open();
1823 if (!ASSERT_OK_PTR(skel, "skel_open"))
1824 goto cleanup;
1825
1826 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1827 0, "tc1_attach_type");
1828 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1829 0, "tc2_attach_type");
1830 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1831 0, "tc3_attach_type");
1832 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1833 0, "tc4_attach_type");
1834
1835 err = test_tc_link__load(skel);
1836 if (!ASSERT_OK(err, "skel_load"))
1837 goto cleanup;
1838
1839 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1840 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1841 pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1842 pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1843
1844 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1845 ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1846 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1847
1848 assert_mprog_count(target, 0);
1849
1850 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1851 if (!ASSERT_OK_PTR(link, "link_attach"))
1852 goto cleanup;
1853
1854 skel->links.tc1 = link;
1855
1856 assert_mprog_count_ifindex(ifindex, target, 1);
1857
1858 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1859 if (!ASSERT_OK_PTR(link, "link_attach"))
1860 goto cleanup;
1861
1862 skel->links.tc2 = link;
1863
1864 assert_mprog_count_ifindex(ifindex, target, 2);
1865
1866 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1867 if (!ASSERT_OK_PTR(link, "link_attach"))
1868 goto cleanup;
1869
1870 skel->links.tc3 = link;
1871
1872 assert_mprog_count_ifindex(ifindex, target, 3);
1873
1874 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1875 if (!ASSERT_OK_PTR(link, "link_attach"))
1876 goto cleanup;
1877
1878 skel->links.tc4 = link;
1879
1880 assert_mprog_count_ifindex(ifindex, target, 4);
1881
1882 tc_hook.ifindex = ifindex;
1883 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1884 BPF_TC_INGRESS : BPF_TC_EGRESS;
1885
1886 err = bpf_tc_hook_create(&tc_hook);
1887 err = err == -EEXIST ? 0 : err;
1888 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1889 goto cleanup;
1890
1891 tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
1892 err = bpf_tc_attach(&tc_hook, &tc_opts);
1893 if (!ASSERT_OK(err, "bpf_tc_attach"))
1894 goto cleanup;
1895
1896 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1897 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1898 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1899
1900 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
1901 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
1902 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
1903 ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
1904
1905 test_tc_link__destroy(skel);
1906 return;
1907cleanup:
1908 test_tc_link__destroy(skel);
1909
1910 ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1911 ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1912 ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1913}
1914
1915void serial_test_tc_links_dev_mixed(void)
1916{
1917 test_tc_links_dev_mixed(BPF_TCX_INGRESS);
1918 test_tc_links_dev_mixed(BPF_TCX_EGRESS);
1919}