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