2 * IPV4 GSO/GRO offload support
3 * Linux INET implementation
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
10 * TCPv4 GSO/GRO support
13 #include <linux/skbuff.h>
15 #include <net/protocol.h>
17 static void tcp_gso_tstamp(struct sk_buff
*skb
, unsigned int ts_seq
,
18 unsigned int seq
, unsigned int mss
)
21 if (before(ts_seq
, seq
+ mss
)) {
22 skb_shinfo(skb
)->tx_flags
|= SKBTX_SW_TSTAMP
;
23 skb_shinfo(skb
)->tskey
= ts_seq
;
32 static struct sk_buff
*tcp4_gso_segment(struct sk_buff
*skb
,
33 netdev_features_t features
)
35 if (!pskb_may_pull(skb
, sizeof(struct tcphdr
)))
36 return ERR_PTR(-EINVAL
);
38 if (unlikely(skb
->ip_summed
!= CHECKSUM_PARTIAL
)) {
39 const struct iphdr
*iph
= ip_hdr(skb
);
40 struct tcphdr
*th
= tcp_hdr(skb
);
42 /* Set up checksum pseudo header, usually expect stack to
43 * have done this already.
47 skb
->ip_summed
= CHECKSUM_PARTIAL
;
48 __tcp_v4_send_check(skb
, iph
->saddr
, iph
->daddr
);
51 return tcp_gso_segment(skb
, features
);
54 struct sk_buff
*tcp_gso_segment(struct sk_buff
*skb
,
55 netdev_features_t features
)
57 struct sk_buff
*segs
= ERR_PTR(-EINVAL
);
58 unsigned int sum_truesize
= 0;
65 struct sk_buff
*gso_skb
= skb
;
67 bool ooo_okay
, copy_destructor
;
71 if (thlen
< sizeof(*th
))
74 if (!pskb_may_pull(skb
, thlen
))
77 oldlen
= (u16
)~skb
->len
;
78 __skb_pull(skb
, thlen
);
80 mss
= skb_shinfo(skb
)->gso_size
;
81 if (unlikely(skb
->len
<= mss
))
84 if (skb_gso_ok(skb
, features
| NETIF_F_GSO_ROBUST
)) {
85 /* Packet is from an untrusted source, reset gso_segs. */
86 int type
= skb_shinfo(skb
)->gso_type
;
98 SKB_GSO_UDP_TUNNEL_CSUM
|
99 SKB_GSO_TUNNEL_REMCSUM
|
101 !(type
& (SKB_GSO_TCPV4
| SKB_GSO_TCPV6
))))
104 skb_shinfo(skb
)->gso_segs
= DIV_ROUND_UP(skb
->len
, mss
);
110 copy_destructor
= gso_skb
->destructor
== tcp_wfree
;
111 ooo_okay
= gso_skb
->ooo_okay
;
112 /* All segments but the first should have ooo_okay cleared */
115 segs
= skb_segment(skb
, features
);
119 /* Only first segment might have ooo_okay set */
120 segs
->ooo_okay
= ooo_okay
;
122 delta
= htonl(oldlen
+ (thlen
+ mss
));
126 seq
= ntohl(th
->seq
);
128 if (unlikely(skb_shinfo(gso_skb
)->tx_flags
& SKBTX_SW_TSTAMP
))
129 tcp_gso_tstamp(segs
, skb_shinfo(gso_skb
)->tskey
, seq
, mss
);
131 newcheck
= ~csum_fold((__force __wsum
)((__force u32
)th
->check
+
132 (__force u32
)delta
));
135 th
->fin
= th
->psh
= 0;
136 th
->check
= newcheck
;
138 if (skb
->ip_summed
== CHECKSUM_PARTIAL
)
139 gso_reset_checksum(skb
, ~th
->check
);
141 th
->check
= gso_make_checksum(skb
, ~th
->check
);
144 if (copy_destructor
) {
145 skb
->destructor
= gso_skb
->destructor
;
146 skb
->sk
= gso_skb
->sk
;
147 sum_truesize
+= skb
->truesize
;
152 th
->seq
= htonl(seq
);
156 /* Following permits TCP Small Queues to work well with GSO :
157 * The callback to TCP stack will be called at the time last frag
158 * is freed at TX completion, and not right now when gso_skb
159 * is freed by GSO engine
161 if (copy_destructor
) {
162 swap(gso_skb
->sk
, skb
->sk
);
163 swap(gso_skb
->destructor
, skb
->destructor
);
164 sum_truesize
+= skb
->truesize
;
165 atomic_add(sum_truesize
- gso_skb
->truesize
,
166 &skb
->sk
->sk_wmem_alloc
);
169 delta
= htonl(oldlen
+ (skb_tail_pointer(skb
) -
170 skb_transport_header(skb
)) +
172 th
->check
= ~csum_fold((__force __wsum
)((__force u32
)th
->check
+
173 (__force u32
)delta
));
174 if (skb
->ip_summed
== CHECKSUM_PARTIAL
)
175 gso_reset_checksum(skb
, ~th
->check
);
177 th
->check
= gso_make_checksum(skb
, ~th
->check
);
182 struct sk_buff
**tcp_gro_receive(struct sk_buff
**head
, struct sk_buff
*skb
)
184 struct sk_buff
**pp
= NULL
;
191 unsigned int mss
= 1;
197 off
= skb_gro_offset(skb
);
198 hlen
= off
+ sizeof(*th
);
199 th
= skb_gro_header_fast(skb
, off
);
200 if (skb_gro_header_hard(skb
, hlen
)) {
201 th
= skb_gro_header_slow(skb
, hlen
, off
);
206 thlen
= th
->doff
* 4;
207 if (thlen
< sizeof(*th
))
211 if (skb_gro_header_hard(skb
, hlen
)) {
212 th
= skb_gro_header_slow(skb
, hlen
, off
);
217 skb_gro_pull(skb
, thlen
);
219 len
= skb_gro_len(skb
);
220 flags
= tcp_flag_word(th
);
222 for (; (p
= *head
); head
= &p
->next
) {
223 if (!NAPI_GRO_CB(p
)->same_flow
)
228 if (*(u32
*)&th
->source
^ *(u32
*)&th2
->source
) {
229 NAPI_GRO_CB(p
)->same_flow
= 0;
236 goto out_check_final
;
239 /* Include the IP ID check below from the inner most IP hdr */
240 flush
= NAPI_GRO_CB(p
)->flush
| NAPI_GRO_CB(p
)->flush_id
;
241 flush
|= (__force
int)(flags
& TCP_FLAG_CWR
);
242 flush
|= (__force
int)((flags
^ tcp_flag_word(th2
)) &
243 ~(TCP_FLAG_CWR
| TCP_FLAG_FIN
| TCP_FLAG_PSH
));
244 flush
|= (__force
int)(th
->ack_seq
^ th2
->ack_seq
);
245 for (i
= sizeof(*th
); i
< thlen
; i
+= 4)
246 flush
|= *(u32
*)((u8
*)th
+ i
) ^
247 *(u32
*)((u8
*)th2
+ i
);
249 mss
= skb_shinfo(p
)->gso_size
;
251 flush
|= (len
- 1) >= mss
;
252 flush
|= (ntohl(th2
->seq
) + skb_gro_len(p
)) ^ ntohl(th
->seq
);
254 if (flush
|| skb_gro_receive(head
, skb
)) {
256 goto out_check_final
;
261 tcp_flag_word(th2
) |= flags
& (TCP_FLAG_FIN
| TCP_FLAG_PSH
);
265 flush
|= (__force
int)(flags
& (TCP_FLAG_URG
| TCP_FLAG_PSH
|
266 TCP_FLAG_RST
| TCP_FLAG_SYN
|
269 if (p
&& (!NAPI_GRO_CB(skb
)->same_flow
|| flush
))
273 NAPI_GRO_CB(skb
)->flush
|= (flush
!= 0);
278 int tcp_gro_complete(struct sk_buff
*skb
)
280 struct tcphdr
*th
= tcp_hdr(skb
);
282 skb
->csum_start
= (unsigned char *)th
- skb
->head
;
283 skb
->csum_offset
= offsetof(struct tcphdr
, check
);
284 skb
->ip_summed
= CHECKSUM_PARTIAL
;
286 skb_shinfo(skb
)->gso_segs
= NAPI_GRO_CB(skb
)->count
;
289 skb_shinfo(skb
)->gso_type
|= SKB_GSO_TCP_ECN
;
293 EXPORT_SYMBOL(tcp_gro_complete
);
295 static struct sk_buff
**tcp4_gro_receive(struct sk_buff
**head
, struct sk_buff
*skb
)
297 /* Don't bother verifying checksum if we're going to flush anyway. */
298 if (!NAPI_GRO_CB(skb
)->flush
&&
299 skb_gro_checksum_validate(skb
, IPPROTO_TCP
,
300 inet_gro_compute_pseudo
)) {
301 NAPI_GRO_CB(skb
)->flush
= 1;
305 return tcp_gro_receive(head
, skb
);
308 static int tcp4_gro_complete(struct sk_buff
*skb
, int thoff
)
310 const struct iphdr
*iph
= ip_hdr(skb
);
311 struct tcphdr
*th
= tcp_hdr(skb
);
313 th
->check
= ~tcp_v4_check(skb
->len
- thoff
, iph
->saddr
,
315 skb_shinfo(skb
)->gso_type
|= SKB_GSO_TCPV4
;
317 return tcp_gro_complete(skb
);
320 static const struct net_offload tcpv4_offload
= {
322 .gso_segment
= tcp4_gso_segment
,
323 .gro_receive
= tcp4_gro_receive
,
324 .gro_complete
= tcp4_gro_complete
,
328 int __init
tcpv4_offload_init(void)
330 return inet_add_offload(&tcpv4_offload
, IPPROTO_TCP
);