ila: Precompute checksum difference for translations
authorTom Herbert <tom@herbertland.com>
Mon, 24 Aug 2015 16:45:42 +0000 (09:45 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 Aug 2015 17:34:40 +0000 (10:34 -0700)
In the ILA build state for LWT compute the checksum difference to apply
to transport checksums that include the IPv6 pseudo header. The
difference is between the route destination (from fib6_config) and the
locator to write.

Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/ila.c

index ffe4dca..678d2df 100644 (file)
@@ -14,6 +14,8 @@
 
 struct ila_params {
        __be64 locator;
+       __be64 locator_match;
+       __wsum csum_diff;
 };
 
 static inline struct ila_params *ila_params_lwtunnel(
@@ -33,6 +35,9 @@ static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to)
 
 static inline __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
 {
+       if (*(__be64 *)&ip6h->daddr == p->locator_match)
+               return p->csum_diff;
+       else
                return compute_csum_diff8((__be32 *)&ip6h->daddr,
                                          (__be32 *)&p->locator);
 }
@@ -130,8 +135,12 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
        struct nlattr *tb[ILA_ATTR_MAX + 1];
        size_t encap_len = sizeof(*p);
        struct lwtunnel_state *newts;
+       const struct fib6_config *cfg6 = cfg;
        int ret;
 
+       if (family != AF_INET6)
+               return -EINVAL;
+
        ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla,
                               ila_nl_policy);
        if (ret < 0)
@@ -149,6 +158,15 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
 
        p->locator = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
 
+       if (cfg6->fc_dst_len > sizeof(__be64)) {
+               /* Precompute checksum difference for translation since we
+                * know both the old locator and the new one.
+                */
+               p->locator_match = *(__be64 *)&cfg6->fc_dst;
+               p->csum_diff = compute_csum_diff8(
+                       (__be32 *)&p->locator_match, (__be32 *)&p->locator);
+       }
+
        newts->type = LWTUNNEL_ENCAP_ILA;
        newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
                        LWTUNNEL_STATE_INPUT_REDIRECT;