datapath: compat: fix udp checksum calculation
[cascardo/ovs.git] / datapath / linux / compat / udp_tunnel.c
index 0ad3c2a..9cf7286 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/ip6_checksum.h>
 #include <net/ip6_tunnel.h>
 
+#include "gso.h"
 
 int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
                         struct socket **sockp)
@@ -141,32 +142,7 @@ void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
 }
 EXPORT_SYMBOL_GPL(rpl_setup_udp_tunnel_sock);
 
-void ovs_udp_gso(struct sk_buff *skb)
-{
-       int udp_offset = skb_transport_offset(skb);
-       struct udphdr *uh;
-
-       uh = udp_hdr(skb);
-       uh->len = htons(skb->len - udp_offset);
-}
-EXPORT_SYMBOL_GPL(ovs_udp_gso);
-
-void ovs_udp_csum_gso(struct sk_buff *skb)
-{
-       struct iphdr *iph = ip_hdr(skb);
-       int udp_offset = skb_transport_offset(skb);
-
-       ovs_udp_gso(skb);
-
-       /* csum segment if tunnel sets skb with csum. The cleanest way
-        * to do this just to set it up from scratch. */
-       skb->ip_summed = CHECKSUM_NONE;
-       udp_set_csum(false, skb, iph->saddr, iph->daddr,
-                    skb->len - udp_offset);
-}
-EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
-
-int rpl_udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk,
+void rpl_udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk,
                            struct sk_buff *skb, __be32 src, __be32 dst,
                            __u8 tos, __u8 ttl, __be16 df, __be16 src_port,
                            __be16 dst_port, bool xnet, bool nocheck)
@@ -183,8 +159,7 @@ int rpl_udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk,
 
        udp_set_csum(nocheck, skb, src, dst, skb->len);
 
-       return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP,
-                            tos, ttl, df, xnet);
+       iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
 }
 EXPORT_SYMBOL_GPL(rpl_udp_tunnel_xmit_skb);
 
@@ -228,12 +203,13 @@ static void udp6_set_csum(bool nocheck, struct sk_buff *skb,
                skb->csum_offset = offsetof(struct udphdr, check);
                uh->check = ~udp_v6_check(len, saddr, daddr, 0);
        } else {
+               int l4_offset = skb_transport_offset(skb);
                __wsum csum;
 
                BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
 
                uh->check = 0;
-               csum = skb_checksum(skb, 0, len, 0);
+               csum = skb_checksum(skb, l4_offset, len, 0);
                uh->check = udp_v6_check(len, saddr, daddr, csum);
                if (uh->check == 0)
                        uh->check = CSUM_MANGLED_0;
@@ -289,4 +265,40 @@ int rpl_udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
        return 0;
 }
 #endif
+
+void ovs_udp_gso(struct sk_buff *skb)
+{
+       int udp_offset = skb_transport_offset(skb);
+       struct udphdr *uh;
+
+       uh = udp_hdr(skb);
+       uh->len = htons(skb->len - udp_offset);
+}
+EXPORT_SYMBOL_GPL(ovs_udp_gso);
+
+void ovs_udp_csum_gso(struct sk_buff *skb)
+{
+       int udp_offset = skb_transport_offset(skb);
+
+       ovs_udp_gso(skb);
+
+       if (!OVS_GSO_CB(skb)->ipv6) {
+               struct iphdr *iph = ip_hdr(skb);
+
+               /* csum segment if tunnel sets skb with csum. The cleanest way
+                * to do this just to set it up from scratch. */
+               udp_set_csum(false, skb, iph->saddr, iph->daddr,
+                               skb->len - udp_offset);
+#if IS_ENABLED(CONFIG_IPV6)
+       } else {
+               struct ipv6hdr *ip6h;
+
+               ip6h = ipv6_hdr(skb);
+               udp6_set_csum(false, skb, &ip6h->saddr, &ip6h->daddr,
+                             skb->len - udp_offset);
+#endif
+       }
+}
+EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
+
 #endif