1*54ea6079SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
2*54ea6079SMartin KaFai Lau /* Copyright (c) 2021 Facebook */
3*54ea6079SMartin KaFai Lau #include <stdbool.h>
4*54ea6079SMartin KaFai Lau #include <stdint.h>
5*54ea6079SMartin KaFai Lau #include <linux/stddef.h>
6*54ea6079SMartin KaFai Lau #include <linux/if_ether.h>
7*54ea6079SMartin KaFai Lau #include <linux/in.h>
8*54ea6079SMartin KaFai Lau #include <linux/in6.h>
9*54ea6079SMartin KaFai Lau #include <linux/ip.h>
10*54ea6079SMartin KaFai Lau #include <linux/ipv6.h>
11*54ea6079SMartin KaFai Lau #include <linux/tcp.h>
12*54ea6079SMartin KaFai Lau #include <linux/udp.h>
13*54ea6079SMartin KaFai Lau #include <linux/bpf.h>
14*54ea6079SMartin KaFai Lau #include <linux/types.h>
15*54ea6079SMartin KaFai Lau #include <bpf/bpf_endian.h>
16*54ea6079SMartin KaFai Lau #include <bpf/bpf_helpers.h>
17*54ea6079SMartin KaFai Lau 
18*54ea6079SMartin KaFai Lau enum pkt_parse_err {
19*54ea6079SMartin KaFai Lau 	NO_ERR,
20*54ea6079SMartin KaFai Lau 	BAD_IP6_HDR,
21*54ea6079SMartin KaFai Lau 	BAD_IP4GUE_HDR,
22*54ea6079SMartin KaFai Lau 	BAD_IP6GUE_HDR,
23*54ea6079SMartin KaFai Lau };
24*54ea6079SMartin KaFai Lau 
25*54ea6079SMartin KaFai Lau enum pkt_flag {
26*54ea6079SMartin KaFai Lau 	TUNNEL = 0x1,
27*54ea6079SMartin KaFai Lau 	TCP_SYN = 0x2,
28*54ea6079SMartin KaFai Lau 	QUIC_INITIAL_FLAG = 0x4,
29*54ea6079SMartin KaFai Lau 	TCP_ACK = 0x8,
30*54ea6079SMartin KaFai Lau 	TCP_RST = 0x10
31*54ea6079SMartin KaFai Lau };
32*54ea6079SMartin KaFai Lau 
33*54ea6079SMartin KaFai Lau struct v4_lpm_key {
34*54ea6079SMartin KaFai Lau 	__u32 prefixlen;
35*54ea6079SMartin KaFai Lau 	__u32 src;
36*54ea6079SMartin KaFai Lau };
37*54ea6079SMartin KaFai Lau 
38*54ea6079SMartin KaFai Lau struct v4_lpm_val {
39*54ea6079SMartin KaFai Lau 	struct v4_lpm_key key;
40*54ea6079SMartin KaFai Lau 	__u8 val;
41*54ea6079SMartin KaFai Lau };
42*54ea6079SMartin KaFai Lau 
43*54ea6079SMartin KaFai Lau struct {
44*54ea6079SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_HASH);
45*54ea6079SMartin KaFai Lau 	__uint(max_entries, 16);
46*54ea6079SMartin KaFai Lau 	__type(key, struct in6_addr);
47*54ea6079SMartin KaFai Lau 	__type(value, bool);
48*54ea6079SMartin KaFai Lau } v6_addr_map SEC(".maps");
49*54ea6079SMartin KaFai Lau 
50*54ea6079SMartin KaFai Lau struct {
51*54ea6079SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_HASH);
52*54ea6079SMartin KaFai Lau 	__uint(max_entries, 16);
53*54ea6079SMartin KaFai Lau 	__type(key, __u32);
54*54ea6079SMartin KaFai Lau 	__type(value, bool);
55*54ea6079SMartin KaFai Lau } v4_addr_map SEC(".maps");
56*54ea6079SMartin KaFai Lau 
57*54ea6079SMartin KaFai Lau struct {
58*54ea6079SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_LPM_TRIE);
59*54ea6079SMartin KaFai Lau 	__uint(max_entries, 16);
60*54ea6079SMartin KaFai Lau 	__uint(key_size, sizeof(struct v4_lpm_key));
61*54ea6079SMartin KaFai Lau 	__uint(value_size, sizeof(struct v4_lpm_val));
62*54ea6079SMartin KaFai Lau 	__uint(map_flags, BPF_F_NO_PREALLOC);
63*54ea6079SMartin KaFai Lau } v4_lpm_val_map SEC(".maps");
64*54ea6079SMartin KaFai Lau 
65*54ea6079SMartin KaFai Lau struct {
66*54ea6079SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_ARRAY);
67*54ea6079SMartin KaFai Lau 	__uint(max_entries, 16);
68*54ea6079SMartin KaFai Lau 	__type(key, int);
69*54ea6079SMartin KaFai Lau 	__type(value, __u8);
70*54ea6079SMartin KaFai Lau } tcp_port_map SEC(".maps");
71*54ea6079SMartin KaFai Lau 
72*54ea6079SMartin KaFai Lau struct {
73*54ea6079SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_ARRAY);
74*54ea6079SMartin KaFai Lau 	__uint(max_entries, 16);
75*54ea6079SMartin KaFai Lau 	__type(key, int);
76*54ea6079SMartin KaFai Lau 	__type(value, __u16);
77*54ea6079SMartin KaFai Lau } udp_port_map SEC(".maps");
78*54ea6079SMartin KaFai Lau 
79*54ea6079SMartin KaFai Lau enum ip_type { V4 = 1, V6 = 2 };
80*54ea6079SMartin KaFai Lau 
81*54ea6079SMartin KaFai Lau struct fw_match_info {
82*54ea6079SMartin KaFai Lau 	__u8 v4_src_ip_match;
83*54ea6079SMartin KaFai Lau 	__u8 v6_src_ip_match;
84*54ea6079SMartin KaFai Lau 	__u8 v4_src_prefix_match;
85*54ea6079SMartin KaFai Lau 	__u8 v4_dst_prefix_match;
86*54ea6079SMartin KaFai Lau 	__u8 tcp_dp_match;
87*54ea6079SMartin KaFai Lau 	__u16 udp_sp_match;
88*54ea6079SMartin KaFai Lau 	__u16 udp_dp_match;
89*54ea6079SMartin KaFai Lau 	bool is_tcp;
90*54ea6079SMartin KaFai Lau 	bool is_tcp_syn;
91*54ea6079SMartin KaFai Lau };
92*54ea6079SMartin KaFai Lau 
93*54ea6079SMartin KaFai Lau struct pkt_info {
94*54ea6079SMartin KaFai Lau 	enum ip_type type;
95*54ea6079SMartin KaFai Lau 	union {
96*54ea6079SMartin KaFai Lau 		struct iphdr *ipv4;
97*54ea6079SMartin KaFai Lau 		struct ipv6hdr *ipv6;
98*54ea6079SMartin KaFai Lau 	} ip;
99*54ea6079SMartin KaFai Lau 	int sport;
100*54ea6079SMartin KaFai Lau 	int dport;
101*54ea6079SMartin KaFai Lau 	__u16 trans_hdr_offset;
102*54ea6079SMartin KaFai Lau 	__u8 proto;
103*54ea6079SMartin KaFai Lau 	__u8 flags;
104*54ea6079SMartin KaFai Lau };
105*54ea6079SMartin KaFai Lau 
parse_ethhdr(void * data,void * data_end)106*54ea6079SMartin KaFai Lau static __always_inline struct ethhdr *parse_ethhdr(void *data, void *data_end)
107*54ea6079SMartin KaFai Lau {
108*54ea6079SMartin KaFai Lau 	struct ethhdr *eth = data;
109*54ea6079SMartin KaFai Lau 
110*54ea6079SMartin KaFai Lau 	if (eth + 1 > data_end)
111*54ea6079SMartin KaFai Lau 		return NULL;
112*54ea6079SMartin KaFai Lau 
113*54ea6079SMartin KaFai Lau 	return eth;
114*54ea6079SMartin KaFai Lau }
115*54ea6079SMartin KaFai Lau 
filter_ipv6_addr(const struct in6_addr * ipv6addr)116*54ea6079SMartin KaFai Lau static __always_inline __u8 filter_ipv6_addr(const struct in6_addr *ipv6addr)
117*54ea6079SMartin KaFai Lau {
118*54ea6079SMartin KaFai Lau 	__u8 *leaf;
119*54ea6079SMartin KaFai Lau 
120*54ea6079SMartin KaFai Lau 	leaf = bpf_map_lookup_elem(&v6_addr_map, ipv6addr);
121*54ea6079SMartin KaFai Lau 
122*54ea6079SMartin KaFai Lau 	return leaf ? *leaf : 0;
123*54ea6079SMartin KaFai Lau }
124*54ea6079SMartin KaFai Lau 
filter_ipv4_addr(const __u32 ipaddr)125*54ea6079SMartin KaFai Lau static __always_inline __u8 filter_ipv4_addr(const __u32 ipaddr)
126*54ea6079SMartin KaFai Lau {
127*54ea6079SMartin KaFai Lau 	__u8 *leaf;
128*54ea6079SMartin KaFai Lau 
129*54ea6079SMartin KaFai Lau 	leaf = bpf_map_lookup_elem(&v4_addr_map, &ipaddr);
130*54ea6079SMartin KaFai Lau 
131*54ea6079SMartin KaFai Lau 	return leaf ? *leaf : 0;
132*54ea6079SMartin KaFai Lau }
133*54ea6079SMartin KaFai Lau 
filter_ipv4_lpm(const __u32 ipaddr)134*54ea6079SMartin KaFai Lau static __always_inline __u8 filter_ipv4_lpm(const __u32 ipaddr)
135*54ea6079SMartin KaFai Lau {
136*54ea6079SMartin KaFai Lau 	struct v4_lpm_key v4_key = {};
137*54ea6079SMartin KaFai Lau 	struct v4_lpm_val *lpm_val;
138*54ea6079SMartin KaFai Lau 
139*54ea6079SMartin KaFai Lau 	v4_key.src = ipaddr;
140*54ea6079SMartin KaFai Lau 	v4_key.prefixlen = 32;
141*54ea6079SMartin KaFai Lau 
142*54ea6079SMartin KaFai Lau 	lpm_val = bpf_map_lookup_elem(&v4_lpm_val_map, &v4_key);
143*54ea6079SMartin KaFai Lau 
144*54ea6079SMartin KaFai Lau 	return lpm_val ? lpm_val->val : 0;
145*54ea6079SMartin KaFai Lau }
146*54ea6079SMartin KaFai Lau 
147*54ea6079SMartin KaFai Lau 
148*54ea6079SMartin KaFai Lau static __always_inline void
filter_src_dst_ip(struct pkt_info * info,struct fw_match_info * match_info)149*54ea6079SMartin KaFai Lau filter_src_dst_ip(struct pkt_info* info, struct fw_match_info* match_info)
150*54ea6079SMartin KaFai Lau {
151*54ea6079SMartin KaFai Lau 	if (info->type == V6) {
152*54ea6079SMartin KaFai Lau 		match_info->v6_src_ip_match =
153*54ea6079SMartin KaFai Lau 			filter_ipv6_addr(&info->ip.ipv6->saddr);
154*54ea6079SMartin KaFai Lau 	} else if (info->type == V4) {
155*54ea6079SMartin KaFai Lau 		match_info->v4_src_ip_match =
156*54ea6079SMartin KaFai Lau 			filter_ipv4_addr(info->ip.ipv4->saddr);
157*54ea6079SMartin KaFai Lau 		match_info->v4_src_prefix_match =
158*54ea6079SMartin KaFai Lau 			filter_ipv4_lpm(info->ip.ipv4->saddr);
159*54ea6079SMartin KaFai Lau 		match_info->v4_dst_prefix_match =
160*54ea6079SMartin KaFai Lau 			filter_ipv4_lpm(info->ip.ipv4->daddr);
161*54ea6079SMartin KaFai Lau 	}
162*54ea6079SMartin KaFai Lau }
163*54ea6079SMartin KaFai Lau 
164*54ea6079SMartin KaFai Lau static __always_inline void *
get_transport_hdr(__u16 offset,void * data,void * data_end)165*54ea6079SMartin KaFai Lau get_transport_hdr(__u16 offset, void *data, void *data_end)
166*54ea6079SMartin KaFai Lau {
167*54ea6079SMartin KaFai Lau 	if (offset > 255 || data + offset > data_end)
168*54ea6079SMartin KaFai Lau 		return NULL;
169*54ea6079SMartin KaFai Lau 
170*54ea6079SMartin KaFai Lau 	return data + offset;
171*54ea6079SMartin KaFai Lau }
172*54ea6079SMartin KaFai Lau 
tcphdr_only_contains_flag(struct tcphdr * tcp,__u32 FLAG)173*54ea6079SMartin KaFai Lau static __always_inline bool tcphdr_only_contains_flag(struct tcphdr *tcp,
174*54ea6079SMartin KaFai Lau 						      __u32 FLAG)
175*54ea6079SMartin KaFai Lau {
176*54ea6079SMartin KaFai Lau 	return (tcp_flag_word(tcp) &
177*54ea6079SMartin KaFai Lau 		(TCP_FLAG_ACK | TCP_FLAG_RST | TCP_FLAG_SYN | TCP_FLAG_FIN)) == FLAG;
178*54ea6079SMartin KaFai Lau }
179*54ea6079SMartin KaFai Lau 
set_tcp_flags(struct pkt_info * info,struct tcphdr * tcp)180*54ea6079SMartin KaFai Lau static __always_inline void set_tcp_flags(struct pkt_info *info,
181*54ea6079SMartin KaFai Lau 					  struct tcphdr *tcp) {
182*54ea6079SMartin KaFai Lau 	if (tcphdr_only_contains_flag(tcp, TCP_FLAG_SYN))
183*54ea6079SMartin KaFai Lau 		info->flags |= TCP_SYN;
184*54ea6079SMartin KaFai Lau 	else if (tcphdr_only_contains_flag(tcp, TCP_FLAG_ACK))
185*54ea6079SMartin KaFai Lau 		info->flags |= TCP_ACK;
186*54ea6079SMartin KaFai Lau 	else if (tcphdr_only_contains_flag(tcp, TCP_FLAG_RST))
187*54ea6079SMartin KaFai Lau 		info->flags |= TCP_RST;
188*54ea6079SMartin KaFai Lau }
189*54ea6079SMartin KaFai Lau 
190*54ea6079SMartin KaFai Lau static __always_inline bool
parse_tcp(struct pkt_info * info,void * transport_hdr,void * data_end)191*54ea6079SMartin KaFai Lau parse_tcp(struct pkt_info *info, void *transport_hdr, void *data_end)
192*54ea6079SMartin KaFai Lau {
193*54ea6079SMartin KaFai Lau 	struct tcphdr *tcp = transport_hdr;
194*54ea6079SMartin KaFai Lau 
195*54ea6079SMartin KaFai Lau 	if (tcp + 1 > data_end)
196*54ea6079SMartin KaFai Lau 		return false;
197*54ea6079SMartin KaFai Lau 
198*54ea6079SMartin KaFai Lau 	info->sport = bpf_ntohs(tcp->source);
199*54ea6079SMartin KaFai Lau 	info->dport = bpf_ntohs(tcp->dest);
200*54ea6079SMartin KaFai Lau 	set_tcp_flags(info, tcp);
201*54ea6079SMartin KaFai Lau 
202*54ea6079SMartin KaFai Lau 	return true;
203*54ea6079SMartin KaFai Lau }
204*54ea6079SMartin KaFai Lau 
205*54ea6079SMartin KaFai Lau static __always_inline bool
parse_udp(struct pkt_info * info,void * transport_hdr,void * data_end)206*54ea6079SMartin KaFai Lau parse_udp(struct pkt_info *info, void *transport_hdr, void *data_end)
207*54ea6079SMartin KaFai Lau {
208*54ea6079SMartin KaFai Lau 	struct udphdr *udp = transport_hdr;
209*54ea6079SMartin KaFai Lau 
210*54ea6079SMartin KaFai Lau 	if (udp + 1 > data_end)
211*54ea6079SMartin KaFai Lau 		return false;
212*54ea6079SMartin KaFai Lau 
213*54ea6079SMartin KaFai Lau 	info->sport = bpf_ntohs(udp->source);
214*54ea6079SMartin KaFai Lau 	info->dport = bpf_ntohs(udp->dest);
215*54ea6079SMartin KaFai Lau 
216*54ea6079SMartin KaFai Lau 	return true;
217*54ea6079SMartin KaFai Lau }
218*54ea6079SMartin KaFai Lau 
filter_tcp_port(int port)219*54ea6079SMartin KaFai Lau static __always_inline __u8 filter_tcp_port(int port)
220*54ea6079SMartin KaFai Lau {
221*54ea6079SMartin KaFai Lau 	__u8 *leaf = bpf_map_lookup_elem(&tcp_port_map, &port);
222*54ea6079SMartin KaFai Lau 
223*54ea6079SMartin KaFai Lau 	return leaf ? *leaf : 0;
224*54ea6079SMartin KaFai Lau }
225*54ea6079SMartin KaFai Lau 
filter_udp_port(int port)226*54ea6079SMartin KaFai Lau static __always_inline __u16 filter_udp_port(int port)
227*54ea6079SMartin KaFai Lau {
228*54ea6079SMartin KaFai Lau 	__u16 *leaf = bpf_map_lookup_elem(&udp_port_map, &port);
229*54ea6079SMartin KaFai Lau 
230*54ea6079SMartin KaFai Lau 	return leaf ? *leaf : 0;
231*54ea6079SMartin KaFai Lau }
232*54ea6079SMartin KaFai Lau 
233*54ea6079SMartin KaFai Lau static __always_inline bool
filter_transport_hdr(void * transport_hdr,void * data_end,struct pkt_info * info,struct fw_match_info * match_info)234*54ea6079SMartin KaFai Lau filter_transport_hdr(void *transport_hdr, void *data_end,
235*54ea6079SMartin KaFai Lau 		     struct pkt_info *info, struct fw_match_info *match_info)
236*54ea6079SMartin KaFai Lau {
237*54ea6079SMartin KaFai Lau 	if (info->proto == IPPROTO_TCP) {
238*54ea6079SMartin KaFai Lau 		if (!parse_tcp(info, transport_hdr, data_end))
239*54ea6079SMartin KaFai Lau 			return false;
240*54ea6079SMartin KaFai Lau 
241*54ea6079SMartin KaFai Lau 		match_info->is_tcp = true;
242*54ea6079SMartin KaFai Lau 		match_info->is_tcp_syn = (info->flags & TCP_SYN) > 0;
243*54ea6079SMartin KaFai Lau 
244*54ea6079SMartin KaFai Lau 		match_info->tcp_dp_match = filter_tcp_port(info->dport);
245*54ea6079SMartin KaFai Lau 	} else if (info->proto == IPPROTO_UDP) {
246*54ea6079SMartin KaFai Lau 		if (!parse_udp(info, transport_hdr, data_end))
247*54ea6079SMartin KaFai Lau 			return false;
248*54ea6079SMartin KaFai Lau 
249*54ea6079SMartin KaFai Lau 		match_info->udp_dp_match = filter_udp_port(info->dport);
250*54ea6079SMartin KaFai Lau 		match_info->udp_sp_match = filter_udp_port(info->sport);
251*54ea6079SMartin KaFai Lau 	}
252*54ea6079SMartin KaFai Lau 
253*54ea6079SMartin KaFai Lau 	return true;
254*54ea6079SMartin KaFai Lau }
255*54ea6079SMartin KaFai Lau 
256*54ea6079SMartin KaFai Lau static __always_inline __u8
parse_gue_v6(struct pkt_info * info,struct ipv6hdr * ip6h,void * data_end)257*54ea6079SMartin KaFai Lau parse_gue_v6(struct pkt_info *info, struct ipv6hdr *ip6h, void *data_end)
258*54ea6079SMartin KaFai Lau {
259*54ea6079SMartin KaFai Lau 	struct udphdr *udp = (struct udphdr *)(ip6h + 1);
260*54ea6079SMartin KaFai Lau 	void *encap_data = udp + 1;
261*54ea6079SMartin KaFai Lau 
262*54ea6079SMartin KaFai Lau 	if (udp + 1 > data_end)
263*54ea6079SMartin KaFai Lau 		return BAD_IP6_HDR;
264*54ea6079SMartin KaFai Lau 
265*54ea6079SMartin KaFai Lau 	if (udp->dest != bpf_htons(6666))
266*54ea6079SMartin KaFai Lau 		return NO_ERR;
267*54ea6079SMartin KaFai Lau 
268*54ea6079SMartin KaFai Lau 	info->flags |= TUNNEL;
269*54ea6079SMartin KaFai Lau 
270*54ea6079SMartin KaFai Lau 	if (encap_data + 1 > data_end)
271*54ea6079SMartin KaFai Lau 		return BAD_IP6GUE_HDR;
272*54ea6079SMartin KaFai Lau 
273*54ea6079SMartin KaFai Lau 	if (*(__u8 *)encap_data & 0x30) {
274*54ea6079SMartin KaFai Lau 		struct ipv6hdr *inner_ip6h = encap_data;
275*54ea6079SMartin KaFai Lau 
276*54ea6079SMartin KaFai Lau 		if (inner_ip6h + 1 > data_end)
277*54ea6079SMartin KaFai Lau 			return BAD_IP6GUE_HDR;
278*54ea6079SMartin KaFai Lau 
279*54ea6079SMartin KaFai Lau 		info->type = V6;
280*54ea6079SMartin KaFai Lau 		info->proto = inner_ip6h->nexthdr;
281*54ea6079SMartin KaFai Lau 		info->ip.ipv6 = inner_ip6h;
282*54ea6079SMartin KaFai Lau 		info->trans_hdr_offset += sizeof(struct ipv6hdr) + sizeof(struct udphdr);
283*54ea6079SMartin KaFai Lau 	} else {
284*54ea6079SMartin KaFai Lau 		struct iphdr *inner_ip4h = encap_data;
285*54ea6079SMartin KaFai Lau 
286*54ea6079SMartin KaFai Lau 		if (inner_ip4h + 1 > data_end)
287*54ea6079SMartin KaFai Lau 			return BAD_IP6GUE_HDR;
288*54ea6079SMartin KaFai Lau 
289*54ea6079SMartin KaFai Lau 		info->type = V4;
290*54ea6079SMartin KaFai Lau 		info->proto = inner_ip4h->protocol;
291*54ea6079SMartin KaFai Lau 		info->ip.ipv4 = inner_ip4h;
292*54ea6079SMartin KaFai Lau 		info->trans_hdr_offset += sizeof(struct iphdr) + sizeof(struct udphdr);
293*54ea6079SMartin KaFai Lau 	}
294*54ea6079SMartin KaFai Lau 
295*54ea6079SMartin KaFai Lau 	return NO_ERR;
296*54ea6079SMartin KaFai Lau }
297*54ea6079SMartin KaFai Lau 
parse_ipv6_gue(struct pkt_info * info,void * data,void * data_end)298*54ea6079SMartin KaFai Lau static __always_inline __u8 parse_ipv6_gue(struct pkt_info *info,
299*54ea6079SMartin KaFai Lau 					   void *data, void *data_end)
300*54ea6079SMartin KaFai Lau {
301*54ea6079SMartin KaFai Lau 	struct ipv6hdr *ip6h = data + sizeof(struct ethhdr);
302*54ea6079SMartin KaFai Lau 
303*54ea6079SMartin KaFai Lau 	if (ip6h + 1 > data_end)
304*54ea6079SMartin KaFai Lau 		return BAD_IP6_HDR;
305*54ea6079SMartin KaFai Lau 
306*54ea6079SMartin KaFai Lau 	info->proto = ip6h->nexthdr;
307*54ea6079SMartin KaFai Lau 	info->ip.ipv6 = ip6h;
308*54ea6079SMartin KaFai Lau 	info->type = V6;
309*54ea6079SMartin KaFai Lau 	info->trans_hdr_offset = sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
310*54ea6079SMartin KaFai Lau 
311*54ea6079SMartin KaFai Lau 	if (info->proto == IPPROTO_UDP)
312*54ea6079SMartin KaFai Lau 		return parse_gue_v6(info, ip6h, data_end);
313*54ea6079SMartin KaFai Lau 
314*54ea6079SMartin KaFai Lau 	return NO_ERR;
315*54ea6079SMartin KaFai Lau }
316*54ea6079SMartin KaFai Lau 
317*54ea6079SMartin KaFai Lau SEC("xdp")
edgewall(struct xdp_md * ctx)318*54ea6079SMartin KaFai Lau int edgewall(struct xdp_md *ctx)
319*54ea6079SMartin KaFai Lau {
320*54ea6079SMartin KaFai Lau 	void *data_end = (void *)(long)(ctx->data_end);
321*54ea6079SMartin KaFai Lau 	void *data = (void *)(long)(ctx->data);
322*54ea6079SMartin KaFai Lau 	struct fw_match_info match_info = {};
323*54ea6079SMartin KaFai Lau 	struct pkt_info info = {};
324*54ea6079SMartin KaFai Lau 	void *transport_hdr;
325*54ea6079SMartin KaFai Lau 	struct ethhdr *eth;
326*54ea6079SMartin KaFai Lau 	bool filter_res;
327*54ea6079SMartin KaFai Lau 	__u32 proto;
328*54ea6079SMartin KaFai Lau 
329*54ea6079SMartin KaFai Lau 	eth = parse_ethhdr(data, data_end);
330*54ea6079SMartin KaFai Lau 	if (!eth)
331*54ea6079SMartin KaFai Lau 		return XDP_DROP;
332*54ea6079SMartin KaFai Lau 
333*54ea6079SMartin KaFai Lau 	proto = eth->h_proto;
334*54ea6079SMartin KaFai Lau 	if (proto != bpf_htons(ETH_P_IPV6))
335*54ea6079SMartin KaFai Lau 		return XDP_DROP;
336*54ea6079SMartin KaFai Lau 
337*54ea6079SMartin KaFai Lau 	if (parse_ipv6_gue(&info, data, data_end))
338*54ea6079SMartin KaFai Lau 		return XDP_DROP;
339*54ea6079SMartin KaFai Lau 
340*54ea6079SMartin KaFai Lau 	if (info.proto == IPPROTO_ICMPV6)
341*54ea6079SMartin KaFai Lau 		return XDP_PASS;
342*54ea6079SMartin KaFai Lau 
343*54ea6079SMartin KaFai Lau 	if (info.proto != IPPROTO_TCP && info.proto != IPPROTO_UDP)
344*54ea6079SMartin KaFai Lau 		return XDP_DROP;
345*54ea6079SMartin KaFai Lau 
346*54ea6079SMartin KaFai Lau 	filter_src_dst_ip(&info, &match_info);
347*54ea6079SMartin KaFai Lau 
348*54ea6079SMartin KaFai Lau 	transport_hdr = get_transport_hdr(info.trans_hdr_offset, data,
349*54ea6079SMartin KaFai Lau 					  data_end);
350*54ea6079SMartin KaFai Lau 	if (!transport_hdr)
351*54ea6079SMartin KaFai Lau 		return XDP_DROP;
352*54ea6079SMartin KaFai Lau 
353*54ea6079SMartin KaFai Lau 	filter_res = filter_transport_hdr(transport_hdr, data_end,
354*54ea6079SMartin KaFai Lau 					  &info, &match_info);
355*54ea6079SMartin KaFai Lau 	if (!filter_res)
356*54ea6079SMartin KaFai Lau 		return XDP_DROP;
357*54ea6079SMartin KaFai Lau 
358*54ea6079SMartin KaFai Lau 	if (match_info.is_tcp && !match_info.is_tcp_syn)
359*54ea6079SMartin KaFai Lau 		return XDP_PASS;
360*54ea6079SMartin KaFai Lau 
361*54ea6079SMartin KaFai Lau 	return XDP_DROP;
362*54ea6079SMartin KaFai Lau }
363*54ea6079SMartin KaFai Lau 
364*54ea6079SMartin KaFai Lau char LICENSE[] SEC("license") = "GPL";
365