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
create_netkit(int mode,int policy,int peer_policy,int * ifindex,bool same_netns)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
move_netkit(void)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
destroy_netkit(void)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
__send_icmp(__u32 dest)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
send_icmp(void)158 static int send_icmp(void)
159 {
160 return __send_icmp(ping_addr_neigh);
161 }
162
serial_test_tc_netkit_basic(void)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
serial_test_tc_netkit_multi_links_target(int mode,int target)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
serial_test_tc_netkit_multi_links(void)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
serial_test_tc_netkit_multi_opts_target(int mode,int target)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
serial_test_tc_netkit_multi_opts(void)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
serial_test_tc_netkit_device(void)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
serial_test_tc_netkit_neigh_links_target(int mode,int target)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
serial_test_tc_netkit_neigh_links(void)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
serial_test_tc_netkit_pkt_type_mode(int mode)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
serial_test_tc_netkit_pkt_type(void)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