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
serial_test_tc_links_basic(void)14 void 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 tc_skel_reset_all_seen(skel);
69 ASSERT_OK(system(ping_cmd), ping_cmd);
70
71 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
72 ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
73
74 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
75 if (!ASSERT_OK_PTR(link, "link_attach"))
76 goto cleanup;
77
78 skel->links.tc2 = link;
79
80 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
81 ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
82
83 assert_mprog_count(BPF_TCX_INGRESS, 1);
84 assert_mprog_count(BPF_TCX_EGRESS, 1);
85
86 memset(prog_ids, 0, sizeof(prog_ids));
87 memset(link_ids, 0, sizeof(link_ids));
88 optq.count = ARRAY_SIZE(prog_ids);
89
90 err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
91 if (!ASSERT_OK(err, "prog_query"))
92 goto cleanup;
93
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]");
100
101 tc_skel_reset_all_seen(skel);
102 ASSERT_OK(system(ping_cmd), ping_cmd);
103
104 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
105 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
106 cleanup:
107 test_tc_link__destroy(skel);
108
109 assert_mprog_count(BPF_TCX_INGRESS, 0);
110 assert_mprog_count(BPF_TCX_EGRESS, 0);
111 }
112
test_tc_links_before_target(int target)113 static void test_tc_links_before_target(int target)
114 {
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;
122 int err;
123
124 skel = test_tc_link__open();
125 if (!ASSERT_OK_PTR(skel, "skel_open"))
126 goto cleanup;
127
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");
136
137 err = test_tc_link__load(skel);
138 if (!ASSERT_OK(err, "skel_load"))
139 goto cleanup;
140
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));
145
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");
149
150 assert_mprog_count(target, 0);
151
152 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
153 if (!ASSERT_OK_PTR(link, "link_attach"))
154 goto cleanup;
155
156 skel->links.tc1 = link;
157
158 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
159
160 assert_mprog_count(target, 1);
161
162 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
163 if (!ASSERT_OK_PTR(link, "link_attach"))
164 goto cleanup;
165
166 skel->links.tc2 = link;
167
168 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
169
170 assert_mprog_count(target, 2);
171
172 optq.prog_ids = prog_ids;
173 optq.link_ids = link_ids;
174
175 memset(prog_ids, 0, sizeof(prog_ids));
176 memset(link_ids, 0, sizeof(link_ids));
177 optq.count = ARRAY_SIZE(prog_ids);
178
179 err = bpf_prog_query_opts(loopback, target, &optq);
180 if (!ASSERT_OK(err, "prog_query"))
181 goto cleanup;
182
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]");
191
192 tc_skel_reset_all_seen(skel);
193 ASSERT_OK(system(ping_cmd), ping_cmd);
194
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");
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 tc_skel_reset_all_seen(skel);
250 ASSERT_OK(system(ping_cmd), ping_cmd);
251
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");
256 cleanup:
257 test_tc_link__destroy(skel);
258 assert_mprog_count(target, 0);
259 }
260
serial_test_tc_links_before(void)261 void serial_test_tc_links_before(void)
262 {
263 test_tc_links_before_target(BPF_TCX_INGRESS);
264 test_tc_links_before_target(BPF_TCX_EGRESS);
265 }
266
test_tc_links_after_target(int target)267 static void test_tc_links_after_target(int target)
268 {
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;
276 int err;
277
278 skel = test_tc_link__open();
279 if (!ASSERT_OK_PTR(skel, "skel_open"))
280 goto cleanup;
281
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");
290
291 err = test_tc_link__load(skel);
292 if (!ASSERT_OK(err, "skel_load"))
293 goto cleanup;
294
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));
299
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");
303
304 assert_mprog_count(target, 0);
305
306 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
307 if (!ASSERT_OK_PTR(link, "link_attach"))
308 goto cleanup;
309
310 skel->links.tc1 = link;
311
312 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
313
314 assert_mprog_count(target, 1);
315
316 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
317 if (!ASSERT_OK_PTR(link, "link_attach"))
318 goto cleanup;
319
320 skel->links.tc2 = link;
321
322 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
323
324 assert_mprog_count(target, 2);
325
326 optq.prog_ids = prog_ids;
327 optq.link_ids = link_ids;
328
329 memset(prog_ids, 0, sizeof(prog_ids));
330 memset(link_ids, 0, sizeof(link_ids));
331 optq.count = ARRAY_SIZE(prog_ids);
332
333 err = bpf_prog_query_opts(loopback, target, &optq);
334 if (!ASSERT_OK(err, "prog_query"))
335 goto cleanup;
336
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]");
345
346 tc_skel_reset_all_seen(skel);
347 ASSERT_OK(system(ping_cmd), ping_cmd);
348
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");
353
354 LIBBPF_OPTS_RESET(optl,
355 .flags = BPF_F_AFTER,
356 .relative_fd = bpf_program__fd(skel->progs.tc1),
357 );
358
359 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
360 if (!ASSERT_OK_PTR(link, "link_attach"))
361 goto cleanup;
362
363 skel->links.tc3 = link;
364
365 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
366
367 LIBBPF_OPTS_RESET(optl,
368 .flags = BPF_F_AFTER | BPF_F_LINK,
369 .relative_fd = bpf_link__fd(skel->links.tc2),
370 );
371
372 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
373 if (!ASSERT_OK_PTR(link, "link_attach"))
374 goto cleanup;
375
376 skel->links.tc4 = link;
377
378 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
379
380 assert_mprog_count(target, 4);
381
382 memset(prog_ids, 0, sizeof(prog_ids));
383 memset(link_ids, 0, sizeof(link_ids));
384 optq.count = ARRAY_SIZE(prog_ids);
385
386 err = bpf_prog_query_opts(loopback, target, &optq);
387 if (!ASSERT_OK(err, "prog_query"))
388 goto cleanup;
389
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]");
402
403 tc_skel_reset_all_seen(skel);
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");
410 cleanup:
411 test_tc_link__destroy(skel);
412 assert_mprog_count(target, 0);
413 }
414
serial_test_tc_links_after(void)415 void 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
test_tc_links_revision_target(int target)421 static 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 tc_skel_reset_all_seen(skel);
506 ASSERT_OK(system(ping_cmd), ping_cmd);
507
508 ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
509 ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
510 cleanup:
511 test_tc_link__destroy(skel);
512 assert_mprog_count(target, 0);
513 }
514
serial_test_tc_links_revision(void)515 void serial_test_tc_links_revision(void)
516 {
517 test_tc_links_revision_target(BPF_TCX_INGRESS);
518 test_tc_links_revision_target(BPF_TCX_EGRESS);
519 }
520
test_tc_chain_classic(int target,bool chain_tc_old)521 static void test_tc_chain_classic(int target, bool chain_tc_old)
522 {
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;
530 int err;
531
532 skel = test_tc_link__open();
533 if (!ASSERT_OK_PTR(skel, "skel_open"))
534 goto cleanup;
535
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");
540
541 err = test_tc_link__load(skel);
542 if (!ASSERT_OK(err, "skel_load"))
543 goto cleanup;
544
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));
548
549 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
550 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
551
552 assert_mprog_count(target, 0);
553
554 if (chain_tc_old) {
555 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
556 BPF_TC_INGRESS : BPF_TC_EGRESS;
557 err = bpf_tc_hook_create(&tc_hook);
558 if (err == 0)
559 hook_created = true;
560 err = err == -EEXIST ? 0 : err;
561 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
562 goto cleanup;
563
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"))
567 goto cleanup;
568 tc_attached = true;
569 }
570
571 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
572 if (!ASSERT_OK_PTR(link, "link_attach"))
573 goto cleanup;
574
575 skel->links.tc1 = link;
576
577 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
578 if (!ASSERT_OK_PTR(link, "link_attach"))
579 goto cleanup;
580
581 skel->links.tc2 = link;
582
583 assert_mprog_count(target, 2);
584
585 tc_skel_reset_all_seen(skel);
586 ASSERT_OK(system(ping_cmd), ping_cmd);
587
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");
591
592 err = bpf_link__detach(skel->links.tc2);
593 if (!ASSERT_OK(err, "prog_detach"))
594 goto cleanup;
595
596 assert_mprog_count(target, 1);
597
598 tc_skel_reset_all_seen(skel);
599 ASSERT_OK(system(ping_cmd), ping_cmd);
600
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");
604 cleanup:
605 if (tc_attached) {
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");
609 }
610 if (hook_created) {
611 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
612 bpf_tc_hook_destroy(&tc_hook);
613 }
614 assert_mprog_count(target, 1);
615 test_tc_link__destroy(skel);
616 assert_mprog_count(target, 0);
617 }
618
serial_test_tc_links_chain_classic(void)619 void serial_test_tc_links_chain_classic(void)
620 {
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);
625 }
626
test_tc_links_replace_target(int target)627 static void test_tc_links_replace_target(int target)
628 {
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;
635 int err;
636
637 skel = test_tc_link__open();
638 if (!ASSERT_OK_PTR(skel, "skel_open"))
639 goto cleanup;
640
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");
647
648 err = test_tc_link__load(skel);
649 if (!ASSERT_OK(err, "skel_load"))
650 goto cleanup;
651
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));
655
656 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
657 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
658
659 assert_mprog_count(target, 0);
660
661 optl.expected_revision = 1;
662
663 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
664 if (!ASSERT_OK_PTR(link, "link_attach"))
665 goto cleanup;
666
667 skel->links.tc1 = link;
668
669 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
670
671 assert_mprog_count(target, 1);
672
673 LIBBPF_OPTS_RESET(optl,
674 .flags = BPF_F_BEFORE,
675 .relative_id = pid1,
676 .expected_revision = 2,
677 );
678
679 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
680 if (!ASSERT_OK_PTR(link, "link_attach"))
681 goto cleanup;
682
683 skel->links.tc2 = link;
684
685 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
686
687 assert_mprog_count(target, 2);
688
689 optq.prog_ids = prog_ids;
690 optq.link_ids = link_ids;
691
692 memset(prog_ids, 0, sizeof(prog_ids));
693 memset(link_ids, 0, sizeof(link_ids));
694 optq.count = ARRAY_SIZE(prog_ids);
695
696 err = bpf_prog_query_opts(loopback, target, &optq);
697 if (!ASSERT_OK(err, "prog_query"))
698 goto cleanup;
699
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]");
708
709 tc_skel_reset_all_seen(skel);
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 LIBBPF_OPTS_RESET(optl,
717 .flags = BPF_F_REPLACE,
718 .relative_fd = bpf_program__fd(skel->progs.tc2),
719 .expected_revision = 3,
720 );
721
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);
725 goto cleanup;
726 }
727
728 assert_mprog_count(target, 2);
729
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,
734 );
735
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);
739 goto cleanup;
740 }
741
742 assert_mprog_count(target, 2);
743
744 LIBBPF_OPTS_RESET(optl,
745 .flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,
746 .relative_id = lid2,
747 );
748
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);
752 goto cleanup;
753 }
754
755 assert_mprog_count(target, 2);
756
757 err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);
758 if (!ASSERT_OK(err, "link_update"))
759 goto cleanup;
760
761 assert_mprog_count(target, 2);
762
763 memset(prog_ids, 0, sizeof(prog_ids));
764 memset(link_ids, 0, sizeof(link_ids));
765 optq.count = ARRAY_SIZE(prog_ids);
766
767 err = bpf_prog_query_opts(loopback, target, &optq);
768 if (!ASSERT_OK(err, "prog_query"))
769 goto cleanup;
770
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]");
779
780 tc_skel_reset_all_seen(skel);
781 ASSERT_OK(system(ping_cmd), ping_cmd);
782
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");
786
787 err = bpf_link__detach(skel->links.tc2);
788 if (!ASSERT_OK(err, "link_detach"))
789 goto cleanup;
790
791 assert_mprog_count(target, 1);
792
793 memset(prog_ids, 0, sizeof(prog_ids));
794 memset(link_ids, 0, sizeof(link_ids));
795 optq.count = ARRAY_SIZE(prog_ids);
796
797 err = bpf_prog_query_opts(loopback, target, &optq);
798 if (!ASSERT_OK(err, "prog_query"))
799 goto cleanup;
800
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]");
807
808 tc_skel_reset_all_seen(skel);
809 ASSERT_OK(system(ping_cmd), ping_cmd);
810
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");
814
815 err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
816 if (!ASSERT_OK(err, "link_update_self"))
817 goto cleanup;
818
819 assert_mprog_count(target, 1);
820
821 memset(prog_ids, 0, sizeof(prog_ids));
822 memset(link_ids, 0, sizeof(link_ids));
823 optq.count = ARRAY_SIZE(prog_ids);
824
825 err = bpf_prog_query_opts(loopback, target, &optq);
826 if (!ASSERT_OK(err, "prog_query"))
827 goto cleanup;
828
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]");
835
836 tc_skel_reset_all_seen(skel);
837 ASSERT_OK(system(ping_cmd), ping_cmd);
838
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");
842 cleanup:
843 test_tc_link__destroy(skel);
844 assert_mprog_count(target, 0);
845 }
846
serial_test_tc_links_replace(void)847 void serial_test_tc_links_replace(void)
848 {
849 test_tc_links_replace_target(BPF_TCX_INGRESS);
850 test_tc_links_replace_target(BPF_TCX_EGRESS);
851 }
852
test_tc_links_invalid_target(int target)853 static void test_tc_links_invalid_target(int target)
854 {
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;
860 int err;
861
862 skel = test_tc_link__open();
863 if (!ASSERT_OK_PTR(skel, "skel_open"))
864 goto cleanup;
865
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");
870
871 err = test_tc_link__load(skel);
872 if (!ASSERT_OK(err, "skel_load"))
873 goto cleanup;
874
875 pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
876 pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
877
878 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
879
880 assert_mprog_count(target, 0);
881
882 optl.flags = BPF_F_BEFORE | BPF_F_AFTER;
883
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);
887 goto cleanup;
888 }
889
890 assert_mprog_count(target, 0);
891
892 LIBBPF_OPTS_RESET(optl,
893 .flags = BPF_F_BEFORE | BPF_F_ID,
894 );
895
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);
899 goto cleanup;
900 }
901
902 assert_mprog_count(target, 0);
903
904 LIBBPF_OPTS_RESET(optl,
905 .flags = BPF_F_AFTER | BPF_F_ID,
906 );
907
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);
911 goto cleanup;
912 }
913
914 assert_mprog_count(target, 0);
915
916 LIBBPF_OPTS_RESET(optl,
917 .flags = BPF_F_ID,
918 );
919
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);
923 goto cleanup;
924 }
925
926 assert_mprog_count(target, 0);
927
928 LIBBPF_OPTS_RESET(optl,
929 .flags = BPF_F_LINK,
930 .relative_fd = bpf_program__fd(skel->progs.tc2),
931 );
932
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);
936 goto cleanup;
937 }
938
939 assert_mprog_count(target, 0);
940
941 LIBBPF_OPTS_RESET(optl,
942 .flags = BPF_F_LINK,
943 );
944
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);
948 goto cleanup;
949 }
950
951 assert_mprog_count(target, 0);
952
953 LIBBPF_OPTS_RESET(optl,
954 .relative_fd = bpf_program__fd(skel->progs.tc2),
955 );
956
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);
960 goto cleanup;
961 }
962
963 assert_mprog_count(target, 0);
964
965 LIBBPF_OPTS_RESET(optl,
966 .flags = BPF_F_BEFORE | BPF_F_AFTER,
967 .relative_fd = bpf_program__fd(skel->progs.tc2),
968 );
969
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);
973 goto cleanup;
974 }
975
976 assert_mprog_count(target, 0);
977
978 LIBBPF_OPTS_RESET(optl,
979 .flags = BPF_F_BEFORE,
980 .relative_fd = bpf_program__fd(skel->progs.tc1),
981 );
982
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);
986 goto cleanup;
987 }
988
989 assert_mprog_count(target, 0);
990
991 LIBBPF_OPTS_RESET(optl,
992 .flags = BPF_F_ID,
993 .relative_id = pid2,
994 );
995
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);
999 goto cleanup;
1000 }
1001
1002 assert_mprog_count(target, 0);
1003
1004 LIBBPF_OPTS_RESET(optl,
1005 .flags = BPF_F_ID,
1006 .relative_id = 42,
1007 );
1008
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);
1012 goto cleanup;
1013 }
1014
1015 assert_mprog_count(target, 0);
1016
1017 LIBBPF_OPTS_RESET(optl,
1018 .flags = BPF_F_BEFORE,
1019 .relative_fd = bpf_program__fd(skel->progs.tc1),
1020 );
1021
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);
1025 goto cleanup;
1026 }
1027
1028 assert_mprog_count(target, 0);
1029
1030 LIBBPF_OPTS_RESET(optl,
1031 .flags = BPF_F_BEFORE | BPF_F_LINK,
1032 .relative_fd = bpf_program__fd(skel->progs.tc1),
1033 );
1034
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);
1038 goto cleanup;
1039 }
1040
1041 assert_mprog_count(target, 0);
1042
1043 LIBBPF_OPTS_RESET(optl,
1044 .flags = BPF_F_AFTER,
1045 .relative_fd = bpf_program__fd(skel->progs.tc1),
1046 );
1047
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);
1051 goto cleanup;
1052 }
1053
1054 assert_mprog_count(target, 0);
1055
1056 LIBBPF_OPTS_RESET(optl);
1057
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);
1061 goto cleanup;
1062 }
1063
1064 assert_mprog_count(target, 0);
1065
1066 LIBBPF_OPTS_RESET(optl,
1067 .flags = BPF_F_AFTER | BPF_F_LINK,
1068 .relative_fd = bpf_program__fd(skel->progs.tc1),
1069 );
1070
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);
1074 goto cleanup;
1075 }
1076
1077 assert_mprog_count(target, 0);
1078
1079 LIBBPF_OPTS_RESET(optl);
1080
1081 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1082 if (!ASSERT_OK_PTR(link, "link_attach"))
1083 goto cleanup;
1084
1085 skel->links.tc1 = link;
1086
1087 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1088
1089 assert_mprog_count(target, 1);
1090
1091 LIBBPF_OPTS_RESET(optl,
1092 .flags = BPF_F_AFTER | BPF_F_LINK,
1093 .relative_fd = bpf_program__fd(skel->progs.tc1),
1094 );
1095
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);
1099 goto cleanup;
1100 }
1101
1102 assert_mprog_count(target, 1);
1103
1104 LIBBPF_OPTS_RESET(optl,
1105 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1106 .relative_id = ~0,
1107 );
1108
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);
1112 goto cleanup;
1113 }
1114
1115 assert_mprog_count(target, 1);
1116
1117 LIBBPF_OPTS_RESET(optl,
1118 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1119 .relative_id = lid1,
1120 );
1121
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);
1125 goto cleanup;
1126 }
1127
1128 assert_mprog_count(target, 1);
1129
1130 LIBBPF_OPTS_RESET(optl,
1131 .flags = BPF_F_BEFORE | BPF_F_ID,
1132 .relative_id = pid1,
1133 );
1134
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);
1138 goto cleanup;
1139 }
1140 assert_mprog_count(target, 1);
1141
1142 LIBBPF_OPTS_RESET(optl,
1143 .flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,
1144 .relative_id = lid1,
1145 );
1146
1147 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1148 if (!ASSERT_OK_PTR(link, "link_attach"))
1149 goto cleanup;
1150
1151 skel->links.tc2 = link;
1152
1153 assert_mprog_count(target, 2);
1154 cleanup:
1155 test_tc_link__destroy(skel);
1156 assert_mprog_count(target, 0);
1157 }
1158
serial_test_tc_links_invalid(void)1159 void serial_test_tc_links_invalid(void)
1160 {
1161 test_tc_links_invalid_target(BPF_TCX_INGRESS);
1162 test_tc_links_invalid_target(BPF_TCX_EGRESS);
1163 }
1164
test_tc_links_prepend_target(int target)1165 static void test_tc_links_prepend_target(int target)
1166 {
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;
1174 int err;
1175
1176 skel = test_tc_link__open();
1177 if (!ASSERT_OK_PTR(skel, "skel_open"))
1178 goto cleanup;
1179
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");
1188
1189 err = test_tc_link__load(skel);
1190 if (!ASSERT_OK(err, "skel_load"))
1191 goto cleanup;
1192
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));
1197
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");
1201
1202 assert_mprog_count(target, 0);
1203
1204 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1205 if (!ASSERT_OK_PTR(link, "link_attach"))
1206 goto cleanup;
1207
1208 skel->links.tc1 = link;
1209
1210 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1211
1212 assert_mprog_count(target, 1);
1213
1214 LIBBPF_OPTS_RESET(optl,
1215 .flags = BPF_F_BEFORE,
1216 );
1217
1218 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1219 if (!ASSERT_OK_PTR(link, "link_attach"))
1220 goto cleanup;
1221
1222 skel->links.tc2 = link;
1223
1224 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1225
1226 assert_mprog_count(target, 2);
1227
1228 optq.prog_ids = prog_ids;
1229 optq.link_ids = link_ids;
1230
1231 memset(prog_ids, 0, sizeof(prog_ids));
1232 memset(link_ids, 0, sizeof(link_ids));
1233 optq.count = ARRAY_SIZE(prog_ids);
1234
1235 err = bpf_prog_query_opts(loopback, target, &optq);
1236 if (!ASSERT_OK(err, "prog_query"))
1237 goto cleanup;
1238
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]");
1247
1248 tc_skel_reset_all_seen(skel);
1249 ASSERT_OK(system(ping_cmd), ping_cmd);
1250
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");
1255
1256 LIBBPF_OPTS_RESET(optl,
1257 .flags = BPF_F_BEFORE,
1258 );
1259
1260 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1261 if (!ASSERT_OK_PTR(link, "link_attach"))
1262 goto cleanup;
1263
1264 skel->links.tc3 = link;
1265
1266 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1267
1268 LIBBPF_OPTS_RESET(optl,
1269 .flags = BPF_F_BEFORE,
1270 );
1271
1272 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1273 if (!ASSERT_OK_PTR(link, "link_attach"))
1274 goto cleanup;
1275
1276 skel->links.tc4 = link;
1277
1278 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1279
1280 assert_mprog_count(target, 4);
1281
1282 memset(prog_ids, 0, sizeof(prog_ids));
1283 memset(link_ids, 0, sizeof(link_ids));
1284 optq.count = ARRAY_SIZE(prog_ids);
1285
1286 err = bpf_prog_query_opts(loopback, target, &optq);
1287 if (!ASSERT_OK(err, "prog_query"))
1288 goto cleanup;
1289
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]");
1302
1303 tc_skel_reset_all_seen(skel);
1304 ASSERT_OK(system(ping_cmd), ping_cmd);
1305
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");
1310 cleanup:
1311 test_tc_link__destroy(skel);
1312 assert_mprog_count(target, 0);
1313 }
1314
serial_test_tc_links_prepend(void)1315 void serial_test_tc_links_prepend(void)
1316 {
1317 test_tc_links_prepend_target(BPF_TCX_INGRESS);
1318 test_tc_links_prepend_target(BPF_TCX_EGRESS);
1319 }
1320
test_tc_links_append_target(int target)1321 static void test_tc_links_append_target(int target)
1322 {
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;
1330 int err;
1331
1332 skel = test_tc_link__open();
1333 if (!ASSERT_OK_PTR(skel, "skel_open"))
1334 goto cleanup;
1335
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");
1344
1345 err = test_tc_link__load(skel);
1346 if (!ASSERT_OK(err, "skel_load"))
1347 goto cleanup;
1348
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));
1353
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");
1357
1358 assert_mprog_count(target, 0);
1359
1360 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1361 if (!ASSERT_OK_PTR(link, "link_attach"))
1362 goto cleanup;
1363
1364 skel->links.tc1 = link;
1365
1366 lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
1367
1368 assert_mprog_count(target, 1);
1369
1370 LIBBPF_OPTS_RESET(optl,
1371 .flags = BPF_F_AFTER,
1372 );
1373
1374 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1375 if (!ASSERT_OK_PTR(link, "link_attach"))
1376 goto cleanup;
1377
1378 skel->links.tc2 = link;
1379
1380 lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1381
1382 assert_mprog_count(target, 2);
1383
1384 optq.prog_ids = prog_ids;
1385 optq.link_ids = link_ids;
1386
1387 memset(prog_ids, 0, sizeof(prog_ids));
1388 memset(link_ids, 0, sizeof(link_ids));
1389 optq.count = ARRAY_SIZE(prog_ids);
1390
1391 err = bpf_prog_query_opts(loopback, target, &optq);
1392 if (!ASSERT_OK(err, "prog_query"))
1393 goto cleanup;
1394
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]");
1403
1404 tc_skel_reset_all_seen(skel);
1405 ASSERT_OK(system(ping_cmd), ping_cmd);
1406
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");
1411
1412 LIBBPF_OPTS_RESET(optl,
1413 .flags = BPF_F_AFTER,
1414 );
1415
1416 link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);
1417 if (!ASSERT_OK_PTR(link, "link_attach"))
1418 goto cleanup;
1419
1420 skel->links.tc3 = link;
1421
1422 lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));
1423
1424 LIBBPF_OPTS_RESET(optl,
1425 .flags = BPF_F_AFTER,
1426 );
1427
1428 link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1429 if (!ASSERT_OK_PTR(link, "link_attach"))
1430 goto cleanup;
1431
1432 skel->links.tc4 = link;
1433
1434 lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1435
1436 assert_mprog_count(target, 4);
1437
1438 memset(prog_ids, 0, sizeof(prog_ids));
1439 memset(link_ids, 0, sizeof(link_ids));
1440 optq.count = ARRAY_SIZE(prog_ids);
1441
1442 err = bpf_prog_query_opts(loopback, target, &optq);
1443 if (!ASSERT_OK(err, "prog_query"))
1444 goto cleanup;
1445
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]");
1458
1459 tc_skel_reset_all_seen(skel);
1460 ASSERT_OK(system(ping_cmd), ping_cmd);
1461
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");
1466 cleanup:
1467 test_tc_link__destroy(skel);
1468 assert_mprog_count(target, 0);
1469 }
1470
serial_test_tc_links_append(void)1471 void serial_test_tc_links_append(void)
1472 {
1473 test_tc_links_append_target(BPF_TCX_INGRESS);
1474 test_tc_links_append_target(BPF_TCX_EGRESS);
1475 }
1476
test_tc_links_dev_cleanup_target(int target)1477 static void test_tc_links_dev_cleanup_target(int target)
1478 {
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;
1484 int err, ifindex;
1485
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");
1489
1490 skel = test_tc_link__open();
1491 if (!ASSERT_OK_PTR(skel, "skel_open"))
1492 goto cleanup;
1493
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");
1502
1503 err = test_tc_link__load(skel);
1504 if (!ASSERT_OK(err, "skel_load"))
1505 goto cleanup;
1506
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));
1511
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");
1515
1516 assert_mprog_count(target, 0);
1517
1518 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1519 if (!ASSERT_OK_PTR(link, "link_attach"))
1520 goto cleanup;
1521
1522 skel->links.tc1 = link;
1523
1524 assert_mprog_count_ifindex(ifindex, target, 1);
1525
1526 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1527 if (!ASSERT_OK_PTR(link, "link_attach"))
1528 goto cleanup;
1529
1530 skel->links.tc2 = link;
1531
1532 assert_mprog_count_ifindex(ifindex, target, 2);
1533
1534 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1535 if (!ASSERT_OK_PTR(link, "link_attach"))
1536 goto cleanup;
1537
1538 skel->links.tc3 = link;
1539
1540 assert_mprog_count_ifindex(ifindex, target, 3);
1541
1542 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1543 if (!ASSERT_OK_PTR(link, "link_attach"))
1544 goto cleanup;
1545
1546 skel->links.tc4 = link;
1547
1548 assert_mprog_count_ifindex(ifindex, target, 4);
1549
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");
1553
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");
1558
1559 test_tc_link__destroy(skel);
1560 return;
1561 cleanup:
1562 test_tc_link__destroy(skel);
1563
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");
1567 }
1568
serial_test_tc_links_dev_cleanup(void)1569 void serial_test_tc_links_dev_cleanup(void)
1570 {
1571 test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);
1572 test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);
1573 }
1574
test_tc_chain_mixed(int target)1575 static void test_tc_chain_mixed(int target)
1576 {
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;
1583 int err;
1584
1585 skel = test_tc_link__open();
1586 if (!ASSERT_OK_PTR(skel, "skel_open"))
1587 goto cleanup;
1588
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");
1595
1596 err = test_tc_link__load(skel);
1597 if (!ASSERT_OK(err, "skel_load"))
1598 goto cleanup;
1599
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));
1603
1604 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1605 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1606
1607 assert_mprog_count(target, 0);
1608
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"))
1614 goto cleanup;
1615
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"))
1619 goto cleanup;
1620
1621 link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);
1622 if (!ASSERT_OK_PTR(link, "link_attach"))
1623 goto cleanup;
1624
1625 skel->links.tc6 = link;
1626
1627 assert_mprog_count(target, 1);
1628
1629 tc_skel_reset_all_seen(skel);
1630 ASSERT_OK(system(ping_cmd), ping_cmd);
1631
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");
1635
1636 err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
1637 if (!ASSERT_OK(err, "link_update"))
1638 goto cleanup;
1639
1640 assert_mprog_count(target, 1);
1641
1642 tc_skel_reset_all_seen(skel);
1643 ASSERT_OK(system(ping_cmd), ping_cmd);
1644
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");
1648
1649 err = bpf_link__detach(skel->links.tc6);
1650 if (!ASSERT_OK(err, "prog_detach"))
1651 goto cleanup;
1652
1653 assert_mprog_count(target, 0);
1654
1655 tc_skel_reset_all_seen(skel);
1656 ASSERT_OK(system(ping_cmd), ping_cmd);
1657
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");
1661
1662 cleanup:
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");
1666
1667 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
1668 bpf_tc_hook_destroy(&tc_hook);
1669
1670 test_tc_link__destroy(skel);
1671 }
1672
serial_test_tc_links_chain_mixed(void)1673 void serial_test_tc_links_chain_mixed(void)
1674 {
1675 test_tc_chain_mixed(BPF_TCX_INGRESS);
1676 test_tc_chain_mixed(BPF_TCX_EGRESS);
1677 }
1678
test_tc_links_ingress(int target,bool chain_tc_old,bool tcx_teardown_first)1679 static void test_tc_links_ingress(int target, bool chain_tc_old,
1680 bool tcx_teardown_first)
1681 {
1682 LIBBPF_OPTS(bpf_tc_opts, tc_opts,
1683 .handle = 1,
1684 .priority = 1,
1685 );
1686 LIBBPF_OPTS(bpf_tc_hook, tc_hook,
1687 .ifindex = loopback,
1688 .attach_point = BPF_TC_CUSTOM,
1689 .parent = TC_H_INGRESS,
1690 );
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;
1696 int err;
1697
1698 skel = test_tc_link__open();
1699 if (!ASSERT_OK_PTR(skel, "skel_open"))
1700 goto cleanup;
1701
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");
1706
1707 err = test_tc_link__load(skel);
1708 if (!ASSERT_OK(err, "skel_load"))
1709 goto cleanup;
1710
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));
1714
1715 ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1716 ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1717
1718 assert_mprog_count(target, 0);
1719
1720 if (chain_tc_old) {
1721 ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");
1722 hook_created = true;
1723
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"))
1727 goto cleanup;
1728 tc_attached = true;
1729 }
1730
1731 link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
1732 if (!ASSERT_OK_PTR(link, "link_attach"))
1733 goto cleanup;
1734
1735 skel->links.tc1 = link;
1736
1737 link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1738 if (!ASSERT_OK_PTR(link, "link_attach"))
1739 goto cleanup;
1740
1741 skel->links.tc2 = link;
1742
1743 assert_mprog_count(target, 2);
1744
1745 tc_skel_reset_all_seen(skel);
1746 ASSERT_OK(system(ping_cmd), ping_cmd);
1747
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");
1751
1752 err = bpf_link__detach(skel->links.tc2);
1753 if (!ASSERT_OK(err, "prog_detach"))
1754 goto cleanup;
1755
1756 assert_mprog_count(target, 1);
1757
1758 tc_skel_reset_all_seen(skel);
1759 ASSERT_OK(system(ping_cmd), ping_cmd);
1760
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");
1764 cleanup:
1765 if (tc_attached) {
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");
1769 }
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);
1781 }
1782
serial_test_tc_links_ingress(void)1783 void serial_test_tc_links_ingress(void)
1784 {
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);
1788 }
1789
test_tc_links_dev_mixed(int target)1790 static void test_tc_links_dev_mixed(int target)
1791 {
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;
1798 int err, ifindex;
1799
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");
1803
1804 skel = test_tc_link__open();
1805 if (!ASSERT_OK_PTR(skel, "skel_open"))
1806 goto cleanup;
1807
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");
1816
1817 err = test_tc_link__load(skel);
1818 if (!ASSERT_OK(err, "skel_load"))
1819 goto cleanup;
1820
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));
1825
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");
1829
1830 assert_mprog_count(target, 0);
1831
1832 link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
1833 if (!ASSERT_OK_PTR(link, "link_attach"))
1834 goto cleanup;
1835
1836 skel->links.tc1 = link;
1837
1838 assert_mprog_count_ifindex(ifindex, target, 1);
1839
1840 link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
1841 if (!ASSERT_OK_PTR(link, "link_attach"))
1842 goto cleanup;
1843
1844 skel->links.tc2 = link;
1845
1846 assert_mprog_count_ifindex(ifindex, target, 2);
1847
1848 link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
1849 if (!ASSERT_OK_PTR(link, "link_attach"))
1850 goto cleanup;
1851
1852 skel->links.tc3 = link;
1853
1854 assert_mprog_count_ifindex(ifindex, target, 3);
1855
1856 link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
1857 if (!ASSERT_OK_PTR(link, "link_attach"))
1858 goto cleanup;
1859
1860 skel->links.tc4 = link;
1861
1862 assert_mprog_count_ifindex(ifindex, target, 4);
1863
1864 tc_hook.ifindex = ifindex;
1865 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
1866 BPF_TC_INGRESS : BPF_TC_EGRESS;
1867
1868 err = bpf_tc_hook_create(&tc_hook);
1869 err = err == -EEXIST ? 0 : err;
1870 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
1871 goto cleanup;
1872
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"))
1876 goto cleanup;
1877
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");
1881
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");
1886
1887 test_tc_link__destroy(skel);
1888 return;
1889 cleanup:
1890 test_tc_link__destroy(skel);
1891
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");
1895 }
1896
serial_test_tc_links_dev_mixed(void)1897 void serial_test_tc_links_dev_mixed(void)
1898 {
1899 test_tc_links_dev_mixed(BPF_TCX_INGRESS);
1900 test_tc_links_dev_mixed(BPF_TCX_EGRESS);
1901 }
1902