File Index
Files and directories
Sign in
FILE

tc_netkit.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/tc_netkit.c C
  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
 27struct icmphdr {
 28	__u8		type;
 29	__u8		code;
 30	__sum16		checksum;
 31	struct {
 32		__be16	id;
 33		__be16	sequence;
 34	} echo;
 35};
 36
 37struct iplink_req {
 38	struct nlmsghdr  n;
 39	struct ifinfomsg i;
 40	char             buf[1024];
 41};
 42
 43static 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
116static 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
126static 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
133static 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;
176out:
177	close(sock);
178	return ret;
179}
180
181static int send_icmp(void)
182{
183	return __send_icmp(ping_addr_neigh);
184}
185
186void 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");
293cleanup:
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
301static 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");
415cleanup:
416	test_tc_link__destroy(skel);
417
418	assert_mprog_count_ifindex(ifindex, target, 0);
419	destroy_netkit();
420}
421
422void 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
430static 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
522cleanup_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);
526cleanup_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);
530cleanup:
531	test_tc_link__destroy(skel);
532
533	assert_mprog_count_ifindex(ifindex, target, 0);
534	destroy_netkit();
535}
536
537void 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
545void 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);
649cleanup:
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
657static 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");
724cleanup:
725	test_tc_link__destroy(skel);
726
727	assert_mprog_count_ifindex(ifindex, target, 0);
728	destroy_netkit();
729}
730
731void 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
737static 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");
799cleanup:
800	test_tc_link__destroy(skel);
801
802	assert_mprog_count_ifindex(ifindex,  BPF_NETKIT_PRIMARY, 0);
803	destroy_netkit();
804}
805
806void 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
812static 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");
858cleanup:
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
866void 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}
~/ Read-only file preview.