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