~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/tc_opts.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2023 Isovalent */
  3 #include <uapi/linux/if_link.h>
  4 #include <net/if.h>
  5 #include <test_progs.h>
  6 
  7 #define loopback 1
  8 #define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"
  9 
 10 #include "test_tc_link.skel.h"
 11 #include "tc_helpers.h"
 12 
 13 void serial_test_tc_opts_basic(void)
 14 {
 15         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
 16         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
 17         LIBBPF_OPTS(bpf_prog_query_opts, optq);
 18         __u32 fd1, fd2, id1, id2;
 19         struct test_tc_link *skel;
 20         __u32 prog_ids[2];
 21         int err;
 22 
 23         skel = test_tc_link__open_and_load();
 24         if (!ASSERT_OK_PTR(skel, "skel_load"))
 25                 goto cleanup;
 26 
 27         fd1 = bpf_program__fd(skel->progs.tc1);
 28         fd2 = bpf_program__fd(skel->progs.tc2);
 29 
 30         id1 = id_from_prog_fd(fd1);
 31         id2 = id_from_prog_fd(fd2);
 32 
 33         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
 34 
 35         assert_mprog_count(BPF_TCX_INGRESS, 0);
 36         assert_mprog_count(BPF_TCX_EGRESS, 0);
 37 
 38         ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
 39         ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
 40 
 41         err = bpf_prog_attach_opts(fd1, loopback, BPF_TCX_INGRESS, &opta);
 42         if (!ASSERT_EQ(err, 0, "prog_attach"))
 43                 goto cleanup;
 44 
 45         assert_mprog_count(BPF_TCX_INGRESS, 1);
 46         assert_mprog_count(BPF_TCX_EGRESS, 0);
 47 
 48         optq.prog_ids = prog_ids;
 49 
 50         memset(prog_ids, 0, sizeof(prog_ids));
 51         optq.count = ARRAY_SIZE(prog_ids);
 52 
 53         err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);
 54         if (!ASSERT_OK(err, "prog_query"))
 55                 goto cleanup_in;
 56 
 57         ASSERT_EQ(optq.count, 1, "count");
 58         ASSERT_EQ(optq.revision, 2, "revision");
 59         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
 60         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
 61 
 62         tc_skel_reset_all_seen(skel);
 63         ASSERT_OK(system(ping_cmd), ping_cmd);
 64 
 65         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
 66         ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
 67 
 68         err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta);
 69         if (!ASSERT_EQ(err, 0, "prog_attach"))
 70                 goto cleanup_in;
 71 
 72         assert_mprog_count(BPF_TCX_INGRESS, 1);
 73         assert_mprog_count(BPF_TCX_EGRESS, 1);
 74 
 75         memset(prog_ids, 0, sizeof(prog_ids));
 76         optq.count = ARRAY_SIZE(prog_ids);
 77 
 78         err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);
 79         if (!ASSERT_OK(err, "prog_query"))
 80                 goto cleanup_eg;
 81 
 82         ASSERT_EQ(optq.count, 1, "count");
 83         ASSERT_EQ(optq.revision, 2, "revision");
 84         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
 85         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
 86 
 87         tc_skel_reset_all_seen(skel);
 88         ASSERT_OK(system(ping_cmd), ping_cmd);
 89 
 90         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
 91         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
 92 
 93 cleanup_eg:
 94         err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd);
 95         ASSERT_OK(err, "prog_detach_eg");
 96 
 97         assert_mprog_count(BPF_TCX_INGRESS, 1);
 98         assert_mprog_count(BPF_TCX_EGRESS, 0);
 99 
