mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	selftests/bpf: run flow dissector tests in skb-less mode
Export last_dissection map from flow dissector and use a known place in tun driver to trigger BPF flow dissection. Signed-off-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
		
							parent
							
								
									c9cb2c1e11
								
							
						
					
					
						commit
						0905beec9f
					
				
					 4 changed files with 165 additions and 34 deletions
				
			
		| 
						 | 
					@ -26,7 +26,7 @@ static void load_and_attach_program(void)
 | 
				
			||||||
	struct bpf_object *obj;
 | 
						struct bpf_object *obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = bpf_flow_load(&obj, cfg_path_name, cfg_section_name,
 | 
						ret = bpf_flow_load(&obj, cfg_path_name, cfg_section_name,
 | 
				
			||||||
			    cfg_map_name, &prog_fd);
 | 
								    cfg_map_name, NULL, &prog_fd, NULL);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		error(1, 0, "bpf_flow_load %s", cfg_path_name);
 | 
							error(1, 0, "bpf_flow_load %s", cfg_path_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,10 +9,12 @@ static inline int bpf_flow_load(struct bpf_object **obj,
 | 
				
			||||||
				const char *path,
 | 
									const char *path,
 | 
				
			||||||
				const char *section_name,
 | 
									const char *section_name,
 | 
				
			||||||
				const char *map_name,
 | 
									const char *map_name,
 | 
				
			||||||
				int *prog_fd)
 | 
									const char *keys_map_name,
 | 
				
			||||||
 | 
									int *prog_fd,
 | 
				
			||||||
 | 
									int *keys_fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bpf_program *prog, *main_prog;
 | 
						struct bpf_program *prog, *main_prog;
 | 
				
			||||||
	struct bpf_map *prog_array;
 | 
						struct bpf_map *prog_array, *keys;
 | 
				
			||||||
	int prog_array_fd;
 | 
						int prog_array_fd;
 | 
				
			||||||
	int ret, fd, i;
 | 
						int ret, fd, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +39,16 @@ static inline int bpf_flow_load(struct bpf_object **obj,
 | 
				
			||||||
	if (prog_array_fd < 0)
 | 
						if (prog_array_fd < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (keys_map_name && keys_fd) {
 | 
				
			||||||
 | 
							keys = bpf_object__find_map_by_name(*obj, keys_map_name);
 | 
				
			||||||
 | 
							if (!keys)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*keys_fd = bpf_map__fd(keys);
 | 
				
			||||||
 | 
							if (*keys_fd < 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i = 0;
 | 
						i = 0;
 | 
				
			||||||
	bpf_object__for_each_program(prog, *obj) {
 | 
						bpf_object__for_each_program(prog, *obj) {
 | 
				
			||||||
		fd = bpf_program__fd(prog);
 | 
							fd = bpf_program__fd(prog);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,8 @@
 | 
				
			||||||
// SPDX-License-Identifier: GPL-2.0
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
#include <test_progs.h>
 | 
					#include <test_progs.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <linux/if.h>
 | 
				
			||||||
 | 
					#include <linux/if_tun.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CHECK_FLOW_KEYS(desc, got, expected)				\
 | 
					#define CHECK_FLOW_KEYS(desc, got, expected)				\
 | 
				
			||||||
	CHECK_ATTR(memcmp(&got, &expected, sizeof(got)) != 0,		\
 | 
						CHECK_ATTR(memcmp(&got, &expected, sizeof(got)) != 0,		\
 | 
				
			||||||
| 
						 | 
					@ -140,13 +143,73 @@ struct test tests[] = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int create_tap(const char *ifname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ifreq ifr = {
 | 
				
			||||||
 | 
							.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int fd, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd = open("/dev/net/tun", O_RDWR);
 | 
				
			||||||
 | 
						if (fd < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ioctl(fd, TUNSETIFF, &ifr);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tx_tap(int fd, void *pkt, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iovec iov[] = {
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								.iov_len = len,
 | 
				
			||||||
 | 
								.iov_base = pkt,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						return writev(fd, iov, ARRAY_SIZE(iov));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ifup(const char *ifname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ifreq ifr = {};
 | 
				
			||||||
 | 
						int sk, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sk = socket(PF_INET, SOCK_DGRAM, 0);
 | 
				
			||||||
 | 
						if (sk < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ioctl(sk, SIOCGIFFLAGS, &ifr);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							close(sk);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifr.ifr_flags |= IFF_UP;
 | 
				
			||||||
 | 
						ret = ioctl(sk, SIOCSIFFLAGS, &ifr);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							close(sk);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						close(sk);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_flow_dissector(void)
 | 
					void test_flow_dissector(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int i, err, prog_fd, keys_fd = -1, tap_fd;
 | 
				
			||||||
	struct bpf_object *obj;
 | 
						struct bpf_object *obj;
 | 
				
			||||||
	int i, err, prog_fd;
 | 
						__u32 duration = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector",
 | 
						err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector",
 | 
				
			||||||
			    "jmp_table", &prog_fd);
 | 
								    "jmp_table", "last_dissection", &prog_fd, &keys_fd);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		error_cnt++;
 | 
							error_cnt++;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -171,5 +234,40 @@ void test_flow_dissector(void)
 | 
				
			||||||
		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
 | 
							CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Do the same tests but for skb-less flow dissector.
 | 
				
			||||||
 | 
						 * We use a known path in the net/tun driver that calls
 | 
				
			||||||
 | 
						 * eth_get_headlen and we manually export bpf_flow_keys
 | 
				
			||||||
 | 
						 * via BPF map in this case.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Note, that since eth_get_headlen operates on a L2 level,
 | 
				
			||||||
 | 
						 * we adjust exported nhoff/thoff by ETH_HLEN.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0);
 | 
				
			||||||
 | 
						CHECK(err, "bpf_prog_attach", "err %d errno %d", err, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tap_fd = create_tap("tap0");
 | 
				
			||||||
 | 
						CHECK(tap_fd < 0, "create_tap", "tap_fd %d errno %d", tap_fd, errno);
 | 
				
			||||||
 | 
						err = ifup("tap0");
 | 
				
			||||||
 | 
						CHECK(err, "ifup", "err %d errno %d", err, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(tests); i++) {
 | 
				
			||||||
 | 
							struct bpf_flow_keys flow_keys = {};
 | 
				
			||||||
 | 
							struct bpf_prog_test_run_attr tattr = {};
 | 
				
			||||||
 | 
							__u32 key = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
 | 
				
			||||||
 | 
							CHECK(err < 0, "tx_tap", "err %d errno %d", err, errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
 | 
				
			||||||
 | 
							CHECK_ATTR(err, tests[i].name, "bpf_map_lookup_elem %d\n", err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							flow_keys.nhoff -= ETH_HLEN;
 | 
				
			||||||
 | 
							flow_keys.thoff -= ETH_HLEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CHECK_ATTR(err, tests[i].name, "skb-less err %d\n", err);
 | 
				
			||||||
 | 
							CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bpf_object__close(obj);
 | 
						bpf_object__close(obj);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,25 @@ struct bpf_map_def SEC("maps") jmp_table = {
 | 
				
			||||||
	.max_entries = 8
 | 
						.max_entries = 8
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bpf_map_def SEC("maps") last_dissection = {
 | 
				
			||||||
 | 
						.type = BPF_MAP_TYPE_ARRAY,
 | 
				
			||||||
 | 
						.key_size = sizeof(__u32),
 | 
				
			||||||
 | 
						.value_size = sizeof(struct bpf_flow_keys),
 | 
				
			||||||
 | 
						.max_entries = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
 | 
				
			||||||
 | 
										    int ret)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bpf_flow_keys *val;
 | 
				
			||||||
 | 
						__u32 key = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = bpf_map_lookup_elem(&last_dissection, &key);
 | 
				
			||||||
 | 
						if (val)
 | 
				
			||||||
 | 
							memcpy(val, keys, sizeof(*val));
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
 | 
					static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
 | 
				
			||||||
							 __u16 hdr_size,
 | 
												 __u16 hdr_size,
 | 
				
			||||||
							 void *buffer)
 | 
												 void *buffer)
 | 
				
			||||||
| 
						 | 
					@ -109,10 +128,10 @@ static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* Protocol not supported */
 | 
							/* Protocol not supported */
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return BPF_DROP;
 | 
						return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SEC("flow_dissector")
 | 
					SEC("flow_dissector")
 | 
				
			||||||
| 
						 | 
					@ -139,8 +158,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
 | 
				
			||||||
	case IPPROTO_ICMP:
 | 
						case IPPROTO_ICMP:
 | 
				
			||||||
		icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp);
 | 
							icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp);
 | 
				
			||||||
		if (!icmp)
 | 
							if (!icmp)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
		return BPF_OK;
 | 
							return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
	case IPPROTO_IPIP:
 | 
						case IPPROTO_IPIP:
 | 
				
			||||||
		keys->is_encap = true;
 | 
							keys->is_encap = true;
 | 
				
			||||||
		return parse_eth_proto(skb, bpf_htons(ETH_P_IP));
 | 
							return parse_eth_proto(skb, bpf_htons(ETH_P_IP));
 | 
				
			||||||
| 
						 | 
					@ -150,11 +169,11 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
 | 
				
			||||||
	case IPPROTO_GRE:
 | 
						case IPPROTO_GRE:
 | 
				
			||||||
		gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre);
 | 
							gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre);
 | 
				
			||||||
		if (!gre)
 | 
							if (!gre)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (bpf_htons(gre->flags & GRE_VERSION))
 | 
							if (bpf_htons(gre->flags & GRE_VERSION))
 | 
				
			||||||
			/* Only inspect standard GRE packets with version 0 */
 | 
								/* Only inspect standard GRE packets with version 0 */
 | 
				
			||||||
			return BPF_OK;
 | 
								return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */
 | 
							keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */
 | 
				
			||||||
		if (GRE_IS_CSUM(gre->flags))
 | 
							if (GRE_IS_CSUM(gre->flags))
 | 
				
			||||||
| 
						 | 
					@ -170,7 +189,7 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
 | 
				
			||||||
			eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),
 | 
								eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),
 | 
				
			||||||
							  &_eth);
 | 
												  &_eth);
 | 
				
			||||||
			if (!eth)
 | 
								if (!eth)
 | 
				
			||||||
				return BPF_DROP;
 | 
									return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			keys->thoff += sizeof(*eth);
 | 
								keys->thoff += sizeof(*eth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,31 +200,31 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
 | 
				
			||||||
	case IPPROTO_TCP:
 | 
						case IPPROTO_TCP:
 | 
				
			||||||
		tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp);
 | 
							tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp);
 | 
				
			||||||
		if (!tcp)
 | 
							if (!tcp)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (tcp->doff < 5)
 | 
							if (tcp->doff < 5)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((__u8 *)tcp + (tcp->doff << 2) > data_end)
 | 
							if ((__u8 *)tcp + (tcp->doff << 2) > data_end)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		keys->sport = tcp->source;
 | 
							keys->sport = tcp->source;
 | 
				
			||||||
		keys->dport = tcp->dest;
 | 
							keys->dport = tcp->dest;
 | 
				
			||||||
		return BPF_OK;
 | 
							return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
	case IPPROTO_UDP:
 | 
						case IPPROTO_UDP:
 | 
				
			||||||
	case IPPROTO_UDPLITE:
 | 
						case IPPROTO_UDPLITE:
 | 
				
			||||||
		udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp);
 | 
							udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp);
 | 
				
			||||||
		if (!udp)
 | 
							if (!udp)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		keys->sport = udp->source;
 | 
							keys->sport = udp->source;
 | 
				
			||||||
		keys->dport = udp->dest;
 | 
							keys->dport = udp->dest;
 | 
				
			||||||
		return BPF_OK;
 | 
							return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return BPF_DROP;
 | 
						return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
 | 
					static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
 | 
				
			||||||
| 
						 | 
					@ -225,7 +244,7 @@ static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
 | 
				
			||||||
		return parse_ip_proto(skb, nexthdr);
 | 
							return parse_ip_proto(skb, nexthdr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return BPF_DROP;
 | 
						return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROG(IP)(struct __sk_buff *skb)
 | 
					PROG(IP)(struct __sk_buff *skb)
 | 
				
			||||||
| 
						 | 
					@ -238,11 +257,11 @@ PROG(IP)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph);
 | 
						iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph);
 | 
				
			||||||
	if (!iph)
 | 
						if (!iph)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* IP header cannot be smaller than 20 bytes */
 | 
						/* IP header cannot be smaller than 20 bytes */
 | 
				
			||||||
	if (iph->ihl < 5)
 | 
						if (iph->ihl < 5)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->addr_proto = ETH_P_IP;
 | 
						keys->addr_proto = ETH_P_IP;
 | 
				
			||||||
	keys->ipv4_src = iph->saddr;
 | 
						keys->ipv4_src = iph->saddr;
 | 
				
			||||||
| 
						 | 
					@ -250,7 +269,7 @@ PROG(IP)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->thoff += iph->ihl << 2;
 | 
						keys->thoff += iph->ihl << 2;
 | 
				
			||||||
	if (data + keys->thoff > data_end)
 | 
						if (data + keys->thoff > data_end)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
 | 
						if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
 | 
				
			||||||
		keys->is_frag = true;
 | 
							keys->is_frag = true;
 | 
				
			||||||
| 
						 | 
					@ -264,7 +283,7 @@ PROG(IP)(struct __sk_buff *skb)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (done)
 | 
						if (done)
 | 
				
			||||||
		return BPF_OK;
 | 
							return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return parse_ip_proto(skb, iph->protocol);
 | 
						return parse_ip_proto(skb, iph->protocol);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -276,7 +295,7 @@ PROG(IPV6)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
 | 
						ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
 | 
				
			||||||
	if (!ip6h)
 | 
						if (!ip6h)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->addr_proto = ETH_P_IPV6;
 | 
						keys->addr_proto = ETH_P_IPV6;
 | 
				
			||||||
	memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
 | 
						memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
 | 
				
			||||||
| 
						 | 
					@ -288,11 +307,12 @@ PROG(IPV6)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROG(IPV6OP)(struct __sk_buff *skb)
 | 
					PROG(IPV6OP)(struct __sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct bpf_flow_keys *keys = skb->flow_keys;
 | 
				
			||||||
	struct ipv6_opt_hdr *ip6h, _ip6h;
 | 
						struct ipv6_opt_hdr *ip6h, _ip6h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
 | 
						ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
 | 
				
			||||||
	if (!ip6h)
 | 
						if (!ip6h)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* hlen is in 8-octets and does not include the first 8 bytes
 | 
						/* hlen is in 8-octets and does not include the first 8 bytes
 | 
				
			||||||
	 * of the header
 | 
						 * of the header
 | 
				
			||||||
| 
						 | 
					@ -309,7 +329,7 @@ PROG(IPV6FR)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh);
 | 
						fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh);
 | 
				
			||||||
	if (!fragh)
 | 
						if (!fragh)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->thoff += sizeof(*fragh);
 | 
						keys->thoff += sizeof(*fragh);
 | 
				
			||||||
	keys->is_frag = true;
 | 
						keys->is_frag = true;
 | 
				
			||||||
| 
						 | 
					@ -321,13 +341,14 @@ PROG(IPV6FR)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROG(MPLS)(struct __sk_buff *skb)
 | 
					PROG(MPLS)(struct __sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct bpf_flow_keys *keys = skb->flow_keys;
 | 
				
			||||||
	struct mpls_label *mpls, _mpls;
 | 
						struct mpls_label *mpls, _mpls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls);
 | 
						mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls);
 | 
				
			||||||
	if (!mpls)
 | 
						if (!mpls)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return BPF_OK;
 | 
						return export_flow_keys(keys, BPF_OK);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROG(VLAN)(struct __sk_buff *skb)
 | 
					PROG(VLAN)(struct __sk_buff *skb)
 | 
				
			||||||
| 
						 | 
					@ -339,10 +360,10 @@ PROG(VLAN)(struct __sk_buff *skb)
 | 
				
			||||||
	if (keys->n_proto == bpf_htons(ETH_P_8021AD)) {
 | 
						if (keys->n_proto == bpf_htons(ETH_P_8021AD)) {
 | 
				
			||||||
		vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
 | 
							vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
 | 
				
			||||||
		if (!vlan)
 | 
							if (!vlan)
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q))
 | 
							if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q))
 | 
				
			||||||
			return BPF_DROP;
 | 
								return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		keys->nhoff += sizeof(*vlan);
 | 
							keys->nhoff += sizeof(*vlan);
 | 
				
			||||||
		keys->thoff += sizeof(*vlan);
 | 
							keys->thoff += sizeof(*vlan);
 | 
				
			||||||
| 
						 | 
					@ -350,14 +371,14 @@ PROG(VLAN)(struct __sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
 | 
						vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
 | 
				
			||||||
	if (!vlan)
 | 
						if (!vlan)
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->nhoff += sizeof(*vlan);
 | 
						keys->nhoff += sizeof(*vlan);
 | 
				
			||||||
	keys->thoff += sizeof(*vlan);
 | 
						keys->thoff += sizeof(*vlan);
 | 
				
			||||||
	/* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/
 | 
						/* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/
 | 
				
			||||||
	if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) ||
 | 
						if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) ||
 | 
				
			||||||
	    vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q))
 | 
						    vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q))
 | 
				
			||||||
		return BPF_DROP;
 | 
							return export_flow_keys(keys, BPF_DROP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys->n_proto = vlan->h_vlan_encapsulated_proto;
 | 
						keys->n_proto = vlan->h_vlan_encapsulated_proto;
 | 
				
			||||||
	return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto);
 | 
						return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue