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