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
create_netkit(int mode,int policy,int peer_policy,int * ifindex,int scrub,int peer_scrub,__u32 flags)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
move_netkit(void)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
destroy_netkit(void)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
__send_icmp(__u32 dest)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
send_icmp(void)181 static int send_icmp(void)
182 {
183 return __send_icmp(ping_addr_neigh);
184 }
185
serial_test_tc_netkit_basic(void)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
serial_test_tc_netkit_multi_links_target(int mode,int target)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
serial_test_tc_netkit_multi_links(void)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
serial_test_tc_netkit_multi_opts_target(int mode,int target)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
serial_test_tc_netkit_multi_opts(void)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
serial_test_tc_netkit_device(void)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
serial_test_tc_netkit_neigh_links_target(int mode,int target)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
serial_test_tc_netkit_neigh_links(void)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
serial_test_tc_netkit_pkt_type_mode(int mode)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
serial_test_tc_netkit_pkt_type(void)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
serial_test_tc_netkit_scrub_type(int scrub,bool room)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
serial_test_tc_netkit_scrub(void)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