xref: /linux/tools/testing/selftests/bpf/prog_tests/tc_netkit.c (revision f6154d8babbb8a98f0d3ea325aafae2e33bfd8be)
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 	if (same_netns) {
77 		ASSERT_OK(system("ip link set dev " netkit_peer " up"),
78 				 "up peer");
79 		ASSERT_OK(system("ip addr add dev " netkit_peer " 10.0.0.2/24"),
80 				 "addr peer");
81 	} else {
82 		ASSERT_OK(system("ip link set " netkit_peer " netns foo"),
83 				 "move peer");
84 		ASSERT_OK(system("ip netns exec foo ip link set dev "
85 				 netkit_peer " up"), "up peer");
86 		ASSERT_OK(system("ip netns exec foo ip addr add dev "
87 				 netkit_peer " 10.0.0.2/24"), "addr peer");
88 	}
89 	return err;
90 }
91 
92 static void destroy_netkit(void)
93 {
94 	ASSERT_OK(system("ip link del dev " netkit_name), "del primary");
95 	ASSERT_OK(system("ip netns del foo"), "delete netns");
96 	ASSERT_EQ(if_nametoindex(netkit_name), 0, netkit_name "_ifindex");
97 }
98 
99 static int __send_icmp(__u32 dest)
100 {
101 	struct sockaddr_in addr;
102 	struct icmphdr icmp;
103 	int sock, ret;
104 
105 	ret = write_sysctl("/proc/sys/net/ipv4/ping_group_range", "0 0");
106 	if (!ASSERT_OK(ret, "write_sysctl(net.ipv4.ping_group_range)"))
107 		return ret;
108 
109 	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
110 	if (!ASSERT_GE(sock, 0, "icmp_socket"))
111 		return -errno;
112 
113 	ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
114 			 netkit_name, strlen(netkit_name) + 1);
115 	if (!ASSERT_OK(ret, "setsockopt(SO_BINDTODEVICE)"))
116 		goto out;
117 
118 	memset(&addr, 0, sizeof(addr));
119 	addr.sin_family = AF_INET;
120 	addr.sin_addr.s_addr = htonl(dest);
121 
122 	memset(&icmp, 0, sizeof(icmp));
123 	icmp.type = ICMP_ECHO;
124 	icmp.echo.id = 1234;
125 	icmp.echo.sequence = 1;
126 
127 	ret = sendto(sock, &icmp, sizeof(icmp), 0,
128 		     (struct sockaddr *)&addr, sizeof(addr));
129 	if (!ASSERT_GE(ret, 0, "icmp_sendto"))
130 		ret = -errno;
131 	else
132 		ret = 0;
133 out:
134 	close(sock);
135 	return ret;
136 }
137 
138 static int send_icmp(void)
139 {
140 	return __send_icmp(ping_addr_neigh);
141 }
142 
143 void serial_test_tc_netkit_basic(void)
144 {
145 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
146 	LIBBPF_OPTS(bpf_netkit_opts, optl);
147 	__u32 prog_ids[2], link_ids[2];
148 	__u32 pid1, pid2, lid1, lid2;
149 	struct test_tc_link *skel;
150 	struct bpf_link *link;
151 	int err, ifindex;
152 
153 	err = create_netkit(NETKIT_L2, NETKIT_PASS, NETKIT_PASS,
154 			    &ifindex, false);
155 	if (err)
156 		return;
157 
158 	skel = test_tc_link__open();
159 	if (!ASSERT_OK_PTR(skel, "skel_open"))
160 		goto cleanup;
161 
162 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
163 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
164 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
165 		  BPF_NETKIT_PEER), 0, "tc2_attach_type");
166 
167 	err = test_tc_link__load(skel);
168 	if (!ASSERT_OK(err, "skel_load"))
169 		goto cleanup;
170 
171 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
172 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
173 
174 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
175 
176 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
177 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
178 
179 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
180 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
181 
182 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
183 	if (!ASSERT_OK_PTR(link, "link_attach"))
184 		goto cleanup;
185 
186 	skel->links.tc1 = link;
187 
188 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
189 
190 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
191 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
192 
193 	optq.prog_ids = prog_ids;
194 	optq.link_ids = link_ids;
195 
196 	memset(prog_ids, 0, sizeof(prog_ids));
197 	memset(link_ids, 0, sizeof(link_ids));
198 	optq.count = ARRAY_SIZE(prog_ids);
199 
200 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq);
201 	if (!ASSERT_OK(err, "prog_query"))
202 		goto cleanup;
203 
204 	ASSERT_EQ(optq.count, 1, "count");
205 	ASSERT_EQ(optq.revision, 2, "revision");
206 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
207 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
208 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
209 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
210 
211 	tc_skel_reset_all_seen(skel);
212 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
213 
214 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
215 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
216 
217 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl);
218 	if (!ASSERT_OK_PTR(link, "link_attach"))
219 		goto cleanup;
220 
221 	skel->links.tc2 = link;
222 
223 	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
224 	ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
225 
226 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
227 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 1);
228 
229 	memset(prog_ids, 0, sizeof(prog_ids));
230 	memset(link_ids, 0, sizeof(link_ids));
231 	optq.count = ARRAY_SIZE(prog_ids);
232 
233 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PEER, &optq);
234 	if (!ASSERT_OK(err, "prog_query"))
235 		goto cleanup;
236 
237 	ASSERT_EQ(optq.count, 1, "count");
238 	ASSERT_EQ(optq.revision, 2, "revision");
239 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
240 	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
241 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
242 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
243 
244 	tc_skel_reset_all_seen(skel);
245 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
246 
247 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
248 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
249 cleanup:
250 	test_tc_link__destroy(skel);
251 
252 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
253 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
254 	destroy_netkit();
255 }
256 
257 static void serial_test_tc_netkit_multi_links_target(int mode, int target)
258 {
259 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
260 	LIBBPF_OPTS(bpf_netkit_opts, optl);
261 	__u32 prog_ids[3], link_ids[3];
262 	__u32 pid1, pid2, lid1, lid2;
263 	struct test_tc_link *skel;
264 	struct bpf_link *link;
265 	int err, ifindex;
266 
267 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
268 			    &ifindex, false);
269 	if (err)
270 		return;
271 
272 	skel = test_tc_link__open();
273 	if (!ASSERT_OK_PTR(skel, "skel_open"))
274 		goto cleanup;
275 
276 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
277 		  target), 0, "tc1_attach_type");
278 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
279 		  target), 0, "tc2_attach_type");
280 
281 	err = test_tc_link__load(skel);
282 	if (!ASSERT_OK(err, "skel_load"))
283 		goto cleanup;
284 
285 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
286 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
287 
288 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
289 
290 	assert_mprog_count_ifindex(ifindex, target, 0);
291 
292 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
293 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
294 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
295 
296 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
297 	if (!ASSERT_OK_PTR(link, "link_attach"))
298 		goto cleanup;
299 
300 	skel->links.tc1 = link;
301 
302 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
303 
304 	assert_mprog_count_ifindex(ifindex, target, 1);
305 
306 	optq.prog_ids = prog_ids;
307 	optq.link_ids = link_ids;
308 
309 	memset(prog_ids, 0, sizeof(prog_ids));
310 	memset(link_ids, 0, sizeof(link_ids));
311 	optq.count = ARRAY_SIZE(prog_ids);
312 
313 	err = bpf_prog_query_opts(ifindex, target, &optq);
314 	if (!ASSERT_OK(err, "prog_query"))
315 		goto cleanup;
316 
317 	ASSERT_EQ(optq.count, 1, "count");
318 	ASSERT_EQ(optq.revision, 2, "revision");
319 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
320 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
321 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
322 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
323 
324 	tc_skel_reset_all_seen(skel);
325 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
326 
327 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
328 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
329 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
330 
331 	LIBBPF_OPTS_RESET(optl,
332 		.flags = BPF_F_BEFORE,
333 		.relative_fd = bpf_program__fd(skel->progs.tc1),
334 	);
335 
336 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex, &optl);
337 	if (!ASSERT_OK_PTR(link, "link_attach"))
338 		goto cleanup;
339 
340 	skel->links.tc2 = link;
341 
342 	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));
343 	ASSERT_NEQ(lid1, lid2, "link_ids_1_2");
344 
345 	assert_mprog_count_ifindex(ifindex, target, 2);
346 
347 	memset(prog_ids, 0, sizeof(prog_ids));
348 	memset(link_ids, 0, sizeof(link_ids));
349 	optq.count = ARRAY_SIZE(prog_ids);
350 
351 	err = bpf_prog_query_opts(ifindex, target, &optq);
352 	if (!ASSERT_OK(err, "prog_query"))
353 		goto cleanup;
354 
355 	ASSERT_EQ(optq.count, 2, "count");
356 	ASSERT_EQ(optq.revision, 3, "revision");
357 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
358 	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");
359 	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
360 	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");
361 	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
362 	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
363 
364 	tc_skel_reset_all_seen(skel);
365 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
366 
367 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
368 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
369 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
370 cleanup:
371 	test_tc_link__destroy(skel);
372 
373 	assert_mprog_count_ifindex(ifindex, target, 0);
374 	destroy_netkit();
375 }
376 
377 void serial_test_tc_netkit_multi_links(void)
378 {
379 	serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
380 	serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
381 	serial_test_tc_netkit_multi_links_target(NETKIT_L2, BPF_NETKIT_PEER);
382 	serial_test_tc_netkit_multi_links_target(NETKIT_L3, BPF_NETKIT_PEER);
383 }
384 
385 static void serial_test_tc_netkit_multi_opts_target(int mode, int target)
386 {
387 	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
388 	LIBBPF_OPTS(bpf_prog_detach_opts, optd);
389 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
390 	__u32 pid1, pid2, fd1, fd2;
391 	__u32 prog_ids[3];
392 	struct test_tc_link *skel;
393 	int err, ifindex;
394 
395 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
396 			    &ifindex, false);
397 	if (err)
398 		return;
399 
400 	skel = test_tc_link__open_and_load();
401 	if (!ASSERT_OK_PTR(skel, "skel_load"))
402 		goto cleanup;
403 
404 	fd1 = bpf_program__fd(skel->progs.tc1);
405 	fd2 = bpf_program__fd(skel->progs.tc2);
406 
407 	pid1 = id_from_prog_fd(fd1);
408 	pid2 = id_from_prog_fd(fd2);
409 
410 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
411 
412 	assert_mprog_count_ifindex(ifindex, target, 0);
413 
414 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
415 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
416 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
417 
418 	err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);
419 	if (!ASSERT_EQ(err, 0, "prog_attach"))
420 		goto cleanup;
421 
422 	assert_mprog_count_ifindex(ifindex, target, 1);
423 
424 	optq.prog_ids = prog_ids;
425 
426 	memset(prog_ids, 0, sizeof(prog_ids));
427 	optq.count = ARRAY_SIZE(prog_ids);
428 
429 	err = bpf_prog_query_opts(ifindex, target, &optq);
430 	if (!ASSERT_OK(err, "prog_query"))
431 		goto cleanup_fd1;
432 
433 	ASSERT_EQ(optq.count, 1, "count");
434 	ASSERT_EQ(optq.revision, 2, "revision");
435 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
436 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
437 
438 	tc_skel_reset_all_seen(skel);
439 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
440 
441 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
442 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
443 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
444 
445 	LIBBPF_OPTS_RESET(opta,
446 		.flags = BPF_F_BEFORE,
447 		.relative_fd = fd1,
448 	);
449 
450 	err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);
451 	if (!ASSERT_EQ(err, 0, "prog_attach"))
452 		goto cleanup_fd1;
453 
454 	assert_mprog_count_ifindex(ifindex, target, 2);
455 
456 	memset(prog_ids, 0, sizeof(prog_ids));
457 	optq.count = ARRAY_SIZE(prog_ids);
458 
459 	err = bpf_prog_query_opts(ifindex, target, &optq);
460 	if (!ASSERT_OK(err, "prog_query"))
461 		goto cleanup_fd2;
462 
463 	ASSERT_EQ(optq.count, 2, "count");
464 	ASSERT_EQ(optq.revision, 3, "revision");
465 	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");
466 	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");
467 	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
468 
469 	tc_skel_reset_all_seen(skel);
470 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
471 
472 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
473 	ASSERT_EQ(skel->bss->seen_eth, true, "seen_eth");
474 	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
475 
476 cleanup_fd2:
477 	err = bpf_prog_detach_opts(fd2, ifindex, target, &optd);
478 	ASSERT_OK(err, "prog_detach");
479 	assert_mprog_count_ifindex(ifindex, target, 1);
480 cleanup_fd1:
481 	err = bpf_prog_detach_opts(fd1, ifindex, target, &optd);
482 	ASSERT_OK(err, "prog_detach");
483 	assert_mprog_count_ifindex(ifindex, target, 0);
484 cleanup:
485 	test_tc_link__destroy(skel);
486 
487 	assert_mprog_count_ifindex(ifindex, target, 0);
488 	destroy_netkit();
489 }
490 
491 void serial_test_tc_netkit_multi_opts(void)
492 {
493 	serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
494 	serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
495 	serial_test_tc_netkit_multi_opts_target(NETKIT_L2, BPF_NETKIT_PEER);
496 	serial_test_tc_netkit_multi_opts_target(NETKIT_L3, BPF_NETKIT_PEER);
497 }
498 
499 void serial_test_tc_netkit_device(void)
500 {
501 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
502 	LIBBPF_OPTS(bpf_netkit_opts, optl);
503 	__u32 prog_ids[2], link_ids[2];
504 	__u32 pid1, pid2, lid1;
505 	struct test_tc_link *skel;
506 	struct bpf_link *link;
507 	int err, ifindex, ifindex2;
508 
509 	err = create_netkit(NETKIT_L3, NETKIT_PASS, NETKIT_PASS,
510 			    &ifindex, true);
511 	if (err)
512 		return;
513 
514 	ifindex2 = if_nametoindex(netkit_peer);
515 	ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2");
516 
517 	skel = test_tc_link__open();
518 	if (!ASSERT_OK_PTR(skel, "skel_open"))
519 		goto cleanup;
520 
521 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
522 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
523 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2,
524 		  BPF_NETKIT_PEER), 0, "tc2_attach_type");
525 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3,
526 		  BPF_NETKIT_PRIMARY), 0, "tc3_attach_type");
527 
528 	err = test_tc_link__load(skel);
529 	if (!ASSERT_OK(err, "skel_load"))
530 		goto cleanup;
531 
532 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
533 	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
534 
535 	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
536 
537 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
538 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
539 
540 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
541 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
542 
543 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
544 	if (!ASSERT_OK_PTR(link, "link_attach"))
545 		goto cleanup;
546 
547 	skel->links.tc1 = link;
548 
549 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
550 
551 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
552 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
553 
554 	optq.prog_ids = prog_ids;
555 	optq.link_ids = link_ids;
556 
557 	memset(prog_ids, 0, sizeof(prog_ids));
558 	memset(link_ids, 0, sizeof(link_ids));
559 	optq.count = ARRAY_SIZE(prog_ids);
560 
561 	err = bpf_prog_query_opts(ifindex, BPF_NETKIT_PRIMARY, &optq);
562 	if (!ASSERT_OK(err, "prog_query"))
563 		goto cleanup;
564 
565 	ASSERT_EQ(optq.count, 1, "count");
566 	ASSERT_EQ(optq.revision, 2, "revision");
567 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
568 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
569 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
570 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
571 
572 	tc_skel_reset_all_seen(skel);
573 	ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
574 
575 	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
576 	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
577 
578 	memset(prog_ids, 0, sizeof(prog_ids));
579 	memset(link_ids, 0, sizeof(link_ids));
580 	optq.count = ARRAY_SIZE(prog_ids);
581 
582 	err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PRIMARY, &optq);
583 	ASSERT_EQ(err, -EACCES, "prog_query_should_fail");
584 
585 	err = bpf_prog_query_opts(ifindex2, BPF_NETKIT_PEER, &optq);
586 	ASSERT_EQ(err, -EACCES, "prog_query_should_fail");
587 
588 	link = bpf_program__attach_netkit(skel->progs.tc2, ifindex2, &optl);
589 	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
590 		bpf_link__destroy(link);
591 		goto cleanup;
592 	}
593 
594 	link = bpf_program__attach_netkit(skel->progs.tc3, ifindex2, &optl);
595 	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {
596 		bpf_link__destroy(link);
597 		goto cleanup;
598 	}
599 
600 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
601 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
602 cleanup:
603 	test_tc_link__destroy(skel);
604 
605 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
606 	assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PEER, 0);
607 	destroy_netkit();
608 }
609 
610 static void serial_test_tc_netkit_neigh_links_target(int mode, int target)
611 {
612 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
613 	LIBBPF_OPTS(bpf_netkit_opts, optl);
614 	__u32 prog_ids[2], link_ids[2];
615 	__u32 pid1, lid1;
616 	struct test_tc_link *skel;
617 	struct bpf_link *link;
618 	int err, ifindex;
619 
620 	err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
621 			    &ifindex, false);
622 	if (err)
623 		return;
624 
625 	skel = test_tc_link__open();
626 	if (!ASSERT_OK_PTR(skel, "skel_open"))
627 		goto cleanup;
628 
629 	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
630 		  BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
631 
632 	err = test_tc_link__load(skel);
633 	if (!ASSERT_OK(err, "skel_load"))
634 		goto cleanup;
635 
636 	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
637 
638 	assert_mprog_count_ifindex(ifindex, target, 0);
639 
640 	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");
641 	ASSERT_EQ(skel->bss->seen_eth, false, "seen_eth");
642 
643 	link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl);
644 	if (!ASSERT_OK_PTR(link, "link_attach"))
645 		goto cleanup;
646 
647 	skel->links.tc1 = link;
648 
649 	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));
650 
651 	assert_mprog_count_ifindex(ifindex, target, 1);
652 
653 	optq.prog_ids = prog_ids;
654 	optq.link_ids = link_ids;
655 
656 	memset(prog_ids, 0, sizeof(prog_ids));
657 	memset(link_ids, 0, sizeof(link_ids));
658 	optq.count = ARRAY_SIZE(prog_ids);
659 
660 	err = bpf_prog_query_opts(ifindex, target, &optq);
661 	if (!ASSERT_OK(err, "prog_query"))
662 		goto cleanup;
663 
664 	ASSERT_EQ(optq.count, 1, "count");
665 	ASSERT_EQ(optq.revision, 2, "revision");
666 	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");
667 	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");
668 	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
669 	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
670 
671 	tc_skel_reset_all_seen(skel);
672 	ASSERT_EQ(__send_icmp(ping_addr_noneigh), 0, "icmp_pkt");
673 
674 	ASSERT_EQ(skel->bss->seen_tc1, true /* L2: ARP */, "seen_tc1");
675 	ASSERT_EQ(skel->bss->seen_eth, mode == NETKIT_L3, "seen_eth");
676 cleanup:
677 	test_tc_link__destroy(skel);
678 
679 	assert_mprog_count_ifindex(ifindex, target, 0);
680 	destroy_netkit();
681 }
682 
683 void serial_test_tc_netkit_neigh_links(void)
684 {
685 	serial_test_tc_netkit_neigh_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
686 	serial_test_tc_netkit_neigh_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
687 }
688