Merge tag 'powerpc-6.6-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.git] / tools / testing / selftests / bpf / prog_tests / tc_links.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }