1 // SPDX-License-Identifier: GPL-2.0
2
3 #define _GNU_SOURCE
4 #include <stdbool.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <bpf/bpf.h>
8 #include <linux/bpf.h>
9 #include <bpf/libbpf.h>
10 #include <arpa/inet.h>
11 #include <asm/byteorder.h>
12 #include <netinet/udp.h>
13 #include <poll.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <sys/time.h>
18 #include <unistd.h>
19 #include "test_progs.h"
20 #include "network_helpers.h"
21 #include "bpf_util.h"
22 #include "bpf_flow.skel.h"
23
24 #define CFG_PORT_INNER 8000
25 #define CFG_PORT_GUE 6080
26 #define SUBTEST_NAME_MAX_LEN 32
27 #define TEST_NAME_MAX_LEN (32 + SUBTEST_NAME_MAX_LEN)
28 #define MAX_SOURCE_PORTS 3
29 #define TEST_PACKETS_COUNT 10
30 #define TEST_PACKET_LEN 100
31 #define TEST_PACKET_PATTERN 'a'
32 #define TEST_IPV4 "192.168.0.1/32"
33 #define TEST_IPV6 "100::a/128"
34 #define TEST_TUNNEL_REMOTE "127.0.0.2"
35 #define TEST_TUNNEL_LOCAL "127.0.0.1"
36
37 #define INIT_ADDR4(addr4, port) \
38 { \
39 .sin_family = AF_INET, \
40 .sin_port = __constant_htons(port), \
41 .sin_addr.s_addr = __constant_htonl(addr4), \
42 }
43
44 #define INIT_ADDR6(addr6, port) \
45 { \
46 .sin6_family = AF_INET6, \
47 .sin6_port = __constant_htons(port), \
48 .sin6_addr = addr6, \
49 }
50 #define TEST_IN4_SRC_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK + 2, 0)
51 #define TEST_IN4_DST_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK, CFG_PORT_INNER)
52 #define TEST_OUT4_SRC_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK + 1, 0)
53 #define TEST_OUT4_DST_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK, 0)
54
55 #define TEST_IN6_SRC_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0)
56 #define TEST_IN6_DST_ADDR_DEFAULT \
57 INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER)
58 #define TEST_OUT6_SRC_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0)
59 #define TEST_OUT6_DST_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0)
60
61 #define TEST_IN4_SRC_ADDR_DISSECT_CONTINUE INIT_ADDR4(INADDR_LOOPBACK + 126, 0)
62 #define TEST_IN4_SRC_ADDR_IPIP INIT_ADDR4((in_addr_t)0x01010101, 0)
63 #define TEST_IN4_DST_ADDR_IPIP INIT_ADDR4((in_addr_t)0xC0A80001, CFG_PORT_INNER)
64
65 struct grehdr {
66 uint16_t unused;
67 uint16_t protocol;
68 } __packed;
69
70 struct guehdr {
71 union {
72 struct {
73 #if defined(__LITTLE_ENDIAN_BITFIELD)
74 __u8 hlen : 5, control : 1, version : 2;
75 #elif defined(__BIG_ENDIAN_BITFIELD)
76 __u8 version : 2, control : 1, hlen : 5;
77 #else
78 #error "Please fix <asm/byteorder.h>"
79 #endif
80 __u8 proto_ctype;
81 __be16 flags;
82 };
83 __be32 word;
84 };
85 };
86
87 static char buf[ETH_DATA_LEN];
88
89 struct test_configuration {
90 char name[SUBTEST_NAME_MAX_LEN];
91 int (*test_setup)(void);
92 void (*test_teardown)(void);
93 int source_ports[MAX_SOURCE_PORTS];
94 int cfg_l3_inner;
95 struct sockaddr_in in_saddr4;
96 struct sockaddr_in in_daddr4;
97 struct sockaddr_in6 in_saddr6;
98 struct sockaddr_in6 in_daddr6;
99 int cfg_l3_outer;
100 struct sockaddr_in out_saddr4;
101 struct sockaddr_in out_daddr4;
102 struct sockaddr_in6 out_saddr6;
103 struct sockaddr_in6 out_daddr6;
104 int cfg_encap_proto;
105 uint8_t cfg_dsfield_inner;
106 uint8_t cfg_dsfield_outer;
107 int cfg_l3_extra;
108 struct sockaddr_in extra_saddr4;
109 struct sockaddr_in extra_daddr4;
110 struct sockaddr_in6 extra_saddr6;
111 struct sockaddr_in6 extra_daddr6;
112 };
113
util_gettime(void)114 static unsigned long util_gettime(void)
115 {
116 struct timeval tv;
117
118 gettimeofday(&tv, NULL);
119 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
120 }
121
build_ipv4_header(void * header,uint8_t proto,uint32_t src,uint32_t dst,int payload_len,uint8_t tos)122 static void build_ipv4_header(void *header, uint8_t proto, uint32_t src,
123 uint32_t dst, int payload_len, uint8_t tos)
124 {
125 struct iphdr *iph = header;
126
127 iph->ihl = 5;
128 iph->version = 4;
129 iph->tos = tos;
130 iph->ttl = 8;
131 iph->tot_len = htons(sizeof(*iph) + payload_len);
132 iph->id = htons(1337);
133 iph->protocol = proto;
134 iph->saddr = src;
135 iph->daddr = dst;
136 iph->check = build_ip_csum((void *)iph);
137 }
138
ipv6_set_dsfield(struct ipv6hdr * ip6h,uint8_t dsfield)139 static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield)
140 {
141 uint16_t val, *ptr = (uint16_t *)ip6h;
142
143 val = ntohs(*ptr);
144 val &= 0xF00F;
145 val |= ((uint16_t)dsfield) << 4;
146 *ptr = htons(val);
147 }
148
build_ipv6_header(void * header,uint8_t proto,const struct sockaddr_in6 * src,const struct sockaddr_in6 * dst,int payload_len,uint8_t dsfield)149 static void build_ipv6_header(void *header, uint8_t proto,
150 const struct sockaddr_in6 *src,
151 const struct sockaddr_in6 *dst, int payload_len,
152 uint8_t dsfield)
153 {
154 struct ipv6hdr *ip6h = header;
155
156 ip6h->version = 6;
157 ip6h->payload_len = htons(payload_len);
158 ip6h->nexthdr = proto;
159 ip6h->hop_limit = 8;
160 ipv6_set_dsfield(ip6h, dsfield);
161
162 memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr));
163 memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr));
164 }
165
build_udp_header(void * header,int payload_len,uint16_t sport,uint16_t dport,int family)166 static void build_udp_header(void *header, int payload_len, uint16_t sport,
167 uint16_t dport, int family)
168 {
169 struct udphdr *udph = header;
170 int len = sizeof(*udph) + payload_len;
171
172 udph->source = htons(sport);
173 udph->dest = htons(dport);
174 udph->len = htons(len);
175 udph->check = 0;
176 if (family == AF_INET)
177 udph->check = build_udp_v4_csum(header - sizeof(struct iphdr),
178 udph);
179 else
180 udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr),
181 udph);
182 }
183
build_gue_header(void * header,uint8_t proto)184 static void build_gue_header(void *header, uint8_t proto)
185 {
186 struct guehdr *gueh = header;
187
188 gueh->proto_ctype = proto;
189 }
190
build_gre_header(void * header,uint16_t proto)191 static void build_gre_header(void *header, uint16_t proto)
192 {
193 struct grehdr *greh = header;
194
195 greh->protocol = htons(proto);
196 }
197
l3_length(int family)198 static int l3_length(int family)
199 {
200 if (family == AF_INET)
201 return sizeof(struct iphdr);
202 else
203 return sizeof(struct ipv6hdr);
204 }
205
build_packet(const struct test_configuration * test,uint16_t sport)206 static int build_packet(const struct test_configuration *test, uint16_t sport)
207 {
208 int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0;
209 int el3_len = 0, packet_len;
210
211 memset(buf, 0, ETH_DATA_LEN);
212
213 if (test->cfg_l3_extra)
214 el3_len = l3_length(test->cfg_l3_extra);
215
216 /* calculate header offsets */
217 if (test->cfg_encap_proto) {
218 ol3_len = l3_length(test->cfg_l3_outer);
219
220 if (test->cfg_encap_proto == IPPROTO_GRE)
221 ol4_len = sizeof(struct grehdr);
222 else if (test->cfg_encap_proto == IPPROTO_UDP)
223 ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr);
224 }
225
226 il3_len = l3_length(test->cfg_l3_inner);
227 il4_len = sizeof(struct udphdr);
228
229 packet_len = el3_len + ol3_len + ol4_len + il3_len + il4_len +
230 TEST_PACKET_LEN;
231 if (!ASSERT_LE(packet_len, sizeof(buf), "check packet size"))
232 return -1;
233
234 /*
235 * Fill packet from inside out, to calculate correct checksums.
236 * But create ip before udp headers, as udp uses ip for pseudo-sum.
237 */
238 memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len,
239 TEST_PACKET_PATTERN, TEST_PACKET_LEN);
240
241 /* add zero byte for udp csum padding */
242 buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + TEST_PACKET_LEN] =
243 0;
244
245 switch (test->cfg_l3_inner) {
246 case PF_INET:
247 build_ipv4_header(buf + el3_len + ol3_len + ol4_len,
248 IPPROTO_UDP, test->in_saddr4.sin_addr.s_addr,
249 test->in_daddr4.sin_addr.s_addr,
250 il4_len + TEST_PACKET_LEN,
251 test->cfg_dsfield_inner);
252 break;
253 case PF_INET6:
254 build_ipv6_header(buf + el3_len + ol3_len + ol4_len,
255 IPPROTO_UDP, &test->in_saddr6,
256 &test->in_daddr6, il4_len + TEST_PACKET_LEN,
257 test->cfg_dsfield_inner);
258 break;
259 }
260
261 build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len,
262 TEST_PACKET_LEN, sport, CFG_PORT_INNER,
263 test->cfg_l3_inner);
264
265 if (!test->cfg_encap_proto)
266 return il3_len + il4_len + TEST_PACKET_LEN;
267
268 switch (test->cfg_l3_outer) {
269 case PF_INET:
270 build_ipv4_header(buf + el3_len, test->cfg_encap_proto,
271 test->out_saddr4.sin_addr.s_addr,
272 test->out_daddr4.sin_addr.s_addr,
273 ol4_len + il3_len + il4_len + TEST_PACKET_LEN,
274 test->cfg_dsfield_outer);
275 break;
276 case PF_INET6:
277 build_ipv6_header(buf + el3_len, test->cfg_encap_proto,
278 &test->out_saddr6, &test->out_daddr6,
279 ol4_len + il3_len + il4_len + TEST_PACKET_LEN,
280 test->cfg_dsfield_outer);
281 break;
282 }
283
284 switch (test->cfg_encap_proto) {
285 case IPPROTO_UDP:
286 build_gue_header(buf + el3_len + ol3_len + ol4_len -
287 sizeof(struct guehdr),
288 test->cfg_l3_inner == PF_INET ? IPPROTO_IPIP :
289 IPPROTO_IPV6);
290 build_udp_header(buf + el3_len + ol3_len,
291 sizeof(struct guehdr) + il3_len + il4_len +
292 TEST_PACKET_LEN,
293 sport, CFG_PORT_GUE, test->cfg_l3_outer);
294 break;
295 case IPPROTO_GRE:
296 build_gre_header(buf + el3_len + ol3_len,
297 test->cfg_l3_inner == PF_INET ? ETH_P_IP :
298 ETH_P_IPV6);
299 break;
300 }
301
302 switch (test->cfg_l3_extra) {
303 case PF_INET:
304 build_ipv4_header(buf,
305 test->cfg_l3_outer == PF_INET ? IPPROTO_IPIP :
306 IPPROTO_IPV6,
307 test->extra_saddr4.sin_addr.s_addr,
308 test->extra_daddr4.sin_addr.s_addr,
309 ol3_len + ol4_len + il3_len + il4_len +
310 TEST_PACKET_LEN,
311 0);
312 break;
313 case PF_INET6:
314 build_ipv6_header(buf,
315 test->cfg_l3_outer == PF_INET ? IPPROTO_IPIP :
316 IPPROTO_IPV6,
317 &test->extra_saddr6, &test->extra_daddr6,
318 ol3_len + ol4_len + il3_len + il4_len +
319 TEST_PACKET_LEN,
320 0);
321 break;
322 }
323
324 return el3_len + ol3_len + ol4_len + il3_len + il4_len +
325 TEST_PACKET_LEN;
326 }
327
328 /* sender transmits encapsulated over RAW or unencap'd over UDP */
setup_tx(const struct test_configuration * test)329 static int setup_tx(const struct test_configuration *test)
330 {
331 int family, fd, ret;
332
333 if (test->cfg_l3_extra)
334 family = test->cfg_l3_extra;
335 else if (test->cfg_l3_outer)
336 family = test->cfg_l3_outer;
337 else
338 family = test->cfg_l3_inner;
339
340 fd = socket(family, SOCK_RAW, IPPROTO_RAW);
341 if (!ASSERT_OK_FD(fd, "setup tx socket"))
342 return fd;
343
344 if (test->cfg_l3_extra) {
345 if (test->cfg_l3_extra == PF_INET)
346 ret = connect(fd, (void *)&test->extra_daddr4,
347 sizeof(test->extra_daddr4));
348 else
349 ret = connect(fd, (void *)&test->extra_daddr6,
350 sizeof(test->extra_daddr6));
351 if (!ASSERT_OK(ret, "connect")) {
352 close(fd);
353 return ret;
354 }
355 } else if (test->cfg_l3_outer) {
356 /* connect to destination if not encapsulated */
357 if (test->cfg_l3_outer == PF_INET)
358 ret = connect(fd, (void *)&test->out_daddr4,
359 sizeof(test->out_daddr4));
360 else
361 ret = connect(fd, (void *)&test->out_daddr6,
362 sizeof(test->out_daddr6));
363 if (!ASSERT_OK(ret, "connect")) {
364 close(fd);
365 return ret;
366 }
367 } else {
368 /* otherwise using loopback */
369 if (test->cfg_l3_inner == PF_INET)
370 ret = connect(fd, (void *)&test->in_daddr4,
371 sizeof(test->in_daddr4));
372 else
373 ret = connect(fd, (void *)&test->in_daddr6,
374 sizeof(test->in_daddr6));
375 if (!ASSERT_OK(ret, "connect")) {
376 close(fd);
377 return ret;
378 }
379 }
380
381 return fd;
382 }
383
384 /* receiver reads unencapsulated UDP */
setup_rx(const struct test_configuration * test)385 static int setup_rx(const struct test_configuration *test)
386 {
387 int fd, ret;
388
389 fd = socket(test->cfg_l3_inner, SOCK_DGRAM, 0);
390 if (!ASSERT_OK_FD(fd, "socket rx"))
391 return fd;
392
393 if (test->cfg_l3_inner == PF_INET)
394 ret = bind(fd, (void *)&test->in_daddr4,
395 sizeof(test->in_daddr4));
396 else
397 ret = bind(fd, (void *)&test->in_daddr6,
398 sizeof(test->in_daddr6));
399 if (!ASSERT_OK(ret, "bind rx")) {
400 close(fd);
401 return ret;
402 }
403
404 return fd;
405 }
406
do_tx(int fd,const char * pkt,int len)407 static int do_tx(int fd, const char *pkt, int len)
408 {
409 int ret;
410
411 ret = write(fd, pkt, len);
412 return ret != len;
413 }
414
do_poll(int fd,short events,int timeout)415 static int do_poll(int fd, short events, int timeout)
416 {
417 struct pollfd pfd;
418 int ret;
419
420 pfd.fd = fd;
421 pfd.events = events;
422
423 ret = poll(&pfd, 1, timeout);
424 return ret;
425 }
426
do_rx(int fd)427 static int do_rx(int fd)
428 {
429 char rbuf;
430 int ret, num = 0;
431
432 while (1) {
433 ret = recv(fd, &rbuf, 1, MSG_DONTWAIT);
434 if (ret == -1 && errno == EAGAIN)
435 break;
436 if (ret < 0)
437 return -1;
438 if (!ASSERT_EQ(rbuf, TEST_PACKET_PATTERN, "check pkt pattern"))
439 return -1;
440 num++;
441 }
442
443 return num;
444 }
445
run_test(const struct test_configuration * test,int source_port_index)446 static int run_test(const struct test_configuration *test,
447 int source_port_index)
448 {
449 int fdt = -1, fdr = -1, len, tx = 0, rx = 0, err;
450 unsigned long tstop, tcur;
451
452 fdr = setup_rx(test);
453 fdt = setup_tx(test);
454 if (!ASSERT_OK_FD(fdr, "setup rx") || !ASSERT_OK_FD(fdt, "setup tx")) {
455 err = -1;
456 goto out_close_sockets;
457 }
458
459 len = build_packet(test,
460 (uint16_t)test->source_ports[source_port_index]);
461 if (!ASSERT_GT(len, 0, "build test packet"))
462 return -1;
463
464 tcur = util_gettime();
465 tstop = tcur;
466
467 while (tx < TEST_PACKETS_COUNT) {
468 if (!ASSERT_OK(do_tx(fdt, buf, len), "do_tx"))
469 break;
470 tx++;
471 err = do_rx(fdr);
472 if (!ASSERT_GE(err, 0, "do_rx"))
473 break;
474 rx += err;
475 }
476
477 /* read straggler packets, if any */
478 if (rx < tx) {
479 tstop = util_gettime() + 100;
480 while (rx < tx) {
481 tcur = util_gettime();
482 if (tcur >= tstop)
483 break;
484
485 err = do_poll(fdr, POLLIN, tstop - tcur);
486 if (err < 0)
487 break;
488 err = do_rx(fdr);
489 if (err >= 0)
490 rx += err;
491 }
492 }
493
494 out_close_sockets:
495 close(fdt);
496 close(fdr);
497 return rx;
498 }
499
attach_and_configure_program(struct bpf_flow * skel)500 static int attach_and_configure_program(struct bpf_flow *skel)
501 {
502 struct bpf_map *prog_array = skel->maps.jmp_table;
503 int main_prog_fd, sub_prog_fd, map_fd, i, err;
504 struct bpf_program *prog;
505 char prog_name[32];
506
507 main_prog_fd = bpf_program__fd(skel->progs._dissect);
508 if (main_prog_fd < 0)
509 return main_prog_fd;
510
511 err = bpf_prog_attach(main_prog_fd, 0, BPF_FLOW_DISSECTOR, 0);
512 if (err)
513 return err;
514
515 map_fd = bpf_map__fd(prog_array);
516 if (map_fd < 0)
517 return map_fd;
518
519 for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
520 snprintf(prog_name, sizeof(prog_name), "flow_dissector_%d", i);
521
522 prog = bpf_object__find_program_by_name(skel->obj, prog_name);
523 if (!prog)
524 return -1;
525
526 sub_prog_fd = bpf_program__fd(prog);
527 if (sub_prog_fd < 0)
528 return -1;
529
530 err = bpf_map_update_elem(map_fd, &i, &sub_prog_fd, BPF_ANY);
531 if (err)
532 return -1;
533 }
534
535 return main_prog_fd;
536 }
537
detach_program(struct bpf_flow * skel,int prog_fd)538 static void detach_program(struct bpf_flow *skel, int prog_fd)
539 {
540 bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR);
541 }
542
set_port_drop(int pf,bool multi_port)543 static int set_port_drop(int pf, bool multi_port)
544 {
545 char dst_port[16];
546
547 snprintf(dst_port, sizeof(dst_port), "%d", CFG_PORT_INNER);
548
549 SYS(fail, "tc qdisc add dev lo ingress");
550 SYS(fail_delete_qdisc, "tc filter add %s %s %s %s %s %s %s %s %s %s %s %s",
551 "dev lo",
552 "parent FFFF:",
553 "protocol", pf == PF_INET6 ? "ipv6" : "ip",
554 "pref 1337",
555 "flower",
556 "ip_proto udp",
557 "src_port", multi_port ? "8-10" : "9",
558 "dst_port", dst_port,
559 "action drop");
560 return 0;
561
562 fail_delete_qdisc:
563 SYS_NOFAIL("tc qdisc del dev lo ingress");
564 fail:
565 return 1;
566 }
567
remove_filter(void)568 static void remove_filter(void)
569 {
570 SYS_NOFAIL("tc filter del dev lo ingress");
571 SYS_NOFAIL("tc qdisc del dev lo ingress");
572 }
573
ipv4_setup(void)574 static int ipv4_setup(void)
575 {
576 return set_port_drop(PF_INET, false);
577 }
578
ipv6_setup(void)579 static int ipv6_setup(void)
580 {
581 return set_port_drop(PF_INET6, false);
582 }
583
port_range_setup(void)584 static int port_range_setup(void)
585 {
586 return set_port_drop(PF_INET, true);
587 }
588
set_addresses(void)589 static int set_addresses(void)
590 {
591 SYS(out, "ip -4 addr add %s dev lo", TEST_IPV4);
592 SYS(out_remove_ipv4, "ip -6 addr add %s dev lo", TEST_IPV6);
593 return 0;
594 out_remove_ipv4:
595 SYS_NOFAIL("ip -4 addr del %s dev lo", TEST_IPV4);
596 out:
597 return -1;
598 }
599
unset_addresses(void)600 static void unset_addresses(void)
601 {
602 SYS_NOFAIL("ip -4 addr del %s dev lo", TEST_IPV4);
603 SYS_NOFAIL("ip -6 addr del %s dev lo", TEST_IPV6);
604 }
605
ipip_setup(void)606 static int ipip_setup(void)
607 {
608 if (!ASSERT_OK(set_addresses(), "configure addresses"))
609 return -1;
610 if (!ASSERT_OK(set_port_drop(PF_INET, false), "set filter"))
611 goto out_unset_addresses;
612 SYS(out_remove_filter,
613 "ip link add ipip_test type ipip remote %s local %s dev lo",
614 TEST_TUNNEL_REMOTE, TEST_TUNNEL_LOCAL);
615 SYS(out_clean_netif, "ip link set ipip_test up");
616 return 0;
617
618 out_clean_netif:
619 SYS_NOFAIL("ip link del ipip_test");
620 out_remove_filter:
621 remove_filter();
622 out_unset_addresses:
623 unset_addresses();
624 return -1;
625 }
626
ipip_shutdown(void)627 static void ipip_shutdown(void)
628 {
629 SYS_NOFAIL("ip link del ipip_test");
630 remove_filter();
631 unset_addresses();
632 }
633
gre_setup(void)634 static int gre_setup(void)
635 {
636 if (!ASSERT_OK(set_addresses(), "configure addresses"))
637 return -1;
638 if (!ASSERT_OK(set_port_drop(PF_INET, false), "set filter"))
639 goto out_unset_addresses;
640 SYS(out_remove_filter,
641 "ip link add gre_test type gre remote %s local %s dev lo",
642 TEST_TUNNEL_REMOTE, TEST_TUNNEL_LOCAL);
643 SYS(out_clean_netif, "ip link set gre_test up");
644 return 0;
645
646 out_clean_netif:
647 SYS_NOFAIL("ip link del ipip_test");
648 out_remove_filter:
649 remove_filter();
650 out_unset_addresses:
651 unset_addresses();
652 return -1;
653 }
654
gre_shutdown(void)655 static void gre_shutdown(void)
656 {
657 SYS_NOFAIL("ip link del gre_test");
658 remove_filter();
659 unset_addresses();
660 }
661
662 static const struct test_configuration tests_input[] = {
663 {
664 .name = "ipv4",
665 .test_setup = ipv4_setup,
666 .test_teardown = remove_filter,
667 .source_ports = { 8, 9, 10 },
668 .cfg_l3_inner = PF_INET,
669 .in_saddr4 = TEST_IN4_SRC_ADDR_DEFAULT,
670 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT
671 },
672 {
673 .name = "ipv4_continue_dissect",
674 .test_setup = ipv4_setup,
675 .test_teardown = remove_filter,
676 .source_ports = { 8, 9, 10 },
677 .cfg_l3_inner = PF_INET,
678 .in_saddr4 = TEST_IN4_SRC_ADDR_DISSECT_CONTINUE,
679 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT },
680 {
681 .name = "ipip",
682 .test_setup = ipip_setup,
683 .test_teardown = ipip_shutdown,
684 .source_ports = { 8, 9, 10 },
685 .cfg_l3_inner = PF_INET,
686 .in_saddr4 = TEST_IN4_SRC_ADDR_IPIP,
687 .in_daddr4 = TEST_IN4_DST_ADDR_IPIP,
688 .out_saddr4 = TEST_OUT4_SRC_ADDR_DEFAULT,
689 .out_daddr4 = TEST_OUT4_DST_ADDR_DEFAULT,
690 .cfg_l3_outer = PF_INET,
691 .cfg_encap_proto = IPPROTO_IPIP,
692
693 },
694 {
695 .name = "gre",
696 .test_setup = gre_setup,
697 .test_teardown = gre_shutdown,
698 .source_ports = { 8, 9, 10 },
699 .cfg_l3_inner = PF_INET,
700 .in_saddr4 = TEST_IN4_SRC_ADDR_IPIP,
701 .in_daddr4 = TEST_IN4_DST_ADDR_IPIP,
702 .out_saddr4 = TEST_OUT4_SRC_ADDR_DEFAULT,
703 .out_daddr4 = TEST_OUT4_DST_ADDR_DEFAULT,
704 .cfg_l3_outer = PF_INET,
705 .cfg_encap_proto = IPPROTO_GRE,
706 },
707 {
708 .name = "port_range",
709 .test_setup = port_range_setup,
710 .test_teardown = remove_filter,
711 .source_ports = { 7, 9, 11 },
712 .cfg_l3_inner = PF_INET,
713 .in_saddr4 = TEST_IN4_SRC_ADDR_DEFAULT,
714 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT },
715 {
716 .name = "ipv6",
717 .test_setup = ipv6_setup,
718 .test_teardown = remove_filter,
719 .source_ports = { 8, 9, 10 },
720 .cfg_l3_inner = PF_INET6,
721 .in_saddr6 = TEST_IN6_SRC_ADDR_DEFAULT,
722 .in_daddr6 = TEST_IN6_DST_ADDR_DEFAULT
723 },
724 };
725
726 struct test_ctx {
727 struct bpf_flow *skel;
728 struct netns_obj *ns;
729 int prog_fd;
730 };
731
test_global_init(struct test_ctx * ctx)732 static int test_global_init(struct test_ctx *ctx)
733 {
734 int err;
735
736 ctx->skel = bpf_flow__open_and_load();
737 if (!ASSERT_OK_PTR(ctx->skel, "open and load flow_dissector"))
738 return -1;
739
740 ctx->ns = netns_new("flow_dissector_classification", true);
741 if (!ASSERT_OK_PTR(ctx->ns, "switch ns"))
742 goto out_destroy_skel;
743
744 err = write_sysctl("/proc/sys/net/ipv4/conf/default/rp_filter", "0");
745 err |= write_sysctl("/proc/sys/net/ipv4/conf/all/rp_filter", "0");
746 err |= write_sysctl("/proc/sys/net/ipv4/conf/lo/rp_filter", "0");
747 if (!ASSERT_OK(err, "configure net tunables"))
748 goto out_clean_ns;
749
750 ctx->prog_fd = attach_and_configure_program(ctx->skel);
751 if (!ASSERT_OK_FD(ctx->prog_fd, "attach and configure program"))
752 goto out_clean_ns;
753 return 0;
754 out_clean_ns:
755 netns_free(ctx->ns);
756 out_destroy_skel:
757 bpf_flow__destroy(ctx->skel);
758 return -1;
759 }
760
test_global_shutdown(struct test_ctx * ctx)761 static void test_global_shutdown(struct test_ctx *ctx)
762 {
763 detach_program(ctx->skel, ctx->prog_fd);
764 netns_free(ctx->ns);
765 bpf_flow__destroy(ctx->skel);
766 }
767
test_flow_dissector_classification(void)768 void test_flow_dissector_classification(void)
769 {
770 struct test_ctx ctx;
771 const struct test_configuration *test;
772 int i;
773
774 if (test_global_init(&ctx))
775 return;
776
777 for (i = 0; i < ARRAY_SIZE(tests_input); i++) {
778 if (!test__start_subtest(tests_input[i].name))
779 continue;
780 test = &tests_input[i];
781 /* All tests are expected to have one rx-ok port first,
782 * then a non-working rx port, and finally a rx-ok port
783 */
784 if (test->test_setup &&
785 !ASSERT_OK(test->test_setup(), "init filter"))
786 continue;
787
788 ASSERT_EQ(run_test(test, 0), TEST_PACKETS_COUNT,
789 "test first port");
790 ASSERT_EQ(run_test(test, 1), 0, "test second port");
791 ASSERT_EQ(run_test(test, 2), TEST_PACKETS_COUNT,
792 "test third port");
793 if (test->test_teardown)
794 test->test_teardown();
795 }
796 test_global_shutdown(&ctx);
797 }
798