1414#define MAX_PAYLOAD_LEN 5000
1515#define MAX_HDR_LEN 64
1616
17+ extern int bpf_xdp_pull_data (struct xdp_md * xdp , __u32 len ) __ksym __weak ;
18+
1719enum {
1820 XDP_MODE = 0 ,
1921 XDP_PORT = 1 ,
@@ -68,30 +70,57 @@ static void record_stats(struct xdp_md *ctx, __u32 stat_type)
6870
6971static struct udphdr * filter_udphdr (struct xdp_md * ctx , __u16 port )
7072{
71- void * data_end = (void * )(long )ctx -> data_end ;
72- void * data = (void * )(long )ctx -> data ;
7373 struct udphdr * udph = NULL ;
74- struct ethhdr * eth = data ;
74+ void * data , * data_end ;
75+ struct ethhdr * eth ;
76+ int err ;
77+
78+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ));
79+ if (err )
80+ return NULL ;
81+
82+ data_end = (void * )(long )ctx -> data_end ;
83+ data = eth = (void * )(long )ctx -> data ;
7584
7685 if (data + sizeof (* eth ) > data_end )
7786 return NULL ;
7887
7988 if (eth -> h_proto == bpf_htons (ETH_P_IP )) {
80- struct iphdr * iph = data + sizeof (* eth );
89+ struct iphdr * iph ;
90+
91+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ) + sizeof (* iph ) +
92+ sizeof (* udph ));
93+ if (err )
94+ return NULL ;
95+
96+ data_end = (void * )(long )ctx -> data_end ;
97+ data = (void * )(long )ctx -> data ;
98+
99+ iph = data + sizeof (* eth );
81100
82101 if (iph + 1 > (struct iphdr * )data_end ||
83102 iph -> protocol != IPPROTO_UDP )
84103 return NULL ;
85104
86- udph = (void * )eth + sizeof (* iph ) + sizeof (* eth );
87- } else if (eth -> h_proto == bpf_htons (ETH_P_IPV6 )) {
88- struct ipv6hdr * ipv6h = data + sizeof (* eth );
105+ udph = data + sizeof (* iph ) + sizeof (* eth );
106+ } else if (eth -> h_proto == bpf_htons (ETH_P_IPV6 )) {
107+ struct ipv6hdr * ipv6h ;
108+
109+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ) + sizeof (* ipv6h ) +
110+ sizeof (* udph ));
111+ if (err )
112+ return NULL ;
113+
114+ data_end = (void * )(long )ctx -> data_end ;
115+ data = (void * )(long )ctx -> data ;
116+
117+ ipv6h = data + sizeof (* eth );
89118
90119 if (ipv6h + 1 > (struct ipv6hdr * )data_end ||
91120 ipv6h -> nexthdr != IPPROTO_UDP )
92121 return NULL ;
93122
94- udph = ( void * ) eth + sizeof (* ipv6h ) + sizeof (* eth );
123+ udph = data + sizeof (* ipv6h ) + sizeof (* eth );
95124 } else {
96125 return NULL ;
97126 }
@@ -145,17 +174,34 @@ static void swap_machdr(void *data)
145174
146175static int xdp_mode_tx_handler (struct xdp_md * ctx , __u16 port )
147176{
148- void * data_end = (void * )(long )ctx -> data_end ;
149- void * data = (void * )(long )ctx -> data ;
150177 struct udphdr * udph = NULL ;
151- struct ethhdr * eth = data ;
178+ void * data , * data_end ;
179+ struct ethhdr * eth ;
180+ int err ;
181+
182+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ));
183+ if (err )
184+ return XDP_PASS ;
185+
186+ data_end = (void * )(long )ctx -> data_end ;
187+ data = eth = (void * )(long )ctx -> data ;
152188
153189 if (data + sizeof (* eth ) > data_end )
154190 return XDP_PASS ;
155191
156192 if (eth -> h_proto == bpf_htons (ETH_P_IP )) {
157- struct iphdr * iph = data + sizeof (* eth );
158- __be32 tmp_ip = iph -> saddr ;
193+ struct iphdr * iph ;
194+ __be32 tmp_ip ;
195+
196+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ) + sizeof (* iph ) +
197+ sizeof (* udph ));
198+ if (err )
199+ return XDP_PASS ;
200+
201+ data_end = (void * )(long )ctx -> data_end ;
202+ data = (void * )(long )ctx -> data ;
203+
204+ iph = data + sizeof (* eth );
159205
160206 if (iph + 1 > (struct iphdr * )data_end ||
161207 iph -> protocol != IPPROTO_UDP )
@@ -169,18 +215,30 @@ static int xdp_mode_tx_handler(struct xdp_md *ctx, __u16 port)
169215 return XDP_PASS ;
170216
171217 record_stats (ctx , STATS_RX );
218+ eth = data ;
172219 swap_machdr ((void * )eth );
173220
221+ tmp_ip = iph -> saddr ;
174222 iph -> saddr = iph -> daddr ;
175223 iph -> daddr = tmp_ip ;
176224
177225 record_stats (ctx , STATS_TX );
178226
179227 return XDP_TX ;
180228
181- } else if (eth -> h_proto == bpf_htons (ETH_P_IPV6 )) {
182- struct ipv6hdr * ipv6h = data + sizeof (* eth );
229+ } else if (eth -> h_proto == bpf_htons (ETH_P_IPV6 )) {
183230 struct in6_addr tmp_ipv6 ;
231+ struct ipv6hdr * ipv6h ;
232+
233+ err = bpf_xdp_pull_data (ctx , sizeof (* eth ) + sizeof (* ipv6h ) +
234+ sizeof (* udph ));
235+ if (err )
236+ return XDP_PASS ;
237+
238+ data_end = (void * )(long )ctx -> data_end ;
239+ data = (void * )(long )ctx -> data ;
240+
241+ ipv6h = data + sizeof (* eth );
184242
185243 if (ipv6h + 1 > (struct ipv6hdr * )data_end ||
186244 ipv6h -> nexthdr != IPPROTO_UDP )
@@ -194,6 +252,7 @@ static int xdp_mode_tx_handler(struct xdp_md *ctx, __u16 port)
194252 return XDP_PASS ;
195253
196254 record_stats (ctx , STATS_RX );
255+ eth = data ;
197256 swap_machdr ((void * )eth );
198257
199258 __builtin_memcpy (& tmp_ipv6 , & ipv6h -> saddr , sizeof (tmp_ipv6 ));
0 commit comments