Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tcp: move logic out of tcp_v[64]_gso_send_check

In tcp_v[46]_gso_send_check the TCP checksum is initialized to the
pseudo header checksum using __tcp_v[46]_send_check. We can move this
logic into new tcp[46]_gso_segment functions to be done when
ip_summed != CHECKSUM_PARTIAL (ip_summed == CHECKSUM_PARTIAL should be
the common case, possibly always true when taking GSO path). After this
change tcp_v[46]_gso_send_check is no-op.

Signed-off-by: Tom Herbert <therbert@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tom Herbert and committed by
David S. Miller
d020f8f7 2fdbfea5

+47 -29
+23 -16
net/ipv4/tcp_offload.c
··· 29 29 } 30 30 } 31 31 32 + struct sk_buff *tcp4_gso_segment(struct sk_buff *skb, 33 + netdev_features_t features) 34 + { 35 + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) 36 + return ERR_PTR(-EINVAL); 37 + 38 + if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { 39 + const struct iphdr *iph = ip_hdr(skb); 40 + struct tcphdr *th = tcp_hdr(skb); 41 + 42 + /* Set up checksum pseudo header, usually expect stack to 43 + * have done this already. 44 + */ 45 + 46 + th->check = 0; 47 + skb->ip_summed = CHECKSUM_PARTIAL; 48 + __tcp_v4_send_check(skb, iph->saddr, iph->daddr); 49 + } 50 + 51 + return tcp_gso_segment(skb, features); 52 + } 53 + 32 54 struct sk_buff *tcp_gso_segment(struct sk_buff *skb, 33 55 netdev_features_t features) 34 56 { ··· 65 43 struct sk_buff *gso_skb = skb; 66 44 __sum16 newcheck; 67 45 bool ooo_okay, copy_destructor; 68 - 69 - if (!pskb_may_pull(skb, sizeof(*th))) 70 - goto out; 71 46 72 47 th = tcp_hdr(skb); 73 48 thlen = th->doff * 4; ··· 290 271 291 272 static int tcp_v4_gso_send_check(struct sk_buff *skb) 292 273 { 293 - const struct iphdr *iph; 294 - struct tcphdr *th; 295 - 296 - if (!pskb_may_pull(skb, sizeof(*th))) 297 - return -EINVAL; 298 - 299 - iph = ip_hdr(skb); 300 - th = tcp_hdr(skb); 301 - 302 - th->check = 0; 303 - skb->ip_summed = CHECKSUM_PARTIAL; 304 - __tcp_v4_send_check(skb, iph->saddr, iph->daddr); 305 274 return 0; 306 275 } 307 276 ··· 321 314 static const struct net_offload tcpv4_offload = { 322 315 .callbacks = { 323 316 .gso_send_check = tcp_v4_gso_send_check, 324 - .gso_segment = tcp_gso_segment, 317 + .gso_segment = tcp4_gso_segment, 325 318 .gro_receive = tcp4_gro_receive, 326 319 .gro_complete = tcp4_gro_complete, 327 320 },
+24 -13
net/ipv6/tcpv6_offload.c
··· 17 17 18 18 static int tcp_v6_gso_send_check(struct sk_buff *skb) 19 19 { 20 - const struct ipv6hdr *ipv6h; 21 - struct tcphdr *th; 22 - 23 - if (!pskb_may_pull(skb, sizeof(*th))) 24 - return -EINVAL; 25 - 26 - ipv6h = ipv6_hdr(skb); 27 - th = tcp_hdr(skb); 28 - 29 - th->check = 0; 30 - skb->ip_summed = CHECKSUM_PARTIAL; 31 - __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); 32 20 return 0; 33 21 } 34 22 ··· 46 58 return tcp_gro_complete(skb); 47 59 } 48 60 61 + struct sk_buff *tcp6_gso_segment(struct sk_buff *skb, 62 + netdev_features_t features) 63 + { 64 + struct tcphdr *th; 65 + 66 + if (!pskb_may_pull(skb, sizeof(*th))) 67 + return ERR_PTR(-EINVAL); 68 + 69 + if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { 70 + const struct ipv6hdr *ipv6h = ipv6_hdr(skb); 71 + struct tcphdr *th = tcp_hdr(skb); 72 + 73 + /* Set up pseudo header, usually expect stack to have done 74 + * this. 75 + */ 76 + 77 + th->check = 0; 78 + skb->ip_summed = CHECKSUM_PARTIAL; 79 + __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); 80 + } 81 + 82 + return tcp_gso_segment(skb, features); 83 + } 49 84 static const struct net_offload tcpv6_offload = { 50 85 .callbacks = { 51 86 .gso_send_check = tcp_v6_gso_send_check, 52 - .gso_segment = tcp_gso_segment, 87 + .gso_segment = tcp6_gso_segment, 53 88 .gro_receive = tcp6_gro_receive, 54 89 .gro_complete = tcp6_gro_complete, 55 90 },