100 cleanup_in:
101         err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd);
102         ASSERT_OK(err, "prog_detach_in");
103 
104         assert_mprog_count(BPF_TCX_INGRESS, 0);
105         assert_mprog_count(BPF_TCX_EGRESS, 0);
106 
107 cleanup:
108         test_tc_link__destroy(skel);
109 }
110 
111 static void test_tc_opts_before_target(int target)
112 {
113         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
114         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
115         LIBBPF_OPTS(bpf_prog_query_opts, optq);
116         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
117         struct test_tc_link *skel;
118         __u32 prog_ids[5];
119         int err;
120 
121         skel = test_tc_link__open_and_load();
122         if (!ASSERT_OK_PTR(skel, "skel_load"))
123                 goto cleanup;
124 
125         fd1 = bpf_program__fd(skel->progs.tc1);
126         fd2 = bpf_program__fd(skel->progs.tc2);
127         fd3 = bpf_program__fd(skel->progs.tc3);
128         fd4 = bpf_program__fd(skel->progs.tc4);
129 
130         id1 = id_from_prog_fd(fd1);
131         id2 = id_from_prog_fd(fd2);
132         id3 = id_from_prog_fd(fd3);
133         id4 = id_from_prog_fd(fd4);
134 
135         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
136         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
137         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
138 
139         assert_mprog_count(target, 0);
140 
141         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
142         if (!ASSERT_EQ(err, 0, "prog_attach"))
143                 goto cleanup;
144 
145         assert_mprog_count(target, 1);
146 
147         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
148         if (!ASSERT_EQ(err, 0, "prog_attach"))
149                 goto cleanup_target;
150 
151         assert_mprog_count(target, 2);
152 
153         optq.prog_ids = prog_ids;
154 
155         memset(prog_ids, 0, sizeof(prog_ids));
156         optq.count = ARRAY_SIZE(prog_ids);
157 
158         err = bpf_prog_query_opts(loopback, target, &optq);
159         if (!ASSERT_OK(err, "prog_query"))
160                 goto cleanup_target2;
161 
162         ASSERT_EQ(optq.count, 2, "count");
163         ASSERT_EQ(optq.revision, 3, "revision");
164         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
165         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
166         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
167 
168         tc_skel_reset_all_seen(skel);
169         ASSERT_OK(system(ping_cmd), ping_cmd);
170 
171         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
172         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
173         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
174         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
175 
176         LIBBPF_OPTS_RESET(opta,
177                 .flags = BPF_F_BEFORE,
178                 .relative_fd = fd2,
179         );
180 
181         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
182         if (!ASSERT_EQ(err, 0, "prog_attach"))
183                 goto cleanup_target2;
184 
185         memset(prog_ids, 0, sizeof(prog_ids));
186         optq.count = ARRAY_SIZE(prog_ids);
187 
188         err = bpf_prog_query_opts(loopback, target, &optq);
189         if (!ASSERT_OK(err, "prog_query"))
190                 goto cleanup_target3;
191 
192         ASSERT_EQ(optq.count, 3, "count");
193         ASSERT_EQ(optq.revision, 4, "revision");
194         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
195         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
196         ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
197         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
198 
199         LIBBPF_OPTS_RESET(opta,
200                 .flags = BPF_F_BEFORE,
201                 .relative_id = id1,
202         );
203 
204         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
205         if (!ASSERT_EQ(err, 0, "prog_attach"))
206                 goto cleanup_target3;
207 
208         assert_mprog_count(target, 4);
209 
210         memset(prog_ids, 0, sizeof(prog_ids));
211         optq.count = ARRAY_SIZE(prog_ids);
212 
213         err = bpf_prog_query_opts(loopback, target, &optq);
214         if (!ASSERT_OK(err, "prog_query"))
215                 goto cleanup_target4;
216 
217         ASSERT_EQ(optq.count, 4, "count");
218         ASSERT_EQ(optq.revision, 5, "revision");
219         ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
220         ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
221         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
222         ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");
223         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
224 
225         tc_skel_reset_all_seen(skel);
226         ASSERT_OK(system(ping_cmd), ping_cmd);
227 
228         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
229         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
230         ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
231         ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
232 
233 cleanup_target4:
234         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
235         ASSERT_OK(err, "prog_detach");
236         assert_mprog_count(target, 3);
237 
238 cleanup_target3:
239         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
240         ASSERT_OK(err, "prog_detach");
241         assert_mprog_count(target, 2);
242 
243 cleanup_target2:
244         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
245         ASSERT_OK(err, "prog_detach");
246         assert_mprog_count(target, 1);
247 
248 cleanup_target:
249         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
250         ASSERT_OK(err, "prog_detach");
251         assert_mprog_count(target, 0);
252 
253 cleanup:
254         test_tc_link__destroy(skel);
255 }
256 
257 void serial_test_tc_opts_before(void)
258 {
259         test_tc_opts_before_target(BPF_TCX_INGRESS);
260         test_tc_opts_before_target(BPF_TCX_EGRESS);
261 }
262 
263 static void test_tc_opts_after_target(int target)
264 {
265         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
266         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
267         LIBBPF_OPTS(bpf_prog_query_opts, optq);
268         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
269         struct test_tc_link *skel;
270         __u32 prog_ids[5];
271         int err;
272 
273         skel = test_tc_link__open_and_load();
274         if (!ASSERT_OK_PTR(skel, "skel_load"))
275                 goto cleanup;
276 
277         fd1 = bpf_program__fd(skel->progs.tc1);
278         fd2 = bpf_program__fd(skel->progs.tc2);
279         fd3 = bpf_program__fd(skel->progs.tc3);
280         fd4 = bpf_program__fd(skel->progs.tc4);
281 
282         id1 = id_from_prog_fd(fd1);
283         id2 = id_from_prog_fd(fd2);
284         id3 = id_from_prog_fd(fd3);
285         id4 = id_from_prog_fd(fd4);
286 
287         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
288         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
289         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
290 
291         assert_mprog_count(target, 0);
292 
293         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
294         if (!ASSERT_EQ(err, 0, "prog_attach"))
295                 goto cleanup;
296 
297         assert_mprog_count(target, 1);
298 
299         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
300         if (!ASSERT_EQ(err, 0, "prog_attach"))
301                 goto cleanup_target;
302 
303         assert_mprog_count(target, 2);
304 
305         optq.prog_ids = prog_ids;
306 
307         memset(prog_ids, 0, sizeof(prog_ids));
308         optq.count = ARRAY_SIZE(prog_ids);
309 
310         err = bpf_prog_query_opts(loopback, target, &optq);
311         if (!ASSERT_OK(err, "prog_query"))
312                 goto cleanup_target2;
313 
314         ASSERT_EQ(optq.count, 2, "count");
315         ASSERT_EQ(optq.revision, 3, "revision");
316         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
317         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
318         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
319 
320         tc_skel_reset_all_seen(skel);
321         ASSERT_OK(system(ping_cmd), ping_cmd);
322 
323         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
324         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
325         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
326         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
327 
328         LIBBPF_OPTS_RESET(opta,
329                 .flags = BPF_F_AFTER,
330                 .relative_fd = fd1,
331         );
332 
333         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
334         if (!ASSERT_EQ(err, 0, "prog_attach"))
335                 goto cleanup_target2;
336 
337         memset(prog_ids, 0, sizeof(prog_ids));
338         optq.count = ARRAY_SIZE(prog_ids);
339 
340         err = bpf_prog_query_opts(loopback, target, &optq);
341         if (!ASSERT_OK(err, "prog_query"))
342                 goto cleanup_target3;
343 
344         ASSERT_EQ(optq.count, 3, "count");
345         ASSERT_EQ(optq.revision, 4, "revision");
346         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
347         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
348         ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
349         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
350 
351         LIBBPF_OPTS_RESET(opta,
352                 .flags = BPF_F_AFTER,
353                 .relative_id = id2,
354         );
355 
356         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
357         if (!ASSERT_EQ(err, 0, "prog_attach"))
358                 goto cleanup_target3;
359 
360         assert_mprog_count(target, 4);
361 
362         memset(prog_ids, 0, sizeof(prog_ids));
363         optq.count = ARRAY_SIZE(prog_ids);
364 
365         err = bpf_prog_query_opts(loopback, target, &optq);
366         if (!ASSERT_OK(err, "prog_query"))
367                 goto cleanup_target4;
368 
369         ASSERT_EQ(optq.count, 4, "count");
370         ASSERT_EQ(optq.revision, 5, "revision");
371         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
372         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
373         ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
374         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
375         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
376 
377         tc_skel_reset_all_seen(skel);
378         ASSERT_OK(system(ping_cmd), ping_cmd);
379 
380         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
381         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
382         ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
383         ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
384 
385 cleanup_target4:
386         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
387         ASSERT_OK(err, "prog_detach");
388         assert_mprog_count(target, 3);
389 
390         memset(prog_ids, 0, sizeof(prog_ids));
391         optq.count = ARRAY_SIZE(prog_ids);
392 
393         err = bpf_prog_query_opts(loopback, target, &optq);
394         if (!ASSERT_OK(err, "prog_query"))
395                 goto cleanup_target3;
396 
397         ASSERT_EQ(optq.count, 3, "count");
398         ASSERT_EQ(optq.revision, 6, "revision");
399         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
400         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
401         ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
402         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
403 
404 cleanup_target3:
405         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
406         ASSERT_OK(err, "prog_detach");
407         assert_mprog_count(target, 2);
408 
409         memset(prog_ids, 0, sizeof(prog_ids));
410         optq.count = ARRAY_SIZE(prog_ids);
411 
412         err = bpf_prog_query_opts(loopback, target, &optq);
413         if (!ASSERT_OK(err, "prog_query"))
414                 goto cleanup_target2;
415 
416         ASSERT_EQ(optq.count, 2, "count");
417         ASSERT_EQ(optq.revision, 7, "revision");
418         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
419         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
420         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
421 
422 cleanup_target2:
423         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
424         ASSERT_OK(err, "prog_detach");
425         assert_mprog_count(target, 1);
426 
427         memset(prog_ids, 0, sizeof(prog_ids));
428         optq.count = ARRAY_SIZE(prog_ids);
429 
430         err = bpf_prog_query_opts(loopback, target, &optq);
431         if (!ASSERT_OK(err, "prog_query"))
432                 goto cleanup_target;
433 
434         ASSERT_EQ(optq.count, 1, "count");
435         ASSERT_EQ(optq.revision, 8, "revision");
436         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
437         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
438 
439 cleanup_target:
440         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
441         ASSERT_OK(err, "prog_detach");
442         assert_mprog_count(target, 0);
443 
444 cleanup:
445         test_tc_link__destroy(skel);
446 }
447 
448 void serial_test_tc_opts_after(void)
449 {
450         test_tc_opts_after_target(BPF_TCX_INGRESS);
451         test_tc_opts_after_target(BPF_TCX_EGRESS);
452 }
453 
454 static void test_tc_opts_revision_target(int target)
455 {
456         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
457         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
458         LIBBPF_OPTS(bpf_prog_query_opts, optq);
459         __u32 fd1, fd2, id1, id2;
460         struct test_tc_link *skel;
461         __u32 prog_ids[3];
462         int err;
463 
464         skel = test_tc_link__open_and_load();
465         if (!ASSERT_OK_PTR(skel, "skel_load"))
466                 goto cleanup;
467 
468         fd1 = bpf_program__fd(skel->progs.tc1);
469         fd2 = bpf_program__fd(skel->progs.tc2);
470 
471         id1 = id_from_prog_fd(fd1);
472         id2 = id_from_prog_fd(fd2);
473 
474         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
475 
476         assert_mprog_count(target, 0);
477 
478         LIBBPF_OPTS_RESET(opta,
479                 .expected_revision = 1,
480         );
481 
482         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
483         if (!ASSERT_EQ(err, 0, "prog_attach"))
484                 goto cleanup;
485 
486         assert_mprog_count(target, 1);
487 
488         LIBBPF_OPTS_RESET(opta,
489                 .expected_revision = 1,
490         );
491 
492         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
493         if (!ASSERT_EQ(err, -ESTALE, "prog_attach"))
494                 goto cleanup_target;
495 
496         assert_mprog_count(target, 1);
497 
498         LIBBPF_OPTS_RESET(opta,
499                 .expected_revision = 2,
500         );
501 
502         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
503         if (!ASSERT_EQ(err, 0, "prog_attach"))
504                 goto cleanup_target;
505 
506         assert_mprog_count(target, 2);
507 
508         optq.prog_ids = prog_ids;
509 
510         memset(prog_ids, 0, sizeof(prog_ids));
511         optq.count = ARRAY_SIZE(prog_ids);
512 
513         err = bpf_prog_query_opts(loopback, target, &optq);
514         if (!ASSERT_OK(err, "prog_query"))
515                 goto cleanup_target2;
516 
517         ASSERT_EQ(optq.count, 2, "count");
518         ASSERT_EQ(optq.revision, 3, "revision");
519         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
520         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
521         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
522 
523         tc_skel_reset_all_seen(skel);
524         ASSERT_OK(system(ping_cmd), ping_cmd);
525 
526         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
527         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
528 
529         LIBBPF_OPTS_RESET(optd,
530                 .expected_revision = 2,
531         );
532 
533         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
534         ASSERT_EQ(err, -ESTALE, "prog_detach");
535         assert_mprog_count(target, 2);
536 
537 cleanup_target2:
538         LIBBPF_OPTS_RESET(optd,
539                 .expected_revision = 3,
540         );
541 
542         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
543         ASSERT_OK(err, "prog_detach");
544         assert_mprog_count(target, 1);
545 
546 cleanup_target:
547         LIBBPF_OPTS_RESET(optd);
548 
549         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
550         ASSERT_OK(err, "prog_detach");
551         assert_mprog_count(target, 0);
552 
553 cleanup:
554         test_tc_link__destroy(skel);
555 }
556 
557 void serial_test_tc_opts_revision(void)
558 {
559         test_tc_opts_revision_target(BPF_TCX_INGRESS);
560         test_tc_opts_revision_target(BPF_TCX_EGRESS);
561 }
562 
563 static void test_tc_chain_classic(int target, bool chain_tc_old)
564 {
565         LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
566         LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
567         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
568         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
569         bool hook_created = false, tc_attached = false;
570         __u32 fd1, fd2, fd3, id1, id2, id3;
571         struct test_tc_link *skel;
572         int err;
573 
574         skel = test_tc_link__open_and_load();
575         if (!ASSERT_OK_PTR(skel, "skel_load"))
576                 goto cleanup;
577 
578         fd1 = bpf_program__fd(skel->progs.tc1);
579         fd2 = bpf_program__fd(skel->progs.tc2);
580         fd3 = bpf_program__fd(skel->progs.tc3);
581 
582         id1 = id_from_prog_fd(fd1);
583         id2 = id_from_prog_fd(fd2);
584         id3 = id_from_prog_fd(fd3);
585 
586         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
587         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
588 
589         assert_mprog_count(target, 0);
590 
591         if (chain_tc_old) {
592                 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
593                                        BPF_TC_INGRESS : BPF_TC_EGRESS;
594                 err = bpf_tc_hook_create(&tc_hook);
595                 if (err == 0)
596                         hook_created = true;
597                 err = err == -EEXIST ? 0 : err;
598                 if (!ASSERT_OK(err, "bpf_tc_hook_create"))
599                         goto cleanup;
600 
601                 tc_opts.prog_fd = fd3;
602                 err = bpf_tc_attach(&tc_hook, &tc_opts);
603                 if (!ASSERT_OK(err, "bpf_tc_attach"))
604                         goto cleanup;
605                 tc_attached = true;
606         }
607 
608         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
609         if (!ASSERT_EQ(err, 0, "prog_attach"))
610                 goto cleanup;
611 
612         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
613         if (!ASSERT_EQ(err, 0, "prog_attach"))
614                 goto cleanup_detach;
615 
616         assert_mprog_count(target, 2);
617 
618         tc_skel_reset_all_seen(skel);
619         ASSERT_OK(system(ping_cmd), ping_cmd);
620 
621         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
622         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
623         ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
624 
625         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
626         if (!ASSERT_OK(err, "prog_detach"))
627                 goto cleanup_detach;
628 
629         assert_mprog_count(target, 1);
630 
631         tc_skel_reset_all_seen(skel);
632         ASSERT_OK(system(ping_cmd), ping_cmd);
633 
634         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
635         ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
636         ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
637 
638 cleanup_detach:
639         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
640         if (!ASSERT_OK(err, "prog_detach"))
641                 goto cleanup;
642 
643         assert_mprog_count(target, 0);
644 cleanup:
645         if (tc_attached) {
646                 tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
647                 err = bpf_tc_detach(&tc_hook, &tc_opts);
648                 ASSERT_OK(err, "bpf_tc_detach");
649         }
650         if (hook_created) {
651                 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
652                 bpf_tc_hook_destroy(&tc_hook);
653         }
654         test_tc_link__destroy(skel);
655         assert_mprog_count(target, 0);
656 }
657 
658 void serial_test_tc_opts_chain_classic(void)
659 {
660         test_tc_chain_classic(BPF_TCX_INGRESS, false);
661         test_tc_chain_classic(BPF_TCX_EGRESS, false);
662         test_tc_chain_classic(BPF_TCX_INGRESS, true);
663         test_tc_chain_classic(BPF_TCX_EGRESS, true);
664 }
665 
666 static void test_tc_opts_replace_target(int target)
667 {
668         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
669         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
670         LIBBPF_OPTS(bpf_prog_query_opts, optq);
671         __u32 fd1, fd2, fd3, id1, id2, id3, detach_fd;
672         __u32 prog_ids[4], prog_flags[4];
673         struct test_tc_link *skel;
674         int err;
675 
676         skel = test_tc_link__open_and_load();
677         if (!ASSERT_OK_PTR(skel, "skel_load"))
678                 goto cleanup;
679 
680         fd1 = bpf_program__fd(skel->progs.tc1);
681         fd2 = bpf_program__fd(skel->progs.tc2);
682         fd3 = bpf_program__fd(skel->progs.tc3);
683 
684         id1 = id_from_prog_fd(fd1);
685         id2 = id_from_prog_fd(fd2);
686         id3 = id_from_prog_fd(fd3);
687 
688         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
689         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
690 
691         assert_mprog_count(target, 0);
692 
693         LIBBPF_OPTS_RESET(opta,
694                 .expected_revision = 1,
695         );
696 
697         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
698         if (!ASSERT_EQ(err, 0, "prog_attach"))
699                 goto cleanup;
700 
701         assert_mprog_count(target, 1);
702 
703         LIBBPF_OPTS_RESET(opta,
704                 .flags = BPF_F_BEFORE,
705                 .relative_id = id1,
706                 .expected_revision = 2,
707         );
708 
709         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
710         if (!ASSERT_EQ(err, 0, "prog_attach"))
711                 goto cleanup_target;
712 
713         detach_fd = fd2;
714 
715         assert_mprog_count(target, 2);
716 
717         optq.prog_attach_flags = prog_flags;
718         optq.prog_ids = prog_ids;
719 
720         memset(prog_flags, 0, sizeof(prog_flags));
721         memset(prog_ids, 0, sizeof(prog_ids));
722         optq.count = ARRAY_SIZE(prog_ids);
723 
724         err = bpf_prog_query_opts(loopback, target, &optq);
725         if (!ASSERT_OK(err, "prog_query"))
726                 goto cleanup_target2;
727 
728         ASSERT_EQ(optq.count, 2, "count");
729         ASSERT_EQ(optq.revision, 3, "revision");
730         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
731         ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
732         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
733 
734         ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
735         ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
736         ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
737 
738         tc_skel_reset_all_seen(skel);
739         ASSERT_OK(system(ping_cmd), ping_cmd);
740 
741         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
742         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
743         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
744 
745         LIBBPF_OPTS_RESET(opta,
746                 .flags = BPF_F_REPLACE,
747                 .replace_prog_fd = fd2,
748                 .expected_revision = 3,
749         );
750 
751         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
752         if (!ASSERT_EQ(err, 0, "prog_attach"))
753                 goto cleanup_target2;
754 
755         detach_fd = fd3;
756 
757         assert_mprog_count(target, 2);
758 
759         memset(prog_ids, 0, sizeof(prog_ids));
760         optq.count = ARRAY_SIZE(prog_ids);
761 
762         err = bpf_prog_query_opts(loopback, target, &optq);
763         if (!ASSERT_OK(err, "prog_query"))
764                 goto cleanup_target2;
765 
766         ASSERT_EQ(optq.count, 2, "count");
767         ASSERT_EQ(optq.revision, 4, "revision");
768         ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
769         ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
770         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
771 
772         tc_skel_reset_all_seen(skel);
773         ASSERT_OK(system(ping_cmd), ping_cmd);
774 
775         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
776         ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
777         ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
778 
779         LIBBPF_OPTS_RESET(opta,
780                 .flags = BPF_F_REPLACE | BPF_F_BEFORE,
781                 .replace_prog_fd = fd3,
782                 .relative_fd = fd1,
783                 .expected_revision = 4,
784         );
785 
786         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
787         if (!ASSERT_EQ(err, 0, "prog_attach"))
788                 goto cleanup_target2;
789 
790         detach_fd = fd2;
791 
792         assert_mprog_count(target, 2);
793 
794         memset(prog_ids, 0, sizeof(prog_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_target2;
800 
801         ASSERT_EQ(optq.count, 2, "count");
802         ASSERT_EQ(optq.revision, 5, "revision");
803         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
804         ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
805         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
806 
807         tc_skel_reset_all_seen(skel);
808         ASSERT_OK(system(ping_cmd), ping_cmd);
809 
810         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
811         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
812         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
813 
814         LIBBPF_OPTS_RESET(opta,
815                 .flags = BPF_F_REPLACE,
816                 .replace_prog_fd = fd2,
817         );
818 
819         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
820         ASSERT_EQ(err, -EEXIST, "prog_attach");
821         assert_mprog_count(target, 2);
822 
823         LIBBPF_OPTS_RESET(opta,
824                 .flags = BPF_F_REPLACE | BPF_F_AFTER,
825                 .replace_prog_fd = fd2,
826                 .relative_fd = fd1,
827                 .expected_revision = 5,
828         );
829 
830         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
831         ASSERT_EQ(err, -ERANGE, "prog_attach");
832         assert_mprog_count(target, 2);
833 
834         LIBBPF_OPTS_RESET(opta,
835                 .flags = BPF_F_BEFORE | BPF_F_AFTER | BPF_F_REPLACE,
836                 .replace_prog_fd = fd2,
837                 .relative_fd = fd1,
838                 .expected_revision = 5,
839         );
840 
841         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
842         ASSERT_EQ(err, -ERANGE, "prog_attach");
843         assert_mprog_count(target, 2);
844 
845         LIBBPF_OPTS_RESET(optd,
846                 .flags = BPF_F_BEFORE,
847                 .relative_id = id1,
848                 .expected_revision = 5,
849         );
850 
851 cleanup_target2:
852         err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
853         ASSERT_OK(err, "prog_detach");
854         assert_mprog_count(target, 1);
855 
856 cleanup_target:
857         LIBBPF_OPTS_RESET(optd);
858 
859         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
860         ASSERT_OK(err, "prog_detach");
861         assert_mprog_count(target, 0);
862 
863 cleanup:
864         test_tc_link__destroy(skel);
865 }
866 
867 void serial_test_tc_opts_replace(void)
868 {
869         test_tc_opts_replace_target(BPF_TCX_INGRESS);
870         test_tc_opts_replace_target(BPF_TCX_EGRESS);
871 }
872 
873 static void test_tc_opts_invalid_target(int target)
874 {
875         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
876         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
877         __u32 fd1, fd2, id1, id2;
878         struct test_tc_link *skel;
879         int err;
880 
881         skel = test_tc_link__open_and_load();
882         if (!ASSERT_OK_PTR(skel, "skel_load"))
883                 goto cleanup;
884 
885         fd1 = bpf_program__fd(skel->progs.tc1);
886         fd2 = bpf_program__fd(skel->progs.tc2);
887 
888         id1 = id_from_prog_fd(fd1);
889         id2 = id_from_prog_fd(fd2);
890 
891         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
892 
893         assert_mprog_count(target, 0);
894 
895         LIBBPF_OPTS_RESET(opta,
896                 .flags = BPF_F_BEFORE | BPF_F_AFTER,
897         );
898 
899         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
900         ASSERT_EQ(err, -ERANGE, "prog_attach");
901         assert_mprog_count(target, 0);
902 
903         LIBBPF_OPTS_RESET(opta,
904                 .flags = BPF_F_BEFORE | BPF_F_ID,
905         );
906 
907         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
908         ASSERT_EQ(err, -ENOENT, "prog_attach");
909         assert_mprog_count(target, 0);
910 
911         LIBBPF_OPTS_RESET(opta,
912                 .flags = BPF_F_AFTER | BPF_F_ID,
913         );
914 
915         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
916         ASSERT_EQ(err, -ENOENT, "prog_attach");
917         assert_mprog_count(target, 0);
918 
919         LIBBPF_OPTS_RESET(opta,
920                 .relative_fd = fd2,
921         );
922 
923         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
924         ASSERT_EQ(err, -EINVAL, "prog_attach");
925         assert_mprog_count(target, 0);
926 
927         LIBBPF_OPTS_RESET(opta,
928                 .flags = BPF_F_BEFORE | BPF_F_AFTER,
929                 .relative_fd = fd2,
930         );
931 
932         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
933         ASSERT_EQ(err, -ENOENT, "prog_attach");
934         assert_mprog_count(target, 0);
935 
936         LIBBPF_OPTS_RESET(opta,
937                 .flags = BPF_F_ID,
938                 .relative_id = id2,
939         );
940 
941         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
942         ASSERT_EQ(err, -EINVAL, "prog_attach");
943         assert_mprog_count(target, 0);
944 
945         LIBBPF_OPTS_RESET(opta,
946                 .flags = BPF_F_BEFORE,
947                 .relative_fd = fd1,
948         );
949 
950         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
951         ASSERT_EQ(err, -ENOENT, "prog_attach");
952         assert_mprog_count(target, 0);
953 
954         LIBBPF_OPTS_RESET(opta,
955                 .flags = BPF_F_AFTER,
956                 .relative_fd = fd1,
957         );
958 
959         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
960         ASSERT_EQ(err, -ENOENT, "prog_attach");
961         assert_mprog_count(target, 0);
962 
963         LIBBPF_OPTS_RESET(opta);
964 
965         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
966         if (!ASSERT_EQ(err, 0, "prog_attach"))
967                 goto cleanup;
968 
969         assert_mprog_count(target, 1);
970 
971         LIBBPF_OPTS_RESET(opta);
972 
973         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
974         ASSERT_EQ(err, -EEXIST, "prog_attach");
975         assert_mprog_count(target, 1);
976 
977         LIBBPF_OPTS_RESET(opta,
978                 .flags = BPF_F_BEFORE,
979                 .relative_fd = fd1,
980         );
981 
982         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
983         ASSERT_EQ(err, -EEXIST, "prog_attach");
984         assert_mprog_count(target, 1);
985 
986         LIBBPF_OPTS_RESET(opta,
987                 .flags = BPF_F_AFTER,
988                 .relative_fd = fd1,
989         );
990 
991         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
992         ASSERT_EQ(err, -EEXIST, "prog_attach");
993         assert_mprog_count(target, 1);
994 
995         LIBBPF_OPTS_RESET(opta,
996                 .flags = BPF_F_REPLACE,
997                 .relative_fd = fd1,
998         );
999 
1000         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1001         ASSERT_EQ(err, -EINVAL, "prog_attach_x1");
1002         assert_mprog_count(target, 1);
1003 
1004         LIBBPF_OPTS_RESET(opta,
1005                 .flags = BPF_F_REPLACE,
1006                 .replace_prog_fd = fd1,
1007         );
1008 
1009         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1010         ASSERT_EQ(err, -EEXIST, "prog_attach");
1011         assert_mprog_count(target, 1);
1012 
1013         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1014         ASSERT_OK(err, "prog_detach");
1015         assert_mprog_count(target, 0);
1016 cleanup:
1017         test_tc_link__destroy(skel);
1018 }
1019 
1020 void serial_test_tc_opts_invalid(void)
1021 {
1022         test_tc_opts_invalid_target(BPF_TCX_INGRESS);
1023         test_tc_opts_invalid_target(BPF_TCX_EGRESS);
1024 }
1025 
1026 static void test_tc_opts_prepend_target(int target)
1027 {
1028         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1029         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1030         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1031         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1032         struct test_tc_link *skel;
1033         __u32 prog_ids[5];
1034         int err;
1035 
1036         skel = test_tc_link__open_and_load();
1037         if (!ASSERT_OK_PTR(skel, "skel_load"))
1038                 goto cleanup;
1039 
1040         fd1 = bpf_program__fd(skel->progs.tc1);
1041         fd2 = bpf_program__fd(skel->progs.tc2);
1042         fd3 = bpf_program__fd(skel->progs.tc3);
1043         fd4 = bpf_program__fd(skel->progs.tc4);
1044 
1045         id1 = id_from_prog_fd(fd1);
1046         id2 = id_from_prog_fd(fd2);
1047         id3 = id_from_prog_fd(fd3);
1048         id4 = id_from_prog_fd(fd4);
1049 
1050         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1051         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1052         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1053 
1054         assert_mprog_count(target, 0);
1055 
1056         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1057         if (!ASSERT_EQ(err, 0, "prog_attach"))
1058                 goto cleanup;
1059 
1060         assert_mprog_count(target, 1);
1061 
1062         LIBBPF_OPTS_RESET(opta,
1063                 .flags = BPF_F_BEFORE,
1064         );
1065 
1066         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1067         if (!ASSERT_EQ(err, 0, "prog_attach"))
1068                 goto cleanup_target;
1069 
1070         assert_mprog_count(target, 2);
1071 
1072         optq.prog_ids = prog_ids;
1073 
1074         memset(prog_ids, 0, sizeof(prog_ids));
1075         optq.count = ARRAY_SIZE(prog_ids);
1076 
1077         err = bpf_prog_query_opts(loopback, target, &optq);
1078         if (!ASSERT_OK(err, "prog_query"))
1079                 goto cleanup_target2;
1080 
1081         ASSERT_EQ(optq.count, 2, "count");
1082         ASSERT_EQ(optq.revision, 3, "revision");
1083         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1084         ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
1085         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1086 
1087         tc_skel_reset_all_seen(skel);
1088         ASSERT_OK(system(ping_cmd), ping_cmd);
1089 
1090         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1091         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1092         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1093         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1094 
1095         LIBBPF_OPTS_RESET(opta,
1096                 .flags = BPF_F_BEFORE,
1097         );
1098 
1099         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1100         if (!ASSERT_EQ(err, 0, "prog_attach"))
1101                 goto cleanup_target2;
1102 
1103         LIBBPF_OPTS_RESET(opta,
1104                 .flags = BPF_F_BEFORE,
1105         );
1106 
1107         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1108         if (!ASSERT_EQ(err, 0, "prog_attach"))
1109                 goto cleanup_target3;
1110 
1111         assert_mprog_count(target, 4);
1112 
1113         memset(prog_ids, 0, sizeof(prog_ids));
1114         optq.count = ARRAY_SIZE(prog_ids);
1115 
1116         err = bpf_prog_query_opts(loopback, target, &optq);
1117         if (!ASSERT_OK(err, "prog_query"))
1118                 goto cleanup_target4;
1119 
1120         ASSERT_EQ(optq.count, 4, "count");
1121         ASSERT_EQ(optq.revision, 5, "revision");
1122         ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1123         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1124         ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");
1125         ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");
1126         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1127 
1128         tc_skel_reset_all_seen(skel);
1129         ASSERT_OK(system(ping_cmd), ping_cmd);
1130 
1131         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1132         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1133         ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1134         ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1135 
1136 cleanup_target4:
1137         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1138         ASSERT_OK(err, "prog_detach");
1139         assert_mprog_count(target, 3);
1140 
1141 cleanup_target3:
1142         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1143         ASSERT_OK(err, "prog_detach");
1144         assert_mprog_count(target, 2);
1145 
1146 cleanup_target2:
1147         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1148         ASSERT_OK(err, "prog_detach");
1149         assert_mprog_count(target, 1);
1150 
1151 cleanup_target:
1152         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1153         ASSERT_OK(err, "prog_detach");
1154         assert_mprog_count(target, 0);
1155 
1156 cleanup:
1157         test_tc_link__destroy(skel);
1158 }
1159 
1160 void serial_test_tc_opts_prepend(void)
1161 {
1162         test_tc_opts_prepend_target(BPF_TCX_INGRESS);
1163         test_tc_opts_prepend_target(BPF_TCX_EGRESS);
1164 }
1165 
1166 static void test_tc_opts_append_target(int target)
1167 {
1168         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1169         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1170         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1171         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1172         struct test_tc_link *skel;
1173         __u32 prog_ids[5];
1174         int err;
1175 
1176         skel = test_tc_link__open_and_load();
1177         if (!ASSERT_OK_PTR(skel, "skel_load"))
1178                 goto cleanup;
1179 
1180         fd1 = bpf_program__fd(skel->progs.tc1);
1181         fd2 = bpf_program__fd(skel->progs.tc2);
1182         fd3 = bpf_program__fd(skel->progs.tc3);
1183         fd4 = bpf_program__fd(skel->progs.tc4);
1184 
1185         id1 = id_from_prog_fd(fd1);
1186         id2 = id_from_prog_fd(fd2);
1187         id3 = id_from_prog_fd(fd3);
1188         id4 = id_from_prog_fd(fd4);
1189 
1190         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1191         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1192         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1193 
1194         assert_mprog_count(target, 0);
1195 
1196         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1197         if (!ASSERT_EQ(err, 0, "prog_attach"))
1198                 goto cleanup;
1199 
1200         assert_mprog_count(target, 1);
1201 
1202         LIBBPF_OPTS_RESET(opta,
1203                 .flags = BPF_F_AFTER,
1204         );
1205 
1206         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1207         if (!ASSERT_EQ(err, 0, "prog_attach"))
1208                 goto cleanup_target;
1209 
1210         assert_mprog_count(target, 2);
1211 
1212         optq.prog_ids = prog_ids;
1213 
1214         memset(prog_ids, 0, sizeof(prog_ids));
1215         optq.count = ARRAY_SIZE(prog_ids);
1216 
1217         err = bpf_prog_query_opts(loopback, target, &optq);
1218         if (!ASSERT_OK(err, "prog_query"))
1219                 goto cleanup_target2;
1220 
1221         ASSERT_EQ(optq.count, 2, "count");
1222         ASSERT_EQ(optq.revision, 3, "revision");
1223         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1224         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1225         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1226 
1227         tc_skel_reset_all_seen(skel);
1228         ASSERT_OK(system(ping_cmd), ping_cmd);
1229 
1230         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1231         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1232         ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
1233         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
1234 
1235         LIBBPF_OPTS_RESET(opta,
1236                 .flags = BPF_F_AFTER,
1237         );
1238 
1239         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1240         if (!ASSERT_EQ(err, 0, "prog_attach"))
1241                 goto cleanup_target2;
1242 
1243         LIBBPF_OPTS_RESET(opta,
1244                 .flags = BPF_F_AFTER,
1245         );
1246 
1247         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1248         if (!ASSERT_EQ(err, 0, "prog_attach"))
1249                 goto cleanup_target3;
1250 
1251         assert_mprog_count(target, 4);
1252 
1253         memset(prog_ids, 0, sizeof(prog_ids));
1254         optq.count = ARRAY_SIZE(prog_ids);
1255 
1256         err = bpf_prog_query_opts(loopback, target, &optq);
1257         if (!ASSERT_OK(err, "prog_query"))
1258                 goto cleanup_target4;
1259 
1260         ASSERT_EQ(optq.count, 4, "count");
1261         ASSERT_EQ(optq.revision, 5, "revision");
1262         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1263         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1264         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1265         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1266         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1267 
1268         tc_skel_reset_all_seen(skel);
1269         ASSERT_OK(system(ping_cmd), ping_cmd);
1270 
1271         ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
1272         ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
1273         ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
1274         ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
1275 
1276 cleanup_target4:
1277         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1278         ASSERT_OK(err, "prog_detach");
1279         assert_mprog_count(target, 3);
1280 
1281 cleanup_target3:
1282         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1283         ASSERT_OK(err, "prog_detach");
1284         assert_mprog_count(target, 2);
1285 
1286 cleanup_target2:
1287         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1288         ASSERT_OK(err, "prog_detach");
1289         assert_mprog_count(target, 1);
1290 
1291 cleanup_target:
1292         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1293         ASSERT_OK(err, "prog_detach");
1294         assert_mprog_count(target, 0);
1295 
1296 cleanup:
1297         test_tc_link__destroy(skel);
1298 }
1299 
1300 void serial_test_tc_opts_append(void)
1301 {
1302         test_tc_opts_append_target(BPF_TCX_INGRESS);
1303         test_tc_opts_append_target(BPF_TCX_EGRESS);
1304 }
1305 
1306 static void test_tc_opts_dev_cleanup_target(int target)
1307 {
1308         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1309         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1310         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1311         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1312         struct test_tc_link *skel;
1313         int err, ifindex;
1314 
1315         ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
1316         ifindex = if_nametoindex("tcx_opts1");
1317         ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
1318 
1319         skel = test_tc_link__open_and_load();
1320         if (!ASSERT_OK_PTR(skel, "skel_load"))
1321                 goto cleanup;
1322 
1323         fd1 = bpf_program__fd(skel->progs.tc1);
1324         fd2 = bpf_program__fd(skel->progs.tc2);
1325         fd3 = bpf_program__fd(skel->progs.tc3);
1326         fd4 = bpf_program__fd(skel->progs.tc4);
1327 
1328         id1 = id_from_prog_fd(fd1);
1329         id2 = id_from_prog_fd(fd2);
1330         id3 = id_from_prog_fd(fd3);
1331         id4 = id_from_prog_fd(fd4);
1332 
1333         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1334         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1335         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1336 
1337         assert_mprog_count_ifindex(ifindex, target, 0);
1338 
1339         err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);
1340         if (!ASSERT_EQ(err, 0, "prog_attach"))
1341                 goto cleanup;
1342 
1343         assert_mprog_count_ifindex(ifindex, target, 1);
1344 
1345         err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);
1346         if (!ASSERT_EQ(err, 0, "prog_attach"))
1347                 goto cleanup1;
1348 
1349         assert_mprog_count_ifindex(ifindex, target, 2);
1350 
1351         err = bpf_prog_attach_opts(fd3, ifindex, target, &opta);
1352         if (!ASSERT_EQ(err, 0, "prog_attach"))
1353                 goto cleanup2;
1354 
1355         assert_mprog_count_ifindex(ifindex, target, 3);
1356 
1357         err = bpf_prog_attach_opts(fd4, ifindex, target, &opta);
1358         if (!ASSERT_EQ(err, 0, "prog_attach"))
1359                 goto cleanup3;
1360 
1361         assert_mprog_count_ifindex(ifindex, target, 4);
1362 
1363         ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1364         ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1365         ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1366         return;
1367 cleanup3:
1368         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1369         ASSERT_OK(err, "prog_detach");
1370 
1371         assert_mprog_count_ifindex(ifindex, target, 2);
1372 cleanup2:
1373         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1374         ASSERT_OK(err, "prog_detach");
1375 
1376         assert_mprog_count_ifindex(ifindex, target, 1);
1377 cleanup1:
1378         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1379         ASSERT_OK(err, "prog_detach");
1380 
1381         assert_mprog_count_ifindex(ifindex, target, 0);
1382 cleanup:
1383         test_tc_link__destroy(skel);
1384 
1385         ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
1386         ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
1387         ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
1388 }
1389 
1390 void serial_test_tc_opts_dev_cleanup(void)
1391 {
1392         test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS);
1393         test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS);
1394 }
1395 
1396 static void test_tc_opts_mixed_target(int target)
1397 {
1398         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1399         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1400         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1401         LIBBPF_OPTS(bpf_tcx_opts, optl);
1402         __u32 pid1, pid2, pid3, pid4, lid2, lid4;
1403         __u32 prog_flags[4], link_flags[4];
1404         __u32 prog_ids[4], link_ids[4];
1405         struct test_tc_link *skel;
1406         struct bpf_link *link;
1407         int err, detach_fd;
1408 
1409         skel = test_tc_link__open();
1410         if (!ASSERT_OK_PTR(skel, "skel_open"))
1411                 goto cleanup;
1412 
1413         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1414                   0, "tc1_attach_type");
1415         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1416                   0, "tc2_attach_type");
1417         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
1418                   0, "tc3_attach_type");
1419         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
1420                   0, "tc4_attach_type");
1421 
1422         err = test_tc_link__load(skel);
1423         if (!ASSERT_OK(err, "skel_load"))
1424                 goto cleanup;
1425 
1426         pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1427         pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1428         pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
1429         pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
1430 
1431         ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1432         ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
1433         ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
1434 
1435         assert_mprog_count(target, 0);
1436 
1437         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1438                                    loopback, target, &opta);
1439         if (!ASSERT_EQ(err, 0, "prog_attach"))
1440                 goto cleanup;
1441 
1442         detach_fd = bpf_program__fd(skel->progs.tc1);
1443 
1444         assert_mprog_count(target, 1);
1445 
1446         link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1447         if (!ASSERT_OK_PTR(link, "link_attach"))
1448                 goto cleanup1;
1449         skel->links.tc2 = link;
1450 
1451         lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
1452 
1453         assert_mprog_count(target, 2);
1454 
1455         LIBBPF_OPTS_RESET(opta,
1456                 .flags = BPF_F_REPLACE,
1457                 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1458         );
1459 
1460         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1461                                    loopback, target, &opta);
1462         ASSERT_EQ(err, -EEXIST, "prog_attach");
1463 
1464         assert_mprog_count(target, 2);
1465 
1466         LIBBPF_OPTS_RESET(opta,
1467                 .flags = BPF_F_REPLACE,
1468                 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1469         );
1470 
1471         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1472                                    loopback, target, &opta);
1473         ASSERT_EQ(err, -EEXIST, "prog_attach");
1474 
1475         assert_mprog_count(target, 2);
1476 
1477         LIBBPF_OPTS_RESET(opta,
1478                 .flags = BPF_F_REPLACE,
1479                 .replace_prog_fd = bpf_program__fd(skel->progs.tc2),
1480         );
1481 
1482         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1483                                    loopback, target, &opta);
1484         ASSERT_EQ(err, -EBUSY, "prog_attach");
1485 
1486         assert_mprog_count(target, 2);
1487 
1488         LIBBPF_OPTS_RESET(opta,
1489                 .flags = BPF_F_REPLACE,
1490                 .replace_prog_fd = bpf_program__fd(skel->progs.tc1),
1491         );
1492 
1493         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),
1494                                    loopback, target, &opta);
1495         if (!ASSERT_EQ(err, 0, "prog_attach"))
1496                 goto cleanup1;
1497 
1498         detach_fd = bpf_program__fd(skel->progs.tc3);
1499 
1500         assert_mprog_count(target, 2);
1501 
1502         link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);
1503         if (!ASSERT_OK_PTR(link, "link_attach"))
1504                 goto cleanup1;
1505         skel->links.tc4 = link;
1506 
1507         lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));
1508 
1509         assert_mprog_count(target, 3);
1510 
1511         LIBBPF_OPTS_RESET(opta,
1512                 .flags = BPF_F_REPLACE,
1513                 .replace_prog_fd = bpf_program__fd(skel->progs.tc4),
1514         );
1515 
1516         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),
1517                                    loopback, target, &opta);
1518         ASSERT_EQ(err, -EEXIST, "prog_attach");
1519 
1520         optq.prog_ids = prog_ids;
1521         optq.prog_attach_flags = prog_flags;
1522         optq.link_ids = link_ids;
1523         optq.link_attach_flags = link_flags;
1524 
1525         memset(prog_ids, 0, sizeof(prog_ids));
1526         memset(prog_flags, 0, sizeof(prog_flags));
1527         memset(link_ids, 0, sizeof(link_ids));
1528         memset(link_flags, 0, sizeof(link_flags));
1529         optq.count = ARRAY_SIZE(prog_ids);
1530 
1531         err = bpf_prog_query_opts(loopback, target, &optq);
1532         if (!ASSERT_OK(err, "prog_query"))
1533                 goto cleanup1;
1534 
1535         ASSERT_EQ(optq.count, 3, "count");
1536         ASSERT_EQ(optq.revision, 5, "revision");
1537         ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");
1538         ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");
1539         ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]");
1540         ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]");
1541         ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");
1542         ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
1543         ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");
1544         ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]");
1545         ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]");
1546         ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
1547         ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]");
1548         ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]");
1549         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1550         ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]");
1551         ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]");
1552         ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]");
1553 
1554         ASSERT_OK(system(ping_cmd), ping_cmd);
1555 
1556 cleanup1:
1557         err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
1558         ASSERT_OK(err, "prog_detach");
1559         assert_mprog_count(target, 2);
1560 
1561 cleanup:
1562         test_tc_link__destroy(skel);
1563         assert_mprog_count(target, 0);
1564 }
1565 
1566 void serial_test_tc_opts_mixed(void)
1567 {
1568         test_tc_opts_mixed_target(BPF_TCX_INGRESS);
1569         test_tc_opts_mixed_target(BPF_TCX_EGRESS);
1570 }
1571 
1572 static void test_tc_opts_demixed_target(int target)
1573 {
1574         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1575         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1576         LIBBPF_OPTS(bpf_tcx_opts, optl);
1577         struct test_tc_link *skel;
1578         struct bpf_link *link;
1579         __u32 pid1, pid2;
1580         int err;
1581 
1582         skel = test_tc_link__open();
1583         if (!ASSERT_OK_PTR(skel, "skel_open"))
1584                 goto cleanup;
1585 
1586         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
1587                   0, "tc1_attach_type");
1588         ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
1589                   0, "tc2_attach_type");
1590 
1591         err = test_tc_link__load(skel);
1592         if (!ASSERT_OK(err, "skel_load"))
1593                 goto cleanup;
1594 
1595         pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
1596         pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
1597         ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
1598 
1599         assert_mprog_count(target, 0);
1600 
1601         err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),
1602                                    loopback, target, &opta);
1603         if (!ASSERT_EQ(err, 0, "prog_attach"))
1604                 goto cleanup;
1605 
1606         assert_mprog_count(target, 1);
1607 
1608         link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
1609         if (!ASSERT_OK_PTR(link, "link_attach"))
1610                 goto cleanup1;
1611         skel->links.tc2 = link;
1612 
1613         assert_mprog_count(target, 2);
1614 
1615         LIBBPF_OPTS_RESET(optd,
1616                 .flags = BPF_F_AFTER,
1617         );
1618 
1619         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1620         ASSERT_EQ(err, -EBUSY, "prog_detach");
1621 
1622         assert_mprog_count(target, 2);
1623 
1624         LIBBPF_OPTS_RESET(optd,
1625                 .flags = BPF_F_BEFORE,
1626         );
1627 
1628         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1629         ASSERT_OK(err, "prog_detach");
1630 
1631         assert_mprog_count(target, 1);
1632         goto cleanup;
1633 
1634 cleanup1:
1635         err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1),
1636                                    loopback, target, &optd);
1637         ASSERT_OK(err, "prog_detach");
1638         assert_mprog_count(target, 2);
1639 
1640 cleanup:
1641         test_tc_link__destroy(skel);
1642         assert_mprog_count(target, 0);
1643 }
1644 
1645 void serial_test_tc_opts_demixed(void)
1646 {
1647         test_tc_opts_demixed_target(BPF_TCX_INGRESS);
1648         test_tc_opts_demixed_target(BPF_TCX_EGRESS);
1649 }
1650 
1651 static void test_tc_opts_detach_target(int target)
1652 {
1653         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1654         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1655         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1656         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1657         struct test_tc_link *skel;
1658         __u32 prog_ids[5];
1659         int err;
1660 
1661         skel = test_tc_link__open_and_load();
1662         if (!ASSERT_OK_PTR(skel, "skel_load"))
1663                 goto cleanup;
1664 
1665         fd1 = bpf_program__fd(skel->progs.tc1);
1666         fd2 = bpf_program__fd(skel->progs.tc2);
1667         fd3 = bpf_program__fd(skel->progs.tc3);
1668         fd4 = bpf_program__fd(skel->progs.tc4);
1669 
1670         id1 = id_from_prog_fd(fd1);
1671         id2 = id_from_prog_fd(fd2);
1672         id3 = id_from_prog_fd(fd3);
1673         id4 = id_from_prog_fd(fd4);
1674 
1675         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1676         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1677         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1678 
1679         assert_mprog_count(target, 0);
1680 
1681         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1682         if (!ASSERT_EQ(err, 0, "prog_attach"))
1683                 goto cleanup;
1684 
1685         assert_mprog_count(target, 1);
1686 
1687         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1688         if (!ASSERT_EQ(err, 0, "prog_attach"))
1689                 goto cleanup1;
1690 
1691         assert_mprog_count(target, 2);
1692 
1693         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1694         if (!ASSERT_EQ(err, 0, "prog_attach"))
1695                 goto cleanup2;
1696 
1697         assert_mprog_count(target, 3);
1698 
1699         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1700         if (!ASSERT_EQ(err, 0, "prog_attach"))
1701                 goto cleanup3;
1702 
1703         assert_mprog_count(target, 4);
1704 
1705         optq.prog_ids = prog_ids;
1706 
1707         memset(prog_ids, 0, sizeof(prog_ids));
1708         optq.count = ARRAY_SIZE(prog_ids);
1709 
1710         err = bpf_prog_query_opts(loopback, target, &optq);
1711         if (!ASSERT_OK(err, "prog_query"))
1712                 goto cleanup4;
1713 
1714         ASSERT_EQ(optq.count, 4, "count");
1715         ASSERT_EQ(optq.revision, 5, "revision");
1716         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1717         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1718         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1719         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1720         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1721 
1722         LIBBPF_OPTS_RESET(optd,
1723                 .flags = BPF_F_BEFORE,
1724         );
1725 
1726         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1727         ASSERT_OK(err, "prog_detach");
1728 
1729         assert_mprog_count(target, 3);
1730 
1731         memset(prog_ids, 0, sizeof(prog_ids));
1732         optq.count = ARRAY_SIZE(prog_ids);
1733 
1734         err = bpf_prog_query_opts(loopback, target, &optq);
1735         if (!ASSERT_OK(err, "prog_query"))
1736                 goto cleanup4;
1737 
1738         ASSERT_EQ(optq.count, 3, "count");
1739         ASSERT_EQ(optq.revision, 6, "revision");
1740         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1741         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1742         ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1743         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1744 
1745         LIBBPF_OPTS_RESET(optd,
1746                 .flags = BPF_F_AFTER,
1747         );
1748 
1749         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1750         ASSERT_OK(err, "prog_detach");
1751 
1752         assert_mprog_count(target, 2);
1753 
1754         memset(prog_ids, 0, sizeof(prog_ids));
1755         optq.count = ARRAY_SIZE(prog_ids);
1756 
1757         err = bpf_prog_query_opts(loopback, target, &optq);
1758         if (!ASSERT_OK(err, "prog_query"))
1759                 goto cleanup4;
1760 
1761         ASSERT_EQ(optq.count, 2, "count");
1762         ASSERT_EQ(optq.revision, 7, "revision");
1763         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1764         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1765         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1766 
1767         LIBBPF_OPTS_RESET(optd);
1768 
1769         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1770         ASSERT_OK(err, "prog_detach");
1771         assert_mprog_count(target, 1);
1772 
1773         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1774         ASSERT_OK(err, "prog_detach");
1775         assert_mprog_count(target, 0);
1776 
1777         LIBBPF_OPTS_RESET(optd,
1778                 .flags = BPF_F_BEFORE,
1779         );
1780 
1781         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1782         ASSERT_EQ(err, -ENOENT, "prog_detach");
1783 
1784         LIBBPF_OPTS_RESET(optd,
1785                 .flags = BPF_F_AFTER,
1786         );
1787 
1788         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1789         ASSERT_EQ(err, -ENOENT, "prog_detach");
1790         goto cleanup;
1791 
1792 cleanup4:
1793         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
1794         ASSERT_OK(err, "prog_detach");
1795         assert_mprog_count(target, 3);
1796 
1797 cleanup3:
1798         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
1799         ASSERT_OK(err, "prog_detach");
1800         assert_mprog_count(target, 2);
1801 
1802 cleanup2:
1803         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1804         ASSERT_OK(err, "prog_detach");
1805         assert_mprog_count(target, 1);
1806 
1807 cleanup1:
1808         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1809         ASSERT_OK(err, "prog_detach");
1810         assert_mprog_count(target, 0);
1811 
1812 cleanup:
1813         test_tc_link__destroy(skel);
1814 }
1815 
1816 void serial_test_tc_opts_detach(void)
1817 {
1818         test_tc_opts_detach_target(BPF_TCX_INGRESS);
1819         test_tc_opts_detach_target(BPF_TCX_EGRESS);
1820 }
1821 
1822 static void test_tc_opts_detach_before_target(int target)
1823 {
1824         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
1825         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
1826         LIBBPF_OPTS(bpf_prog_query_opts, optq);
1827         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
1828         struct test_tc_link *skel;
1829         __u32 prog_ids[5];
1830         int err;
1831 
1832         skel = test_tc_link__open_and_load();
1833         if (!ASSERT_OK_PTR(skel, "skel_load"))
1834                 goto cleanup;
1835 
1836         fd1 = bpf_program__fd(skel->progs.tc1);
1837         fd2 = bpf_program__fd(skel->progs.tc2);
1838         fd3 = bpf_program__fd(skel->progs.tc3);
1839         fd4 = bpf_program__fd(skel->progs.tc4);
1840 
1841         id1 = id_from_prog_fd(fd1);
1842         id2 = id_from_prog_fd(fd2);
1843         id3 = id_from_prog_fd(fd3);
1844         id4 = id_from_prog_fd(fd4);
1845 
1846         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
1847         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
1848         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
1849 
1850         assert_mprog_count(target, 0);
1851 
1852         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
1853         if (!ASSERT_EQ(err, 0, "prog_attach"))
1854                 goto cleanup;
1855 
1856         assert_mprog_count(target, 1);
1857 
1858         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
1859         if (!ASSERT_EQ(err, 0, "prog_attach"))
1860                 goto cleanup1;
1861 
1862         assert_mprog_count(target, 2);
1863 
1864         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
1865         if (!ASSERT_EQ(err, 0, "prog_attach"))
1866                 goto cleanup2;
1867 
1868         assert_mprog_count(target, 3);
1869 
1870         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
1871         if (!ASSERT_EQ(err, 0, "prog_attach"))
1872                 goto cleanup3;
1873 
1874         assert_mprog_count(target, 4);
1875 
1876         optq.prog_ids = prog_ids;
1877 
1878         memset(prog_ids, 0, sizeof(prog_ids));
1879         optq.count = ARRAY_SIZE(prog_ids);
1880 
1881         err = bpf_prog_query_opts(loopback, target, &optq);
1882         if (!ASSERT_OK(err, "prog_query"))
1883                 goto cleanup4;
1884 
1885         ASSERT_EQ(optq.count, 4, "count");
1886         ASSERT_EQ(optq.revision, 5, "revision");
1887         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
1888         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
1889         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
1890         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
1891         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
1892 
1893         LIBBPF_OPTS_RESET(optd,
1894                 .flags = BPF_F_BEFORE,
1895                 .relative_fd = fd2,
1896         );
1897 
1898         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1899         ASSERT_OK(err, "prog_detach");
1900 
1901         assert_mprog_count(target, 3);
1902 
1903         memset(prog_ids, 0, sizeof(prog_ids));
1904         optq.count = ARRAY_SIZE(prog_ids);
1905 
1906         err = bpf_prog_query_opts(loopback, target, &optq);
1907         if (!ASSERT_OK(err, "prog_query"))
1908                 goto cleanup4;
1909 
1910         ASSERT_EQ(optq.count, 3, "count");
1911         ASSERT_EQ(optq.revision, 6, "revision");
1912         ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
1913         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
1914         ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
1915         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
1916 
1917         LIBBPF_OPTS_RESET(optd,
1918                 .flags = BPF_F_BEFORE,
1919                 .relative_fd = fd2,
1920         );
1921 
1922         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
1923         ASSERT_EQ(err, -ENOENT, "prog_detach");
1924         assert_mprog_count(target, 3);
1925 
1926         LIBBPF_OPTS_RESET(optd,
1927                 .flags = BPF_F_BEFORE,
1928                 .relative_fd = fd4,
1929         );
1930 
1931         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1932         ASSERT_EQ(err, -ERANGE, "prog_detach");
1933         assert_mprog_count(target, 3);
1934 
1935         LIBBPF_OPTS_RESET(optd,
1936                 .flags = BPF_F_BEFORE,
1937                 .relative_fd = fd1,
1938         );
1939 
1940         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1941         ASSERT_EQ(err, -ENOENT, "prog_detach");
1942         assert_mprog_count(target, 3);
1943 
1944         LIBBPF_OPTS_RESET(optd,
1945                 .flags = BPF_F_BEFORE,
1946                 .relative_fd = fd3,
1947         );
1948 
1949         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
1950         ASSERT_OK(err, "prog_detach");
1951 
1952         assert_mprog_count(target, 2);
1953 
1954         memset(prog_ids, 0, sizeof(prog_ids));
1955         optq.count = ARRAY_SIZE(prog_ids);
1956 
1957         err = bpf_prog_query_opts(loopback, target, &optq);
1958         if (!ASSERT_OK(err, "prog_query"))
1959                 goto cleanup4;
1960 
1961         ASSERT_EQ(optq.count, 2, "count");
1962         ASSERT_EQ(optq.revision, 7, "revision");
1963         ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");
1964         ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
1965         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
1966 
1967         LIBBPF_OPTS_RESET(optd,
1968                 .flags = BPF_F_BEFORE,
1969                 .relative_fd = fd4,
1970         );
1971 
1972         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1973         ASSERT_OK(err, "prog_detach");
1974 
1975         assert_mprog_count(target, 1);
1976 
1977         memset(prog_ids, 0, sizeof(prog_ids));
1978         optq.count = ARRAY_SIZE(prog_ids);
1979 
1980         err = bpf_prog_query_opts(loopback, target, &optq);
1981         if (!ASSERT_OK(err, "prog_query"))
1982                 goto cleanup4;
1983 
1984         ASSERT_EQ(optq.count, 1, "count");
1985         ASSERT_EQ(optq.revision, 8, "revision");
1986         ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");
1987         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
1988 
1989         LIBBPF_OPTS_RESET(optd,
1990                 .flags = BPF_F_BEFORE,
1991         );
1992 
1993         err = bpf_prog_detach_opts(0, loopback, target, &optd);
1994         ASSERT_OK(err, "prog_detach");
1995 
1996         assert_mprog_count(target, 0);
1997         goto cleanup;
1998 
1999 cleanup4:
2000         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2001         ASSERT_OK(err, "prog_detach");
2002         assert_mprog_count(target, 3);
2003 
2004 cleanup3:
2005         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2006         ASSERT_OK(err, "prog_detach");
2007         assert_mprog_count(target, 2);
2008 
2009 cleanup2:
2010         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2011         ASSERT_OK(err, "prog_detach");
2012         assert_mprog_count(target, 1);
2013 
2014 cleanup1:
2015         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2016         ASSERT_OK(err, "prog_detach");
2017         assert_mprog_count(target, 0);
2018 
2019 cleanup:
2020         test_tc_link__destroy(skel);
2021 }
2022 
2023 void serial_test_tc_opts_detach_before(void)
2024 {
2025         test_tc_opts_detach_before_target(BPF_TCX_INGRESS);
2026         test_tc_opts_detach_before_target(BPF_TCX_EGRESS);
2027 }
2028 
2029 static void test_tc_opts_detach_after_target(int target)
2030 {
2031         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2032         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2033         LIBBPF_OPTS(bpf_prog_query_opts, optq);
2034         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
2035         struct test_tc_link *skel;
2036         __u32 prog_ids[5];
2037         int err;
2038 
2039         skel = test_tc_link__open_and_load();
2040         if (!ASSERT_OK_PTR(skel, "skel_load"))
2041                 goto cleanup;
2042 
2043         fd1 = bpf_program__fd(skel->progs.tc1);
2044         fd2 = bpf_program__fd(skel->progs.tc2);
2045         fd3 = bpf_program__fd(skel->progs.tc3);
2046         fd4 = bpf_program__fd(skel->progs.tc4);
2047 
2048         id1 = id_from_prog_fd(fd1);
2049         id2 = id_from_prog_fd(fd2);
2050         id3 = id_from_prog_fd(fd3);
2051         id4 = id_from_prog_fd(fd4);
2052 
2053         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2054         ASSERT_NEQ(id3, id4, "prog_ids_3_4");
2055         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2056 
2057         assert_mprog_count(target, 0);
2058 
2059         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2060         if (!ASSERT_EQ(err, 0, "prog_attach"))
2061                 goto cleanup;
2062 
2063         assert_mprog_count(target, 1);
2064 
2065         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
2066         if (!ASSERT_EQ(err, 0, "prog_attach"))
2067                 goto cleanup1;
2068 
2069         assert_mprog_count(target, 2);
2070 
2071         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2072         if (!ASSERT_EQ(err, 0, "prog_attach"))
2073                 goto cleanup2;
2074 
2075         assert_mprog_count(target, 3);
2076 
2077         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
2078         if (!ASSERT_EQ(err, 0, "prog_attach"))
2079                 goto cleanup3;
2080 
2081         assert_mprog_count(target, 4);
2082 
2083         optq.prog_ids = prog_ids;
2084 
2085         memset(prog_ids, 0, sizeof(prog_ids));
2086         optq.count = ARRAY_SIZE(prog_ids);
2087 
2088         err = bpf_prog_query_opts(loopback, target, &optq);
2089         if (!ASSERT_OK(err, "prog_query"))
2090                 goto cleanup4;
2091 
2092         ASSERT_EQ(optq.count, 4, "count");
2093         ASSERT_EQ(optq.revision, 5, "revision");
2094         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2095         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
2096         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
2097         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
2098         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
2099 
2100         LIBBPF_OPTS_RESET(optd,
2101                 .flags = BPF_F_AFTER,
2102                 .relative_fd = fd1,
2103         );
2104 
2105         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2106         ASSERT_OK(err, "prog_detach");
2107 
2108         assert_mprog_count(target, 3);
2109 
2110         memset(prog_ids, 0, sizeof(prog_ids));
2111         optq.count = ARRAY_SIZE(prog_ids);
2112 
2113         err = bpf_prog_query_opts(loopback, target, &optq);
2114         if (!ASSERT_OK(err, "prog_query"))
2115                 goto cleanup4;
2116 
2117         ASSERT_EQ(optq.count, 3, "count");
2118         ASSERT_EQ(optq.revision, 6, "revision");
2119         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2120         ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
2121         ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");
2122         ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");
2123 
2124         LIBBPF_OPTS_RESET(optd,
2125                 .flags = BPF_F_AFTER,
2126                 .relative_fd = fd1,
2127         );
2128 
2129         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2130         ASSERT_EQ(err, -ENOENT, "prog_detach");
2131         assert_mprog_count(target, 3);
2132 
2133         LIBBPF_OPTS_RESET(optd,
2134                 .flags = BPF_F_AFTER,
2135                 .relative_fd = fd4,
2136         );
2137 
2138         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2139         ASSERT_EQ(err, -ERANGE, "prog_detach");
2140         assert_mprog_count(target, 3);
2141 
2142         LIBBPF_OPTS_RESET(optd,
2143                 .flags = BPF_F_AFTER,
2144                 .relative_fd = fd3,
2145         );
2146 
2147         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2148         ASSERT_EQ(err, -ERANGE, "prog_detach");
2149         assert_mprog_count(target, 3);
2150 
2151         LIBBPF_OPTS_RESET(optd,
2152                 .flags = BPF_F_AFTER,
2153                 .relative_fd = fd1,
2154         );
2155 
2156         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2157         ASSERT_EQ(err, -ERANGE, "prog_detach");
2158         assert_mprog_count(target, 3);
2159 
2160         LIBBPF_OPTS_RESET(optd,
2161                 .flags = BPF_F_AFTER,
2162                 .relative_fd = fd1,
2163         );
2164 
2165         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2166         ASSERT_OK(err, "prog_detach");
2167 
2168         assert_mprog_count(target, 2);
2169 
2170         memset(prog_ids, 0, sizeof(prog_ids));
2171         optq.count = ARRAY_SIZE(prog_ids);
2172 
2173         err = bpf_prog_query_opts(loopback, target, &optq);
2174         if (!ASSERT_OK(err, "prog_query"))
2175                 goto cleanup4;
2176 
2177         ASSERT_EQ(optq.count, 2, "count");
2178         ASSERT_EQ(optq.revision, 7, "revision");
2179         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2180         ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");
2181         ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
2182 
2183         LIBBPF_OPTS_RESET(optd,
2184                 .flags = BPF_F_AFTER,
2185                 .relative_fd = fd1,
2186         );
2187 
2188         err = bpf_prog_detach_opts(0, loopback, target, &optd);
2189         ASSERT_OK(err, "prog_detach");
2190 
2191         assert_mprog_count(target, 1);
2192 
2193         memset(prog_ids, 0, sizeof(prog_ids));
2194         optq.count = ARRAY_SIZE(prog_ids);
2195 
2196         err = bpf_prog_query_opts(loopback, target, &optq);
2197         if (!ASSERT_OK(err, "prog_query"))
2198                 goto cleanup4;
2199 
2200         ASSERT_EQ(optq.count, 1, "count");
2201         ASSERT_EQ(optq.revision, 8, "revision");
2202         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2203         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
2204 
2205         LIBBPF_OPTS_RESET(optd,
2206                 .flags = BPF_F_AFTER,
2207         );
2208 
2209         err = bpf_prog_detach_opts(0, loopback, target, &optd);
2210         ASSERT_OK(err, "prog_detach");
2211 
2212         assert_mprog_count(target, 0);
2213         goto cleanup;
2214 
2215 cleanup4:
2216         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2217         ASSERT_OK(err, "prog_detach");
2218         assert_mprog_count(target, 3);
2219 
2220 cleanup3:
2221         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2222         ASSERT_OK(err, "prog_detach");
2223         assert_mprog_count(target, 2);
2224 
2225 cleanup2:
2226         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2227         ASSERT_OK(err, "prog_detach");
2228         assert_mprog_count(target, 1);
2229 
2230 cleanup1:
2231         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2232         ASSERT_OK(err, "prog_detach");
2233         assert_mprog_count(target, 0);
2234 
2235 cleanup:
2236         test_tc_link__destroy(skel);
2237 }
2238 
2239 void serial_test_tc_opts_detach_after(void)
2240 {
2241         test_tc_opts_detach_after_target(BPF_TCX_INGRESS);
2242         test_tc_opts_detach_after_target(BPF_TCX_EGRESS);
2243 }
2244 
2245 static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
2246 {
2247         LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2248         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2249         int err;
2250 
2251         assert_mprog_count(target, 0);
2252         if (chain_tc_old) {
2253                 tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2254                                        BPF_TC_INGRESS : BPF_TC_EGRESS;
2255                 err = bpf_tc_hook_create(&tc_hook);
2256                 ASSERT_OK(err, "bpf_tc_hook_create");
2257                 assert_mprog_count(target, 0);
2258         }
2259         err = bpf_prog_detach_opts(0, loopback, target, &optd);
2260         ASSERT_EQ(err, -ENOENT, "prog_detach");
2261         if (chain_tc_old) {
2262                 tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2263                 bpf_tc_hook_destroy(&tc_hook);
2264         }
2265         assert_mprog_count(target, 0);
2266 }
2267 
2268 void serial_test_tc_opts_delete_empty(void)
2269 {
2270         test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);
2271         test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);
2272         test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);
2273         test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);
2274 }
2275 
2276 static void test_tc_chain_mixed(int target)
2277 {
2278         LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
2279         LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
2280         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2281         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2282         __u32 fd1, fd2, fd3, id1, id2, id3;
2283         struct test_tc_link *skel;
2284         int err, detach_fd;
2285 
2286         skel = test_tc_link__open_and_load();
2287         if (!ASSERT_OK_PTR(skel, "skel_load"))
2288                 goto cleanup;
2289 
2290         fd1 = bpf_program__fd(skel->progs.tc4);
2291         fd2 = bpf_program__fd(skel->progs.tc5);
2292         fd3 = bpf_program__fd(skel->progs.tc6);
2293 
2294         id1 = id_from_prog_fd(fd1);
2295         id2 = id_from_prog_fd(fd2);
2296         id3 = id_from_prog_fd(fd3);
2297 
2298         ASSERT_NEQ(id1, id2, "prog_ids_1_2");
2299         ASSERT_NEQ(id2, id3, "prog_ids_2_3");
2300 
2301         assert_mprog_count(target, 0);
2302 
2303         tc_hook.attach_point = target == BPF_TCX_INGRESS ?
2304                                BPF_TC_INGRESS : BPF_TC_EGRESS;
2305         err = bpf_tc_hook_create(&tc_hook);
2306         err = err == -EEXIST ? 0 : err;
2307         if (!ASSERT_OK(err, "bpf_tc_hook_create"))
2308                 goto cleanup;
2309 
2310         tc_opts.prog_fd = fd2;
2311         err = bpf_tc_attach(&tc_hook, &tc_opts);
2312         if (!ASSERT_OK(err, "bpf_tc_attach"))
2313                 goto cleanup_hook;
2314 
2315         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2316         if (!ASSERT_EQ(err, 0, "prog_attach"))
2317                 goto cleanup_filter;
2318 
2319         detach_fd = fd3;
2320 
2321         assert_mprog_count(target, 1);
2322 
2323         tc_skel_reset_all_seen(skel);
2324         ASSERT_OK(system(ping_cmd), ping_cmd);
2325 
2326         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2327         ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
2328         ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
2329 
2330         LIBBPF_OPTS_RESET(opta,
2331                 .flags = BPF_F_REPLACE,
2332                 .replace_prog_fd = fd3,
2333         );
2334 
2335         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2336         if (!ASSERT_EQ(err, 0, "prog_attach"))
2337                 goto cleanup_opts;
2338 
2339         detach_fd = fd1;
2340 
2341         assert_mprog_count(target, 1);
2342 
2343         tc_skel_reset_all_seen(skel);
2344         ASSERT_OK(system(ping_cmd), ping_cmd);
2345 
2346         ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
2347         ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2348         ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2349 
2350 cleanup_opts:
2351         err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
2352         ASSERT_OK(err, "prog_detach");
2353         assert_mprog_count(target, 0);
2354 
2355         tc_skel_reset_all_seen(skel);
2356         ASSERT_OK(system(ping_cmd), ping_cmd);
2357 
2358         ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
2359         ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
2360         ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
2361 
2362 cleanup_filter:
2363         tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
2364         err = bpf_tc_detach(&tc_hook, &tc_opts);
2365         ASSERT_OK(err, "bpf_tc_detach");
2366 
2367 cleanup_hook:
2368         tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
2369         bpf_tc_hook_destroy(&tc_hook);
2370 
2371 cleanup:
2372         test_tc_link__destroy(skel);
2373 }
2374 
2375 void serial_test_tc_opts_chain_mixed(void)
2376 {
2377         test_tc_chain_mixed(BPF_TCX_INGRESS);
2378         test_tc_chain_mixed(BPF_TCX_EGRESS);
2379 }
2380 
2381 static int generate_dummy_prog(void)
2382 {
2383         const struct bpf_insn prog_insns[] = {
2384                 BPF_MOV64_IMM(BPF_REG_0, 0),
2385                 BPF_EXIT_INSN(),
2386         };
2387         const size_t prog_insn_cnt = sizeof(prog_insns) / sizeof(struct bpf_insn);
2388         LIBBPF_OPTS(bpf_prog_load_opts, opts);
2389         const size_t log_buf_sz = 256;
2390         char log_buf[log_buf_sz];
2391         int fd = -1;
2392 
2393         opts.log_buf = log_buf;
2394         opts.log_size = log_buf_sz;
2395 
2396         log_buf[0] = '\0';
2397         opts.log_level = 0;
2398         fd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, "tcx_prog", "GPL",
2399                            prog_insns, prog_insn_cnt, &opts);
2400         ASSERT_STREQ(log_buf, "", "log_0");
2401         ASSERT_GE(fd, 0, "prog_fd");
2402         return fd;
2403 }
2404 
2405 static void test_tc_opts_max_target(int target, int flags, bool relative)
2406 {
2407         int err, ifindex, i, prog_fd, last_fd = -1;
2408         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2409         const int max_progs = 63;
2410 
2411         ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
2412         ifindex = if_nametoindex("tcx_opts1");
2413         ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
2414 
2415         assert_mprog_count_ifindex(ifindex, target, 0);
2416 
2417         for (i = 0; i < max_progs; i++) {
2418                 prog_fd = generate_dummy_prog();
2419                 if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
2420                         goto cleanup;
2421                 err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
2422                 if (!ASSERT_EQ(err, 0, "prog_attach"))
2423                         goto cleanup;
2424                 assert_mprog_count_ifindex(ifindex, target, i + 1);
2425                 if (i == max_progs - 1 && relative)
2426                         last_fd = prog_fd;
2427                 else
2428                         close(prog_fd);
2429         }
2430 
2431         prog_fd = generate_dummy_prog();
2432         if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))
2433                 goto cleanup;
2434         opta.flags = flags;
2435         if (last_fd > 0)
2436                 opta.relative_fd = last_fd;
2437         err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);
2438         ASSERT_EQ(err, -ERANGE, "prog_64_attach");
2439         assert_mprog_count_ifindex(ifindex, target, max_progs);
2440         close(prog_fd);
2441 cleanup:
2442         if (last_fd > 0)
2443                 close(last_fd);
2444         ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
2445         ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
2446         ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
2447 }
2448 
2449 void serial_test_tc_opts_max(void)
2450 {
2451         test_tc_opts_max_target(BPF_TCX_INGRESS, 0, false);
2452         test_tc_opts_max_target(BPF_TCX_EGRESS, 0, false);
2453 
2454         test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_BEFORE, false);
2455         test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_BEFORE, true);
2456 
2457         test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);
2458         test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);
2459 }
2460 
2461 static void test_tc_opts_query_target(int target)
2462 {
2463         const size_t attr_size = offsetofend(union bpf_attr, query);
2464         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2465         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2466         LIBBPF_OPTS(bpf_prog_query_opts, optq);
2467         __u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
2468         struct test_tc_link *skel;
2469         union bpf_attr attr;
2470         __u32 prog_ids[10];
2471         int err;
2472 
2473         skel = test_tc_link__open_and_load();
2474         if (!ASSERT_OK_PTR(skel, "skel_load"))
2475                 goto cleanup;
2476 
2477         fd1 = bpf_program__fd(skel->progs.tc1);
2478         fd2 = bpf_program__fd(skel->progs.tc2);
2479         fd3 = bpf_program__fd(skel->progs.tc3);
2480         fd4 = bpf_program__fd(skel->progs.tc4);
2481 
2482         id1 = id_from_prog_fd(fd1);
2483         id2 = id_from_prog_fd(fd2);
2484         id3 = id_from_prog_fd(fd3);
2485         id4 = id_from_prog_fd(fd4);
2486 
2487         assert_mprog_count(target, 0);
2488 
2489         LIBBPF_OPTS_RESET(opta,
2490                 .expected_revision = 1,
2491         );
2492 
2493         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2494         if (!ASSERT_EQ(err, 0, "prog_attach"))
2495                 goto cleanup;
2496 
2497         assert_mprog_count(target, 1);
2498 
2499         LIBBPF_OPTS_RESET(opta,
2500                 .expected_revision = 2,
2501         );
2502 
2503         err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
2504         if (!ASSERT_EQ(err, 0, "prog_attach"))
2505                 goto cleanup1;
2506 
2507         assert_mprog_count(target, 2);
2508 
2509         LIBBPF_OPTS_RESET(opta,
2510                 .expected_revision = 3,
2511         );
2512 
2513         err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
2514         if (!ASSERT_EQ(err, 0, "prog_attach"))
2515                 goto cleanup2;
2516 
2517         assert_mprog_count(target, 3);
2518 
2519         LIBBPF_OPTS_RESET(opta,
2520                 .expected_revision = 4,
2521         );
2522 
2523         err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
2524         if (!ASSERT_EQ(err, 0, "prog_attach"))
2525                 goto cleanup3;
2526 
2527         assert_mprog_count(target, 4);
2528 
2529         /* Test 1: Double query via libbpf API */
2530         err = bpf_prog_query_opts(loopback, target, &optq);
2531         if (!ASSERT_OK(err, "prog_query"))
2532                 goto cleanup4;
2533 
2534         ASSERT_EQ(optq.count, 4, "count");
2535         ASSERT_EQ(optq.revision, 5, "revision");
2536         ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");
2537         ASSERT_EQ(optq.link_ids, NULL, "link_ids");
2538 
2539         memset(prog_ids, 0, sizeof(prog_ids));
2540         optq.prog_ids = prog_ids;
2541 
2542         err = bpf_prog_query_opts(loopback, target, &optq);
2543         if (!ASSERT_OK(err, "prog_query"))
2544                 goto cleanup4;
2545 
2546         ASSERT_EQ(optq.count, 4, "count");
2547         ASSERT_EQ(optq.revision, 5, "revision");
2548         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2549         ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
2550         ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
2551         ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
2552         ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
2553         ASSERT_EQ(optq.link_ids, NULL, "link_ids");
2554 
2555         /* Test 2: Double query via bpf_attr & bpf(2) directly */
2556         memset(&attr, 0, attr_size);
2557         attr.query.target_ifindex = loopback;
2558         attr.query.attach_type = target;
2559 
2560         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2561         if (!ASSERT_OK(err, "prog_query"))
2562                 goto cleanup4;
2563 
2564         ASSERT_EQ(attr.query.count, 4, "count");
2565         ASSERT_EQ(attr.query.revision, 5, "revision");
2566         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2567         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2568         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2569         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2570         ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");
2571         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2572         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2573         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2574 
2575         memset(prog_ids, 0, sizeof(prog_ids));
2576         attr.query.prog_ids = ptr_to_u64(prog_ids);
2577 
2578         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2579         if (!ASSERT_OK(err, "prog_query"))
2580                 goto cleanup4;
2581 
2582         ASSERT_EQ(attr.query.count, 4, "count");
2583         ASSERT_EQ(attr.query.revision, 5, "revision");
2584         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2585         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2586         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2587         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2588         ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
2589         ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
2590         ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
2591         ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");
2592         ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");
2593         ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2594         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2595         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2596         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2597 
2598         /* Test 3: Query with smaller prog_ids array */
2599         memset(&attr, 0, attr_size);
2600         attr.query.target_ifindex = loopback;
2601         attr.query.attach_type = target;
2602 
2603         memset(prog_ids, 0, sizeof(prog_ids));
2604         attr.query.prog_ids = ptr_to_u64(prog_ids);
2605         attr.query.count = 2;
2606 
2607         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2608         ASSERT_EQ(err, -1, "prog_query_should_fail");
2609         ASSERT_EQ(errno, ENOSPC, "prog_query_should_fail");
2610 
2611         ASSERT_EQ(attr.query.count, 4, "count");
2612         ASSERT_EQ(attr.query.revision, 5, "revision");
2613         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2614         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2615         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2616         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2617         ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
2618         ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
2619         ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
2620         ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");
2621         ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");
2622         ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2623         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2624         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2625         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2626 
2627         /* Test 4: Query with larger prog_ids array */
2628         memset(&attr, 0, attr_size);
2629         attr.query.target_ifindex = loopback;
2630         attr.query.attach_type = target;
2631 
2632         memset(prog_ids, 0, sizeof(prog_ids));
2633         attr.query.prog_ids = ptr_to_u64(prog_ids);
2634         attr.query.count = 10;
2635 
2636         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2637         if (!ASSERT_OK(err, "prog_query"))
2638                 goto cleanup4;
2639 
2640         ASSERT_EQ(attr.query.count, 4, "count");
2641         ASSERT_EQ(attr.query.revision, 5, "revision");
2642         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2643         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2644         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2645         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2646         ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
2647         ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
2648         ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
2649         ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");
2650         ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");
2651         ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2652         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2653         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2654         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2655 
2656         /* Test 5: Query with NULL prog_ids array but with count > 0 */
2657         memset(&attr, 0, attr_size);
2658         attr.query.target_ifindex = loopback;
2659         attr.query.attach_type = target;
2660 
2661         memset(prog_ids, 0, sizeof(prog_ids));
2662         attr.query.count = sizeof(prog_ids);
2663 
2664         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2665         if (!ASSERT_OK(err, "prog_query"))
2666                 goto cleanup4;
2667 
2668         ASSERT_EQ(attr.query.count, 4, "count");
2669         ASSERT_EQ(attr.query.revision, 5, "revision");
2670         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2671         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2672         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2673         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2674         ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");
2675         ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");
2676         ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");
2677         ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");
2678         ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2679         ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");
2680         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2681         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2682         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2683 
2684         /* Test 6: Query with non-NULL prog_ids array but with count == 0 */
2685         memset(&attr, 0, attr_size);
2686         attr.query.target_ifindex = loopback;
2687         attr.query.attach_type = target;
2688 
2689         memset(prog_ids, 0, sizeof(prog_ids));
2690         attr.query.prog_ids = ptr_to_u64(prog_ids);
2691 
2692         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2693         if (!ASSERT_OK(err, "prog_query"))
2694                 goto cleanup4;
2695 
2696         ASSERT_EQ(attr.query.count, 4, "count");
2697         ASSERT_EQ(attr.query.revision, 5, "revision");
2698         ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
2699         ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
2700         ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
2701         ASSERT_EQ(attr.query.attach_type, target, "attach_type");
2702         ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");
2703         ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");
2704         ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");
2705         ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");
2706         ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
2707         ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
2708         ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
2709         ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
2710         ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
2711 
2712         /* Test 7: Query with invalid flags */
2713         attr.query.attach_flags = 0;
2714         attr.query.query_flags = 1;
2715 
2716         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2717         ASSERT_EQ(err, -1, "prog_query_should_fail");
2718         ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");
2719 
2720         attr.query.attach_flags = 1;
2721         attr.query.query_flags = 0;
2722 
2723         err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
2724         ASSERT_EQ(err, -1, "prog_query_should_fail");
2725         ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");
2726 
2727 cleanup4:
2728         err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
2729         ASSERT_OK(err, "prog_detach");
2730         assert_mprog_count(target, 3);
2731 
2732 cleanup3:
2733         err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
2734         ASSERT_OK(err, "prog_detach");
2735         assert_mprog_count(target, 2);
2736 
2737 cleanup2:
2738         err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
2739         ASSERT_OK(err, "prog_detach");
2740         assert_mprog_count(target, 1);
2741 
2742 cleanup1:
2743         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2744         ASSERT_OK(err, "prog_detach");
2745         assert_mprog_count(target, 0);
2746 
2747 cleanup:
2748         test_tc_link__destroy(skel);
2749 }
2750 
2751 void serial_test_tc_opts_query(void)
2752 {
2753         test_tc_opts_query_target(BPF_TCX_INGRESS);
2754         test_tc_opts_query_target(BPF_TCX_EGRESS);
2755 }
2756 
2757 static void test_tc_opts_query_attach_target(int target)
2758 {
2759         LIBBPF_OPTS(bpf_prog_attach_opts, opta);
2760         LIBBPF_OPTS(bpf_prog_detach_opts, optd);
2761         LIBBPF_OPTS(bpf_prog_query_opts, optq);
2762         struct test_tc_link *skel;
2763         __u32 prog_ids[2];
2764         __u32 fd1, id1;
2765         int err;
2766 
2767         skel = test_tc_link__open_and_load();
2768         if (!ASSERT_OK_PTR(skel, "skel_load"))
2769                 goto cleanup;
2770 
2771         fd1 = bpf_program__fd(skel->progs.tc1);
2772         id1 = id_from_prog_fd(fd1);
2773 
2774         err = bpf_prog_query_opts(loopback, target, &optq);
2775         if (!ASSERT_OK(err, "prog_query"))
2776                 goto cleanup;
2777 
2778         ASSERT_EQ(optq.count, 0, "count");
2779         ASSERT_EQ(optq.revision, 1, "revision");
2780 
2781         LIBBPF_OPTS_RESET(opta,
2782                 .expected_revision = optq.revision,
2783         );
2784 
2785         err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
2786         if (!ASSERT_EQ(err, 0, "prog_attach"))
2787                 goto cleanup;
2788 
2789         memset(prog_ids, 0, sizeof(prog_ids));
2790         optq.prog_ids = prog_ids;
2791         optq.count = ARRAY_SIZE(prog_ids);
2792 
2793         err = bpf_prog_query_opts(loopback, target, &optq);
2794         if (!ASSERT_OK(err, "prog_query"))
2795                 goto cleanup1;
2796 
2797         ASSERT_EQ(optq.count, 1, "count");
2798         ASSERT_EQ(optq.revision, 2, "revision");
2799         ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
2800         ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
2801 
2802 cleanup1:
2803         err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
2804         ASSERT_OK(err, "prog_detach");
2805         assert_mprog_count(target, 0);
2806 cleanup:
2807         test_tc_link__destroy(skel);
2808 }
2809 
2810 void serial_test_tc_opts_query_attach(void)
2811 {
2812         test_tc_opts_query_attach_target(BPF_TCX_INGRESS);
2813         test_tc_opts_query_attach_target(BPF_TCX_EGRESS);
2814 }
2815 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php