xref: /linux/tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c (revision 27eddbf3449026a73d6ed52d55b192bfcf526a03)
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