@@ -38,21 +38,17 @@ static inline struct fou *fou_from_sock(struct sock *sk)
38
38
return sk -> sk_user_data ;
39
39
}
40
40
41
- static int fou_udp_encap_recv_deliver (struct sk_buff * skb ,
42
- u8 protocol , size_t len )
41
+ static void fou_recv_pull (struct sk_buff * skb , size_t len )
43
42
{
44
43
struct iphdr * iph = ip_hdr (skb );
45
44
46
45
/* Remove 'len' bytes from the packet (UDP header and
47
- * FOU header if present), modify the protocol to the one
48
- * we found, and then call rcv_encap.
46
+ * FOU header if present).
49
47
*/
50
48
iph -> tot_len = htons (ntohs (iph -> tot_len ) - len );
51
49
__skb_pull (skb , len );
52
50
skb_postpull_rcsum (skb , udp_hdr (skb ), len );
53
51
skb_reset_transport_header (skb );
54
-
55
- return - protocol ;
56
52
}
57
53
58
54
static int fou_udp_recv (struct sock * sk , struct sk_buff * skb )
@@ -62,16 +58,24 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
62
58
if (!fou )
63
59
return 1 ;
64
60
65
- return fou_udp_encap_recv_deliver (skb , fou -> protocol ,
66
- sizeof (struct udphdr ));
61
+ fou_recv_pull (skb , sizeof (struct udphdr ));
62
+
63
+ return - fou -> protocol ;
64
+ }
65
+
66
+ static int gue_control_message (struct sk_buff * skb , struct guehdr * guehdr )
67
+ {
68
+ /* No support yet */
69
+ kfree_skb (skb );
70
+ return 0 ;
67
71
}
68
72
69
73
static int gue_udp_recv (struct sock * sk , struct sk_buff * skb )
70
74
{
71
75
struct fou * fou = fou_from_sock (sk );
72
- size_t len ;
76
+ size_t len , optlen , hdrlen ;
73
77
struct guehdr * guehdr ;
74
- struct udphdr * uh ;
78
+ void * data ;
75
79
76
80
if (!fou )
77
81
return 1 ;
@@ -80,25 +84,38 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
80
84
if (!pskb_may_pull (skb , len ))
81
85
goto drop ;
82
86
83
- uh = udp_hdr (skb );
84
- guehdr = (struct guehdr * )& uh [1 ];
87
+ guehdr = (struct guehdr * )& udp_hdr (skb )[1 ];
88
+
89
+ optlen = guehdr -> hlen << 2 ;
90
+ len += optlen ;
85
91
86
- len += guehdr -> hlen << 2 ;
87
92
if (!pskb_may_pull (skb , len ))
88
93
goto drop ;
89
94
90
- uh = udp_hdr ( skb );
91
- guehdr = (struct guehdr * )& uh [1 ];
95
+ /* guehdr may change after pull */
96
+ guehdr = (struct guehdr * )& udp_hdr ( skb ) [1 ];
92
97
93
- if (guehdr -> version != 0 )
94
- goto drop ;
98
+ hdrlen = sizeof (struct guehdr ) + optlen ;
95
99
96
- if (guehdr -> flags ) {
97
- /* No support yet */
100
+ if (guehdr -> version != 0 || validate_gue_flags (guehdr , optlen ))
98
101
goto drop ;
102
+
103
+ /* Pull UDP and GUE headers */
104
+ fou_recv_pull (skb , len );
105
+
106
+ data = & guehdr [1 ];
107
+
108
+ if (guehdr -> flags & GUE_FLAG_PRIV ) {
109
+ data += GUE_LEN_PRIV ;
110
+
111
+ /* Process private flags */
99
112
}
100
113
101
- return fou_udp_encap_recv_deliver (skb , guehdr -> next_hdr , len );
114
+ if (unlikely (guehdr -> control ))
115
+ return gue_control_message (skb , guehdr );
116
+
117
+ return - guehdr -> proto_ctype ;
118
+
102
119
drop :
103
120
kfree_skb (skb );
104
121
return 0 ;
@@ -154,36 +171,47 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
154
171
const struct net_offload * ops ;
155
172
struct sk_buff * * pp = NULL ;
156
173
struct sk_buff * p ;
157
- u8 proto ;
158
174
struct guehdr * guehdr ;
159
- unsigned int hlen , guehlen ;
160
- unsigned int off ;
175
+ size_t len , optlen , hdrlen , off ;
176
+ void * data ;
161
177
int flush = 1 ;
162
178
163
179
off = skb_gro_offset (skb );
164
- hlen = off + sizeof (* guehdr );
180
+ len = off + sizeof (* guehdr );
181
+
165
182
guehdr = skb_gro_header_fast (skb , off );
166
- if (skb_gro_header_hard (skb , hlen )) {
167
- guehdr = skb_gro_header_slow (skb , hlen , off );
183
+ if (skb_gro_header_hard (skb , len )) {
184
+ guehdr = skb_gro_header_slow (skb , len , off );
168
185
if (unlikely (!guehdr ))
169
186
goto out ;
170
187
}
171
188
172
- proto = guehdr -> next_hdr ;
189
+ optlen = guehdr -> hlen << 2 ;
190
+ len += optlen ;
173
191
174
- rcu_read_lock ();
175
- offloads = NAPI_GRO_CB (skb ) -> is_ipv6 ? inet6_offloads : inet_offloads ;
176
- ops = rcu_dereference ( offloads [ proto ]);
177
- if ( WARN_ON (! ops || ! ops -> callbacks . gro_receive ))
178
- goto out_unlock ;
192
+ if ( skb_gro_header_hard ( skb , len )) {
193
+ guehdr = skb_gro_header_slow (skb , len , off ) ;
194
+ if ( unlikely (! guehdr ))
195
+ goto out ;
196
+ }
179
197
180
- guehlen = sizeof (* guehdr ) + (guehdr -> hlen << 2 );
198
+ if (unlikely (guehdr -> control ) || guehdr -> version != 0 ||
199
+ validate_gue_flags (guehdr , optlen ))
200
+ goto out ;
181
201
182
- hlen = off + guehlen ;
183
- if (skb_gro_header_hard (skb , hlen )) {
184
- guehdr = skb_gro_header_slow (skb , hlen , off );
185
- if (unlikely (!guehdr ))
186
- goto out_unlock ;
202
+ hdrlen = sizeof (* guehdr ) + optlen ;
203
+
204
+ skb_gro_pull (skb , hdrlen );
205
+
206
+ /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
207
+ skb_gro_postpull_rcsum (skb , guehdr , hdrlen );
208
+
209
+ data = & guehdr [1 ];
210
+
211
+ if (guehdr -> flags & GUE_FLAG_PRIV ) {
212
+ data += GUE_LEN_PRIV ;
213
+
214
+ /* Process private flags */
187
215
}
188
216
189
217
flush = 0 ;
@@ -197,7 +225,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
197
225
guehdr2 = (struct guehdr * )(p -> data + off );
198
226
199
227
/* Compare base GUE header to be equal (covers
200
- * hlen, version, next_hdr , and flags.
228
+ * hlen, version, proto_ctype , and flags.
201
229
*/
202
230
if (guehdr -> word != guehdr2 -> word ) {
203
231
NAPI_GRO_CB (p )-> same_flow = 0 ;
@@ -212,10 +240,11 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
212
240
}
213
241
}
214
242
215
- skb_gro_pull (skb , guehlen );
216
-
217
- /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
218
- skb_gro_postpull_rcsum (skb , guehdr , guehlen );
243
+ rcu_read_lock ();
244
+ offloads = NAPI_GRO_CB (skb )-> is_ipv6 ? inet6_offloads : inet_offloads ;
245
+ ops = rcu_dereference (offloads [guehdr -> proto_ctype ]);
246
+ if (WARN_ON (!ops || !ops -> callbacks .gro_receive ))
247
+ goto out_unlock ;
219
248
220
249
pp = ops -> callbacks .gro_receive (head , skb );
221
250
@@ -236,7 +265,7 @@ static int gue_gro_complete(struct sk_buff *skb, int nhoff)
236
265
u8 proto ;
237
266
int err = - ENOENT ;
238
267
239
- proto = guehdr -> next_hdr ;
268
+ proto = guehdr -> proto_ctype ;
240
269
241
270
guehlen = sizeof (* guehdr ) + (guehdr -> hlen << 2 );
242
271
@@ -533,8 +562,12 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
533
562
bool csum = !!(e -> flags & TUNNEL_ENCAP_FLAG_CSUM );
534
563
int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL ;
535
564
struct guehdr * guehdr ;
536
- size_t hdr_len = sizeof ( struct guehdr ) ;
565
+ size_t optlen = 0 ;
537
566
__be16 sport ;
567
+ void * data ;
568
+ bool need_priv = false;
569
+
570
+ optlen += need_priv ? GUE_LEN_PRIV : 0 ;
538
571
539
572
skb = iptunnel_handle_offloads (skb , csum , type );
540
573
@@ -545,14 +578,27 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
545
578
sport = e -> sport ? : udp_flow_src_port (dev_net (skb -> dev ),
546
579
skb , 0 , 0 , false);
547
580
548
- skb_push (skb , hdr_len );
581
+ skb_push (skb , sizeof ( struct guehdr ) + optlen );
549
582
550
583
guehdr = (struct guehdr * )skb -> data ;
551
584
585
+ guehdr -> control = 0 ;
552
586
guehdr -> version = 0 ;
553
- guehdr -> hlen = 0 ;
587
+ guehdr -> hlen = optlen >> 2 ;
554
588
guehdr -> flags = 0 ;
555
- guehdr -> next_hdr = * protocol ;
589
+ guehdr -> proto_ctype = * protocol ;
590
+
591
+ data = & guehdr [1 ];
592
+
593
+ if (need_priv ) {
594
+ __be32 * flags = data ;
595
+
596
+ guehdr -> flags |= GUE_FLAG_PRIV ;
597
+ * flags = 0 ;
598
+ data += GUE_LEN_PRIV ;
599
+
600
+ /* Add private flags */
601
+ }
556
602
557
603
fou_build_udp (skb , e , fl4 , protocol , sport );
558
604
0 commit comments