xref: /linux/tools/testing/selftests/bpf/prog_tests/tc_netkit.c (revision f2ad904e923f70a80f478febf001f88dfd65a64c)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Isovalent */
3 #include <uapi/linux/if_link.h>
4 #include <net/if.h>
5 #include <test_progs.h>
6 
7 #define netkit_peer "nk0"
8 #define netkit_name "nk1"
9 
10 #define ping_addr_neigh		0x0a000002 /* 10.0.0.2 */
11 #define ping_addr_noneigh	0x0a000003 /* 10.0.0.3 */
12 
13 #include "test_tc_link.skel.h"
14 #include "netlink_helpers.h"
15 #include "tc_helpers.h"
16 
17 #define NETKIT_HEADROOM	32
18 #define NETKIT_TAILROOM	8
19 
20 #define MARK		42
21 #define PRIO		0xeb9f
22 #define ICMP_ECHO	8
23 
24 #define FLAG_ADJUST_ROOM (1 << 0)
25 #define FLAG_SAME_NETNS  (1 << 1)
26 
27 struct icmphdr {
28 	__u8		type;
29 	__u8		code;
30 	__sum16		checksum;
31 	struct {
32 		__be16	id;
33 		__be16	sequence;
34 	} echo;
35 };
36 
37 struct iplink_req {
38 	struct nlmsghdr  n;
39 	struct ifinfomsg i;
40 	char             buf[1024];
41 };
42 
43 static int create_netkit(int mode, int policy, int peer_policy, int *ifindex,
44 			 int scrub, int peer_scrub, __u32 flags)
45 {
46 	struct rtnl_handle rth = { .fd = -1 };
47 	struct iplink_req req = {};
48 	struct rtattr *linkinfo, *data;
49 	const char *type = "netkit";
50 	int err;
51 
52 	err = rtnl_open(&rth, 0);
53 	if (!ASSERT_OK(err, "open_rtnetlink"))
54 		return err;
55 
56 	memset(&req, 0, sizeof(req));
57 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
58 	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
59 	req.n.nlmsg_type = RTM_NEWLINK;
60 	req.i.ifi_family = AF_UNSPEC;
61 
62 	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, netkit_name,
63 		  strlen(netkit_name));
64 	linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
65 	addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type));
66 	data = addattr_nest(&req.n, sizeof(req), IFLA_INFO_DATA);
67 	addattr32(&req.n, sizeof(req), IFLA_NETKIT_POLICY, policy);
68 	addattr32(&req.n, sizeof(req), IFLA_NETKIT_PEER_POLICY, peer_policy);
69 	addattr32(&req.n, sizeof(req), IFLA_NETKIT_SCRUB, scrub);
70 	addattr32(&req.n, sizeof(req), IFLA_NETKIT_PEER_SCRUB, peer_scrub);
71 	addattr32(&req.n, sizeof(req), IFLA_NETKIT_MODE, mode);
72 	if (flags & FLAG_ADJUST_ROOM) {
73 		addattr16(&req.n, sizeof(req), IFLA_NETKIT_HEADROOM, NETKIT_HEADROOM);
74 		addattr16(&req.n, sizeof(req), IFLA_NETKIT_TAILROOM, NETKIT_TAILROOM);
75 	}
76 	addattr_nest_end(&req.n, data);
77 	addattr_nest_end(&req.n, linkinfo);
78 
79 	err = rtnl_talk(&rth, &req.n, NULL);
80 	ASSERT_OK(err, "talk_rtnetlink");
81 	rtnl_close(&rth);
82 	*ifindex = if_nametoindex(netkit_name);
83 
84 	ASSERT_GT(*ifindex, 0, "retrieve_ifindex");
85 	ASSERT_OK(system("ip netns add foo"), "create netns");
86 	ASSERT_OK(system("ip link set dev " netkit_name " up"),
87 			 "up primary");
88 	ASSERT_OK(system("ip addr add dev " netkit_name " 10.0.0.1/24"),
89 			 "addr primary");
90 
91 	if (mode == NETKIT_L3) {
92 		ASSERT_EQ(system("ip link set dev " netkit_name
93 				 " addr ee:ff:bb:cc:aa:dd 2> /dev/null"), 512,
94 				 "set hwaddress");
95 	} else {
96 		ASSERT_OK(system("ip link set dev " netkit_name
97 				 " addr ee:ff:bb:cc:aa:dd"),
98 				 "set hwaddress");
99 	}
100 	if (flags & FLAG_SAME_NETNS) {
101 		ASSERT_OK(system("ip link set dev " netkit_peer " up"),
102 				 "up peer");
103 		ASSERT_OK(system("ip addr add dev " netkit_peer " 10.0.0.2/24"),
104 				 "addr peer");
105 	} else {
106 		ASSERT_OK(system("ip link set " netkit_peer " netns foo"),
107 				 "move peer");
108 		ASSERT_OK(system("ip netns exec foo ip link set dev "
109 				 netkit_peer " up"), "up peer");
110 		ASSERT_OK(system("ip netns exec foo ip addr add dev "
111 				 netkit_peer " 10.0.0.2/24"), "addr peer");
112 	}
113 	return err;
114 }
115 
116 static void move_netkit(void)
117 {
118 	ASSERT_OK(system("ip link set " netkit_peer " netns foo"),
119 			 "move peer");
120 	ASSERT_OK(system("ip netns exec foo ip link set dev "
121 			 netkit_peer " up"), "up peer");
122 	ASSERT_OK(system("ip netns exec foo ip addr add dev "
123 			 netkit_peer " 10.0.0.2/24"), "addr peer");
124 }
125 
126 static void destroy_netkit(void)
127 {
128 	ASSERT_OK(system("ip link del dev " netkit_name), "del primary");
129 	ASSERT_OK(system("ip netns del foo"), "delete netns");
130 	ASSERT_EQ(if_nametoindex(netkit_name), 0, netkit_name "_ifindex");
131 }
132 
133 static int __send_icmp(__u32 dest)
134 {
135 	int sock, ret, mark = MARK, prio = PRIO;
136 	struct sockaddr_in addr;
137 	struct icmphdr icmp;
138 
139 	ret = write_sysctl("/proc/sys/net/ipv4/ping_group_range", "0 0");
140 	if (!ASSERT_OK(ret, "write_sysctl(net.ipv4.ping_group_range)"))
141 		return ret;
142 
143 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
144 	if (!ASSERT_GE(sock, 0, "icmp_socket"))
145 		return -errno;
146 
147 	ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
148 			 netkit_name, strlen(netkit_name) + 1);
149 	if (!ASSERT_OK(ret, "setsockopt(SO_BINDTODEVICE)"))
150 		goto out;
151 
152 	ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
153 	if (!ASSERT_OK(ret, "setsockopt(SO_MARK)"))
154 		goto out;
155 
156 	ret = setsockopt(sock, SOL_SOCKET, SO_PRIORITY,
157 			 &prio, sizeof(prio));
158 	if (!ASSERT_OK(ret, "setsockopt(SO_PRIORITY)"))
159 		goto out;
160 
161 	memset(&addr, 0, sizeof(addr));
162 	addr.sin_family = AF_INET;
163 	addr.sin_addr.s_addr = htonl(dest);
164 
165 	memset(&icmp, 0, sizeof(icmp));
166 	icmp.type = ICMP_ECHO;
167 	icmp.echo.id = 1234;
168 	icmp.echo.sequence = 1;
169 
170 	ret = sendto(sock, &icmp, sizeof(icmp), 0,
171 		     (struct sockaddr *)&addr, sizeof(addr));
172 	if (!ASSERT_GE(ret, 0, "icmp_sendto"))
173 		ret = -errno;
174 	else
175 		ret = 0;
176 out:
177 	close(sock);
178 	return ret;
179 }
180 
181 static int send_icmp(void)
182 {
183 	return __send_icmp(ping_addr_neigh);
184 }
185 
186 void serial_test_tc_netkit_basic(void)
187 {
188 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
189 	LIBBPF_OPTS(bpf_netkit_opts, optl);
190 	__u32 prog_ids[2], link_ids[2];
191 	__u32 pid1, pid2, lid1, lid2;
192 	struct test_tc_link *skel;
193 	struct bpf_link *link;
194 	int err, ifindex;
195 
196 	err = create_netkit(NETKIT_L2, NETKIT_PASS, NETKIT_PASS,
197 			    &ifindex, NETKIT_SCRUB_DEFAULT,
198 			    NETKIT_SCRUB_DEFAULT, 0);
199 	if (err)
200 		return;
201 
202 	skel = test_tc_link__open();
203 	if (!ASSERT_OK_PTR(skel, "skel_open"))
204 		goto cleanup;
205 
206 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
207 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
208 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
209 		  BPF_NETKIT_PEER), 0, "tc2_attach_type");
210 
211 	err = test_tc_link__load(skel);
212 	if (!ASSERT_OK(err, "skel_load"))
213 		goto cleanup;
214 
215 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
216 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
217 
218 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
219 
220 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
221 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
222 
223 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
224 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
225 
226 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
227 	if (!ASSERT_OK_PTR(link, "link_attach"))
228 		goto cleanup;
229 
230 	skel->links.tc1 = link;
231 
232 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
233 
234 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
235 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
236 
237 	optq.prog_ids = prog_ids;
238 	optq.link_ids = link_ids;
239 
240 	memset(prog_ids, 0, sizeof(prog_ids));
241 	memset(link_ids, 0, sizeof(link_ids));
242 	optq.count = ARRAY_SIZE(prog_ids);
243 
244 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq);
245 	if (!ASSERT_OK(err, "prog_query"))
246 		goto cleanup;
247 
248 	ASSERT_EQ(optq.count, 1, "count");
249 	ASSERT_EQ(optq.revision, 2, "revision");
250 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
251 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
252 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
253 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
254 
255 	tc_skel_reset_all_seen(skel);
256 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
257 
258 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
259 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
260 
261 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl);
262 	if (!ASSERT_OK_PTR(link, "link_attach"))
263 		goto cleanup;
264 
265 	skel->links.tc2 = link;
266 
267 	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
268 	ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
269 
270 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
271 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 1);
272 
273 	memset(prog_ids, 0, sizeof(prog_ids));
274 	memset(link_ids, 0, sizeof(link_ids));
275 	optq.count = ARRAY_SIZE(prog_ids);
276 
277 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PEER, &optq);
278 	if (!ASSERT_OK(err, "prog_query"))
279 		goto cleanup;
280 
281 	ASSERT_EQ(optq.count, 1, "count");
282 	ASSERT_EQ(optq.revision, 2, "revision");
283 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
284 	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
285 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
286 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
287 
288 	tc_skel_reset_all_seen(skel);
289 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
290 
291 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
292 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
293 cleanup:
294 	test_tc_link__destroy(skel);
295 
296 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
297 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
298 	destroy_netkit();
299 }
300 
301 static void serial_test_tc_netkit_multi_links_target(int mode, int target)
302 {
303 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
304 	LIBBPF_OPTS(bpf_netkit_opts, optl);
305 	__u32 prog_ids[3], link_ids[3];
306 	__u32 pid1, pid2, lid1, lid2;
307 	struct test_tc_link *skel;
308 	struct bpf_link *link;
309 	int err, ifindex;
310 
311 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
312 			    &ifindex, NETKIT_SCRUB_DEFAULT,
313 			    NETKIT_SCRUB_DEFAULT, 0);
314 	if (err)
315 		return;
316 
317 	skel = test_tc_link__open();
318 	if (!ASSERT_OK_PTR(skel, "skel_open"))
319 		goto cleanup;
320 
321 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
322 		  target), 0, "tc1_attach_type");
323 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
324 		  target), 0, "tc2_attach_type");
325 
326 	err = test_tc_link__load(skel);
327 	if (!ASSERT_OK(err, "skel_load"))
328 		goto cleanup;
329 
330 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
331 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
332 
333 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
334 
335 	assert_mprog_count_ifindex(ifindex, target, 0);
336 
337 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
338 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
339 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
340 
341 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
342 	if (!ASSERT_OK_PTR(link, "link_attach"))
343 		goto cleanup;
344 
345 	skel->links.tc1 = link;
346 
347 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
348 
349 	assert_mprog_count_ifindex(ifindex, target, 1);
350 
351 	optq.prog_ids = prog_ids;
352 	optq.link_ids = link_ids;
353 
354 	memset(prog_ids, 0, sizeof(prog_ids));
355 	memset(link_ids, 0, sizeof(link_ids));
356 	optq.count = ARRAY_SIZE(prog_ids);
357 
358 	err = bpf_prog_query_opts(ifindex, target, &optq);
359 	if (!ASSERT_OK(err, "prog_query"))
360 		goto cleanup;
361 
362 	ASSERT_EQ(optq.count, 1, "count");
363 	ASSERT_EQ(optq.revision, 2, "revision");
364 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
365 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
366 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
367 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
368 
369 	tc_skel_reset_all_seen(skel);
370 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
371 
372 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
373 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
374 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
375 
376 	LIBBPF_OPTS_RESET(optl,
377 		.flags = BPF_F_BEFORE,
378 		.relative_fd = bpf_program__fd(skel->progs.tc1),
379 	);
380 
381 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl);
382 	if (!ASSERT_OK_PTR(link, "link_attach"))
383 		goto cleanup;
384 
385 	skel->links.tc2 = link;
386 
387 	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
388 	ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
389 
390 	assert_mprog_count_ifindex(ifindex, target, 2);
391 
392 	memset(prog_ids, 0, sizeof(prog_ids));
393 	memset(link_ids, 0, sizeof(link_ids));
394 	optq.count = ARRAY_SIZE(prog_ids);
395 
396 	err = bpf_prog_query_opts(ifindex, target, &optq);
397 	if (!ASSERT_OK(err, "prog_query"))
398 		goto cleanup;
399 
400 	ASSERT_EQ(optq.count, 2, "count");
401 	ASSERT_EQ(optq.revision, 3, "revision");
402 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
403 	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
404 	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
405 	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
406 	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
407 	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
408 
409 	tc_skel_reset_all_seen(skel);
410 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
411 
412 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
413 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
414 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
415 cleanup:
416 	test_tc_link__destroy(skel);
417 
418 	assert_mprog_count_ifindex(ifindex, target, 0);
419 	destroy_netkit();
420 }
421 
422 void serial_test_tc_netkit_multi_links(void)
423 {
424 	serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
425 	serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
426 	serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PEER);
427 	serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PEER);
428 }
429 
430 static void serial_test_tc_netkit_multi_opts_target(int mode, int target)
431 {
432 	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
433 	LIBBPF_OPTS(bpf_prog_detach_opts, optd);
434 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
435 	__u32 pid1, pid2, fd1, fd2;
436 	__u32 prog_ids[3];
437 	struct test_tc_link *skel;
438 	int err, ifindex;
439 
440 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
441 			    &ifindex, NETKIT_SCRUB_DEFAULT,
442 			    NETKIT_SCRUB_DEFAULT, 0);
443 	if (err)
444 		return;
445 
446 	skel = test_tc_link__open_and_load();
447 	if (!ASSERT_OK_PTR(skel, "skel_load"))
448 		goto cleanup;
449 
450 	fd1 = bpf_program__fd(skel->progs.tc1);
451 	fd2 = bpf_program__fd(skel->progs.tc2);
452 
453 	pid1 = id_from_prog_fd(fd1);
454 	pid2 = id_from_prog_fd(fd2);
455 
456 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
457 
458 	assert_mprog_count_ifindex(ifindex, target, 0);
459 
460 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
461 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
462 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
463 
464 	err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);
465 	if (!ASSERT_EQ(err, 0, "prog_attach"))
466 		goto cleanup;
467 
468 	assert_mprog_count_ifindex(ifindex, target, 1);
469 
470 	optq.prog_ids = prog_ids;
471 
472 	memset(prog_ids, 0, sizeof(prog_ids));
473 	optq.count = ARRAY_SIZE(prog_ids);
474 
475 	err = bpf_prog_query_opts(ifindex, target, &optq);
476 	if (!ASSERT_OK(err, "prog_query"))
477 		goto cleanup_fd1;
478 
479 	ASSERT_EQ(optq.count, 1, "count");
480 	ASSERT_EQ(optq.revision, 2, "revision");
481 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
482 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
483 
484 	tc_skel_reset_all_seen(skel);
485 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
486 
487 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
488 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
489 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
490 
491 	LIBBPF_OPTS_RESET(opta,
492 		.flags = BPF_F_BEFORE,
493 		.relative_fd = fd1,
494 	);
495 
496 	err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);
497 	if (!ASSERT_EQ(err, 0, "prog_attach"))
498 		goto cleanup_fd1;
499 
500 	assert_mprog_count_ifindex(ifindex, target, 2);
501 
502 	memset(prog_ids, 0, sizeof(prog_ids));
503 	optq.count = ARRAY_SIZE(prog_ids);
504 
505 	err = bpf_prog_query_opts(ifindex, target, &optq);
506 	if (!ASSERT_OK(err, "prog_query"))
507 		goto cleanup_fd2;
508 
509 	ASSERT_EQ(optq.count, 2, "count");
510 	ASSERT_EQ(optq.revision, 3, "revision");
511 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
512 	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
513 	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
514 
515 	tc_skel_reset_all_seen(skel);
516 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
517 
518 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
519 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
520 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
521 
522 cleanup_fd2:
523 	err = bpf_prog_detach_opts(fd2, ifindex, target, &optd);
524 	ASSERT_OK(err, "prog_detach");
525 	assert_mprog_count_ifindex(ifindex, target, 1);
526 cleanup_fd1:
527 	err = bpf_prog_detach_opts(fd1, ifindex, target, &optd);
528 	ASSERT_OK(err, "prog_detach");
529 	assert_mprog_count_ifindex(ifindex, target, 0);
530 cleanup:
531 	test_tc_link__destroy(skel);
532 
533 	assert_mprog_count_ifindex(ifindex, target, 0);
534 	destroy_netkit();
535 }
536 
537 void serial_test_tc_netkit_multi_opts(void)
538 {
539 	serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
540 	serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
541 	serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PEER);
542 	serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PEER);
543 }
544 
545 void serial_test_tc_netkit_device(void)
546 {
547 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
548 	LIBBPF_OPTS(bpf_netkit_opts, optl);
549 	__u32 prog_ids[2], link_ids[2];
550 	__u32 pid1, pid2, lid1;
551 	struct test_tc_link *skel;
552 	struct bpf_link *link;
553 	int err, ifindex, ifindex2;
554 
555 	err = create_netkit(NETKIT_L3, NETKIT_PASS, NETKIT_PASS,
556 			    &ifindex, NETKIT_SCRUB_DEFAULT,
557 			    NETKIT_SCRUB_DEFAULT, FLAG_SAME_NETNS);
558 	if (err)
559 		return;
560 
561 	ifindex2 = if_nametoindex(netkit_peer);
562 	ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2");
563 
564 	skel = test_tc_link__open();
565 	if (!ASSERT_OK_PTR(skel, "skel_open"))
566 		goto cleanup;
567 
568 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
569 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
570 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
571 		  BPF_NETKIT_PEER), 0, "tc2_attach_type");
572 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3,
573 		  BPF_NETKIT_PRIMARY), 0, "tc3_attach_type");
574 
575 	err = test_tc_link__load(skel);
576 	if (!ASSERT_OK(err, "skel_load"))
577 		goto cleanup;
578 
579 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
580 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
581 
582 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
583 
584 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
585 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
586 
587 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
588 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
589 
590 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
591 	if (!ASSERT_OK_PTR(link, "link_attach"))
592 		goto cleanup;
593 
594 	skel->links.tc1 = link;
595 
596 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
597 
598 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
599 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
600 
601 	optq.prog_ids = prog_ids;
602 	optq.link_ids = link_ids;
603 
604 	memset(prog_ids, 0, sizeof(prog_ids));
605 	memset(link_ids, 0, sizeof(link_ids));
606 	optq.count = ARRAY_SIZE(prog_ids);
607 
608 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq);
609 	if (!ASSERT_OK(err, "prog_query"))
610 		goto cleanup;
611 
612 	ASSERT_EQ(optq.count, 1, "count");
613 	ASSERT_EQ(optq.revision, 2, "revision");
614 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
615 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
616 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
617 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
618 
619 	tc_skel_reset_all_seen(skel);
620 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
621 
622 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
623 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
624 
625 	memset(prog_ids, 0, sizeof(prog_ids));
626 	memset(link_ids, 0, sizeof(link_ids));
627 	optq.count = ARRAY_SIZE(prog_ids);
628 
629 	err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PRIMARY, &optq);
630 	ASSERT_EQ(err, -EACCES, "prog_query_should_fail");
631 
632 	err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PEER, &optq);
633 	ASSERT_EQ(err, -EACCES, "prog_query_should_fail");
634 
635 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex2, &optl);
636 	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
637 		bpf_link__destroy(link);
638 		goto cleanup;
639 	}
640 
641 	link = bpf_program__attach_netkit(skel->progs.tc3, ifindex2, &optl);
642 	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
643 		bpf_link__destroy(link);
644 		goto cleanup;
645 	}
646 
647 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
648 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
649 cleanup:
650 	test_tc_link__destroy(skel);
651 
652 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
653 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
654 	destroy_netkit();
655 }
656 
657 static void serial_test_tc_netkit_neigh_links_target(int mode, int target)
658 {
659 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
660 	LIBBPF_OPTS(bpf_netkit_opts, optl);
661 	__u32 prog_ids[2], link_ids[2];
662 	__u32 pid1, lid1;
663 	struct test_tc_link *skel;
664 	struct bpf_link *link;
665 	int err, ifindex;
666 
667 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
668 			    &ifindex, NETKIT_SCRUB_DEFAULT,
669 			    NETKIT_SCRUB_DEFAULT, 0);
670 	if (err)
671 		return;
672 
673 	skel = test_tc_link__open();
674 	if (!ASSERT_OK_PTR(skel, "skel_open"))
675 		goto cleanup;
676 
677 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
678 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
679 
680 	err = test_tc_link__load(skel);
681 	if (!ASSERT_OK(err, "skel_load"))
682 		goto cleanup;
683 
684 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
685 
686 	assert_mprog_count_ifindex(ifindex, target, 0);
687 
688 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
689 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
690 
691 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
692 	if (!ASSERT_OK_PTR(link, "link_attach"))
693 		goto cleanup;
694 
695 	skel->links.tc1 = link;
696 
697 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
698 
699 	assert_mprog_count_ifindex(ifindex, target, 1);
700 
701 	optq.prog_ids = prog_ids;
702 	optq.link_ids = link_ids;
703 
704 	memset(prog_ids, 0, sizeof(prog_ids));
705 	memset(link_ids, 0, sizeof(link_ids));
706 	optq.count = ARRAY_SIZE(prog_ids);
707 
708 	err = bpf_prog_query_opts(ifindex, target, &optq);
709 	if (!ASSERT_OK(err, "prog_query"))
710 		goto cleanup;
711 
712 	ASSERT_EQ(optq.count, 1, "count");
713 	ASSERT_EQ(optq.revision, 2, "revision");
714 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
715 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
716 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
717 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
718 
719 	tc_skel_reset_all_seen(skel);
720 	ASSERT_EQ(__send_icmp(ping_addr_noneigh), 0, "icmp_pkt");
721 
722 	ASSERT_EQ(skel->bss->seen_tc1, true /* L2: ARP */, "seen_tc1");
723 	ASSERT_EQ(skel->bss->seen_eth, mode == NETKIT_L3, "seen_eth");
724 cleanup:
725 	test_tc_link__destroy(skel);
726 
727 	assert_mprog_count_ifindex(ifindex, target, 0);
728 	destroy_netkit();
729 }
730 
731 void serial_test_tc_netkit_neigh_links(void)
732 {
733 	serial_test_tc_netkit_neigh_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
734 	serial_test_tc_netkit_neigh_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
735 }
736 
737 static void serial_test_tc_netkit_pkt_type_mode(int mode)
738 {
739 	LIBBPF_OPTS(bpf_netkit_opts, optl_nk);
740 	LIBBPF_OPTS(bpf_tcx_opts, optl_tcx);
741 	int err, ifindex, ifindex2;
742 	struct test_tc_link *skel;
743 	struct bpf_link *link;
744 
745 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
746 			    &ifindex, NETKIT_SCRUB_DEFAULT,
747 			    NETKIT_SCRUB_DEFAULT, FLAG_SAME_NETNS);
748 	if (err)
749 		return;
750 
751 	ifindex2 = if_nametoindex(netkit_peer);
752 	ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2");
753 
754 	skel = test_tc_link__open();
755 	if (!ASSERT_OK_PTR(skel, "skel_open"))
756 		goto cleanup;
757 
758 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
759 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
760 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc7,
761 		  BPF_TCX_INGRESS), 0, "tc7_attach_type");
762 
763 	err = test_tc_link__load(skel);
764 	if (!ASSERT_OK(err, "skel_load"))
765 		goto cleanup;
766 
767 	assert_mprog_count_ifindex(ifindex,  BPF_NETKIT_PRIMARY, 0);
768 	assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0);
769 
770 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl_nk);
771 	if (!ASSERT_OK_PTR(link, "link_attach"))
772 		goto cleanup;
773 
774 	skel->links.tc1 = link;
775 
776 	assert_mprog_count_ifindex(ifindex,  BPF_NETKIT_PRIMARY, 1);
777 	assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0);
778 
779 	link = bpf_program__attach_tcx(skel->progs.tc7, ifindex2, &optl_tcx);
780 	if (!ASSERT_OK_PTR(link, "link_attach"))
781 		goto cleanup;
782 
783 	skel->links.tc7 = link;
784 
785 	assert_mprog_count_ifindex(ifindex,  BPF_NETKIT_PRIMARY, 1);
786 	assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 1);
787 
788 	move_netkit();
789 
790 	tc_skel_reset_all_seen(skel);
791 	skel->bss->set_type = true;
792 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
793 
794 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
795 	ASSERT_EQ(skel->bss->seen_tc7, true, "seen_tc7");
796 
797 	ASSERT_EQ(skel->bss->seen_host,  true, "seen_host");
798 	ASSERT_EQ(skel->bss->seen_mcast, true, "seen_mcast");
799 cleanup:
800 	test_tc_link__destroy(skel);
801 
802 	assert_mprog_count_ifindex(ifindex,  BPF_NETKIT_PRIMARY, 0);
803 	destroy_netkit();
804 }
805 
806 void serial_test_tc_netkit_pkt_type(void)
807 {
808 	serial_test_tc_netkit_pkt_type_mode(NETKIT_L2);
809 	serial_test_tc_netkit_pkt_type_mode(NETKIT_L3);
810 }
811 
812 static void serial_test_tc_netkit_scrub_type(int scrub, bool room)
813 {
814 	LIBBPF_OPTS(bpf_netkit_opts, optl);
815 	struct test_tc_link *skel;
816 	struct bpf_link *link;
817 	int err, ifindex;
818 
819 	err = create_netkit(NETKIT_L2, NETKIT_PASS, NETKIT_PASS,
820 			    &ifindex, scrub, scrub,
821 			    room ? FLAG_ADJUST_ROOM : 0);
822 	if (err)
823 		return;
824 
825 	skel = test_tc_link__open();
826 	if (!ASSERT_OK_PTR(skel, "skel_open"))
827 		goto cleanup;
828 
829 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc8,
830 		  BPF_NETKIT_PRIMARY), 0, "tc8_attach_type");
831 
832 	err = test_tc_link__load(skel);
833 	if (!ASSERT_OK(err, "skel_load"))
834 		goto cleanup;
835 
836 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
837 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
838 
839 	ASSERT_EQ(skel->bss->seen_tc8, false, "seen_tc8");
840 
841 	link = bpf_program__attach_netkit(skel->progs.tc8, ifindex, &optl);
842 	if (!ASSERT_OK_PTR(link, "link_attach"))
843 		goto cleanup;
844 
845 	skel->links.tc8 = link;
846 
847 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
848 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
849 
850 	tc_skel_reset_all_seen(skel);
851 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
852 
853 	ASSERT_EQ(skel->bss->seen_tc8, true, "seen_tc8");
854 	ASSERT_EQ(skel->bss->mark, scrub == NETKIT_SCRUB_NONE ? MARK : 0, "mark");
855 	ASSERT_EQ(skel->bss->prio, scrub == NETKIT_SCRUB_NONE ? PRIO : 0, "prio");
856 	ASSERT_EQ(skel->bss->headroom, room ? NETKIT_HEADROOM : 0, "headroom");
857 	ASSERT_EQ(skel->bss->tailroom, room ? NETKIT_TAILROOM : 0, "tailroom");
858 cleanup:
859 	test_tc_link__destroy(skel);
860 
861 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
862 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
863 	destroy_netkit();
864 }
865 
866 void serial_test_tc_netkit_scrub(void)
867 {
868 	serial_test_tc_netkit_scrub_type(NETKIT_SCRUB_DEFAULT, false);
869 	serial_test_tc_netkit_scrub_type(NETKIT_SCRUB_NONE, true);
870 }
871