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