diff options
| author | David S. Miller <davem@davemloft.net> | 2014-06-15 04:00:56 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-06-15 04:00:56 -0400 |
| commit | e4f7ae930afafd4d9d67449657fefe51010c3349 (patch) | |
| tree | e1b1b85a1b30f00acf147818537b7e7bd7b3b86c | |
| parent | 63c6f81cdde58c41da62a8d8a209592e42a0203e (diff) | |
| parent | f79b064c15068176e3f6f67715aafd7fe183120c (diff) | |
Merge branch 'csum_fixes'
Tom Herbert says:
====================
Fixes related to some recent checksum modifications.
- Fix GSO constants to match NETIF flags
- Fix logic in saving checksum complete in __skb_checksum_complete
- Call __skb_checksum_complete from UDP if we are checksumming over
whole packet in order to save checksum.
- Fixes to VXLAN to work correctly with checksum complete
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/vxlan.c | 11 | ||||
| -rw-r--r-- | include/linux/netdev_features.h | 1 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 7 | ||||
| -rw-r--r-- | include/linux/skbuff.h | 23 | ||||
| -rw-r--r-- | include/net/udp.h | 4 | ||||
| -rw-r--r-- | net/core/datagram.c | 36 | ||||
| -rw-r--r-- | net/core/skbuff.c | 3 |
7 files changed, 60 insertions, 25 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e0995ffd046d..ade33ef82823 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
| @@ -1156,15 +1156,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) | |||
| 1156 | if (!vs) | 1156 | if (!vs) |
| 1157 | goto drop; | 1157 | goto drop; |
| 1158 | 1158 | ||
| 1159 | /* If the NIC driver gave us an encapsulated packet | 1159 | skb_pop_rcv_encapsulation(skb); |
| 1160 | * with the encapsulation mark, the device checksummed it | ||
| 1161 | * for us. Otherwise force the upper layers to verify it. | ||
| 1162 | */ | ||
| 1163 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && skb->ip_summed != CHECKSUM_PARTIAL) || | ||
| 1164 | !skb->encapsulation) | ||
| 1165 | skb->ip_summed = CHECKSUM_NONE; | ||
| 1166 | |||
| 1167 | skb->encapsulation = 0; | ||
| 1168 | 1160 | ||
| 1169 | vs->rcv(vs, skb, vxh->vx_vni); | 1161 | vs->rcv(vs, skb, vxh->vx_vni); |
| 1170 | return 0; | 1162 | return 0; |
| @@ -1201,6 +1193,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, | |||
| 1201 | skb_reset_mac_header(skb); | 1193 | skb_reset_mac_header(skb); |
| 1202 | skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); | 1194 | skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); |
| 1203 | skb->protocol = eth_type_trans(skb, vxlan->dev); | 1195 | skb->protocol = eth_type_trans(skb, vxlan->dev); |
| 1196 | skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); | ||
| 1204 | 1197 | ||
| 1205 | /* Ignore packet loops (and multicast echo) */ | 1198 | /* Ignore packet loops (and multicast echo) */ |
| 1206 | if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) | 1199 | if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) |
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index e5a589435e2b..d99800cbdcf3 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h | |||
| @@ -117,6 +117,7 @@ enum { | |||
| 117 | #define NETIF_F_GSO_IPIP __NETIF_F(GSO_IPIP) | 117 | #define NETIF_F_GSO_IPIP __NETIF_F(GSO_IPIP) |
| 118 | #define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT) | 118 | #define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT) |
| 119 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) | 119 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) |
| 120 | #define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) | ||
| 120 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) | 121 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) |
| 121 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) | 122 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) |
| 122 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) | 123 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index abe3de1db932..66f9a04ec270 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -3305,6 +3305,13 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) | |||
| 3305 | BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); | 3305 | BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); |
| 3306 | BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); | 3306 | BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); |
| 3307 | BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); | 3307 | BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); |
| 3308 | BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT)); | ||
| 3309 | BUILD_BUG_ON(SKB_GSO_GRE_CSUM != (NETIF_F_GSO_GRE_CSUM >> NETIF_F_GSO_SHIFT)); | ||
| 3310 | BUILD_BUG_ON(SKB_GSO_IPIP != (NETIF_F_GSO_IPIP >> NETIF_F_GSO_SHIFT)); | ||
| 3311 | BUILD_BUG_ON(SKB_GSO_SIT != (NETIF_F_GSO_SIT >> NETIF_F_GSO_SHIFT)); | ||
| 3312 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); | ||
| 3313 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); | ||
| 3314 | BUILD_BUG_ON(SKB_GSO_MPLS != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT)); | ||
| 3308 | 3315 | ||
| 3309 | return (features & feature) == feature; | 3316 | return (features & feature) == feature; |
| 3310 | } | 3317 | } |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5b5cd3189c98..ec89301ada41 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
| @@ -338,17 +338,18 @@ enum { | |||
| 338 | 338 | ||
| 339 | SKB_GSO_GRE = 1 << 6, | 339 | SKB_GSO_GRE = 1 << 6, |
| 340 | 340 | ||
| 341 | SKB_GSO_IPIP = 1 << 7, | 341 | SKB_GSO_GRE_CSUM = 1 << 7, |
| 342 | 342 | ||
| 343 | SKB_GSO_SIT = 1 << 8, | 343 | SKB_GSO_IPIP = 1 << 8, |
| 344 | 344 | ||
| 345 | SKB_GSO_UDP_TUNNEL = 1 << 9, | 345 | SKB_GSO_SIT = 1 << 9, |
| 346 | 346 | ||
| 347 | SKB_GSO_MPLS = 1 << 10, | 347 | SKB_GSO_UDP_TUNNEL = 1 << 10, |
| 348 | 348 | ||
| 349 | SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11, | 349 | SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11, |
| 350 | 350 | ||
| 351 | SKB_GSO_GRE_CSUM = 1 << 12, | 351 | SKB_GSO_MPLS = 1 << 12, |
| 352 | |||
| 352 | }; | 353 | }; |
| 353 | 354 | ||
| 354 | #if BITS_PER_LONG > 32 | 355 | #if BITS_PER_LONG > 32 |
| @@ -1853,6 +1854,18 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len) | |||
| 1853 | return pskb_may_pull(skb, skb_network_offset(skb) + len); | 1854 | return pskb_may_pull(skb, skb_network_offset(skb) + len); |
| 1854 | } | 1855 | } |
| 1855 | 1856 | ||
| 1857 | static inline void skb_pop_rcv_encapsulation(struct sk_buff *skb) | ||
| 1858 | { | ||
| 1859 | /* Only continue with checksum unnecessary if device indicated | ||
| 1860 | * it is valid across encapsulation (skb->encapsulation was set). | ||
| 1861 | */ | ||
| 1862 | if (skb->ip_summed == CHECKSUM_UNNECESSARY && !skb->encapsulation) | ||
| 1863 | skb->ip_summed = CHECKSUM_NONE; | ||
| 1864 | |||
| 1865 | skb->encapsulation = 0; | ||
| 1866 | skb->csum_valid = 0; | ||
| 1867 | } | ||
| 1868 | |||
| 1856 | /* | 1869 | /* |
| 1857 | * CPUs often take a performance hit when accessing unaligned memory | 1870 | * CPUs often take a performance hit when accessing unaligned memory |
| 1858 | * locations. The actual performance hit varies, it can be small if the | 1871 | * locations. The actual performance hit varies, it can be small if the |
diff --git a/include/net/udp.h b/include/net/udp.h index 2ecfc6e15609..68a1fefe3dfe 100644 --- a/include/net/udp.h +++ b/include/net/udp.h | |||
| @@ -111,7 +111,9 @@ struct sk_buff; | |||
| 111 | */ | 111 | */ |
| 112 | static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) | 112 | static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) |
| 113 | { | 113 | { |
| 114 | return __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov); | 114 | return (UDP_SKB_CB(skb)->cscov == skb->len ? |
| 115 | __skb_checksum_complete(skb) : | ||
| 116 | __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov)); | ||
| 115 | } | 117 | } |
| 116 | 118 | ||
| 117 | static inline int udp_lib_checksum_complete(struct sk_buff *skb) | 119 | static inline int udp_lib_checksum_complete(struct sk_buff *skb) |
diff --git a/net/core/datagram.c b/net/core/datagram.c index 6b1c04ca1d50..488dd1a825c0 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
| @@ -739,22 +739,38 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) | |||
| 739 | __sum16 sum; | 739 | __sum16 sum; |
| 740 | 740 | ||
| 741 | sum = csum_fold(skb_checksum(skb, 0, len, skb->csum)); | 741 | sum = csum_fold(skb_checksum(skb, 0, len, skb->csum)); |
| 742 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum && | 742 | if (likely(!sum)) { |
| 743 | !skb->csum_complete_sw) | 743 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && |
| 744 | netdev_rx_csum_fault(skb->dev); | 744 | !skb->csum_complete_sw) |
| 745 | 745 | netdev_rx_csum_fault(skb->dev); | |
| 746 | /* Save checksum complete for later use */ | 746 | } |
| 747 | skb->csum = sum; | 747 | skb->csum_valid = !sum; |
| 748 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
| 749 | skb->csum_complete_sw = 1; | ||
| 750 | |||
| 751 | return sum; | 748 | return sum; |
| 752 | } | 749 | } |
| 753 | EXPORT_SYMBOL(__skb_checksum_complete_head); | 750 | EXPORT_SYMBOL(__skb_checksum_complete_head); |
| 754 | 751 | ||
| 755 | __sum16 __skb_checksum_complete(struct sk_buff *skb) | 752 | __sum16 __skb_checksum_complete(struct sk_buff *skb) |
| 756 | { | 753 | { |
| 757 | return __skb_checksum_complete_head(skb, skb->len); | 754 | __wsum csum; |
| 755 | __sum16 sum; | ||
| 756 | |||
| 757 | csum = skb_checksum(skb, 0, skb->len, 0); | ||
| 758 | |||
| 759 | /* skb->csum holds pseudo checksum */ | ||
| 760 | sum = csum_fold(csum_add(skb->csum, csum)); | ||
| 761 | if (likely(!sum)) { | ||
| 762 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && | ||
| 763 | !skb->csum_complete_sw) | ||
| 764 | netdev_rx_csum_fault(skb->dev); | ||
| 765 | } | ||
| 766 | |||
| 767 | /* Save full packet checksum */ | ||
| 768 | skb->csum = csum; | ||
| 769 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
| 770 | skb->csum_complete_sw = 1; | ||
| 771 | skb->csum_valid = !sum; | ||
| 772 | |||
| 773 | return sum; | ||
| 758 | } | 774 | } |
| 759 | EXPORT_SYMBOL(__skb_checksum_complete); | 775 | EXPORT_SYMBOL(__skb_checksum_complete); |
| 760 | 776 | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bf92824af3f7..9cd5344fad73 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -689,6 +689,9 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) | |||
| 689 | new->ooo_okay = old->ooo_okay; | 689 | new->ooo_okay = old->ooo_okay; |
| 690 | new->no_fcs = old->no_fcs; | 690 | new->no_fcs = old->no_fcs; |
| 691 | new->encapsulation = old->encapsulation; | 691 | new->encapsulation = old->encapsulation; |
| 692 | new->encap_hdr_csum = old->encap_hdr_csum; | ||
| 693 | new->csum_valid = old->csum_valid; | ||
| 694 | new->csum_complete_sw = old->csum_complete_sw; | ||
| 692 | #ifdef CONFIG_XFRM | 695 | #ifdef CONFIG_XFRM |
| 693 | new->sp = secpath_get(old->sp); | 696 | new->sp = secpath_get(old->sp); |
| 694 | #endif | 697 | #endif |
