]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ila: add checksum neutral map auto
authorTom Herbert <tom@quantonium.net>
Sun, 5 Nov 2017 23:58:23 +0000 (15:58 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Nov 2017 02:20:48 +0000 (11:20 +0900)
Add checksum neutral auto that performs checksum neutral mapping
without using the C-bit. This is enabled by configuration of
a mapping.

The checksum neutral function has been split into
ila_csum_do_neutral_fmt and ila_csum_do_neutral_nofmt. The former
handles the C-bit and includes it in the adjustment value. The latter
just sets the adjustment value on the locator diff only.

Added configuration for checksum neutral map aut in ila_lwt
and ila_xlat.

Signed-off-by: Tom Herbert <tom@quantonium.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/ila.h
net/ipv6/ila/ila_common.c
net/ipv6/ila/ila_lwt.c
net/ipv6/ila/ila_xlat.c

index f54853288f99ce2832c559f44228102d633651a1..0744881dcef3a811e85713e7564b0ea29a3690c0 100644 (file)
@@ -41,6 +41,7 @@ enum {
        ILA_CSUM_ADJUST_TRANSPORT,
        ILA_CSUM_NEUTRAL_MAP,
        ILA_CSUM_NO_ACTION,
+       ILA_CSUM_NEUTRAL_MAP_AUTO,
 };
 
 #endif /* _UAPI_LINUX_ILA_H */
index f1d9248d8b865cc69a336300b719c24fe73ef6be..8c88ecf29b93529acd8014dabdd618362a140922 100644 (file)
@@ -37,8 +37,8 @@ static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
        return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p);
 }
 
-static void ila_csum_do_neutral(struct ila_addr *iaddr,
-                               struct ila_params *p)
+static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr,
+                                   struct ila_params *p)
 {
        __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
        __wsum diff, fval;
@@ -60,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr,
        iaddr->ident.csum_neutral ^= 1;
 }
 
-static void ila_csum_adjust_transport(struct sk_buff *skb,
+static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr,
                                      struct ila_params *p)
 {
+       __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
        __wsum diff;
-       struct ipv6hdr *ip6h = ipv6_hdr(skb);
-       struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
+
+       diff = get_csum_diff_iaddr(iaddr, p);
+
+       *adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust)));
+}
+
+static void ila_csum_adjust_transport(struct sk_buff *skb,
+                                     struct ila_params *p)
+{
        size_t nhoff = sizeof(struct ipv6hdr);
+       struct ipv6hdr *ip6h = ipv6_hdr(skb);
+       __wsum diff;
 
        switch (ip6h->nexthdr) {
        case NEXTHDR_TCP:
@@ -105,36 +115,39 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
                }
                break;
        }
-
-       /* Now change destination address */
-       iaddr->loc = p->locator;
 }
 
 void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
-                            bool set_csum_neutral)
+                            bool sir2ila)
 {
        struct ipv6hdr *ip6h = ipv6_hdr(skb);
        struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
 
-       /* First deal with the transport checksum */
-       if (ila_csum_neutral_set(iaddr->ident)) {
-               /* C-bit is set in the locator indicating that this
-                * is a locator being translated to a SIR address.
-                * Perform (receiver) checksum-neutral translation.
-                */
-               if (!set_csum_neutral)
-                       ila_csum_do_neutral(iaddr, p);
-       } else {
-               switch (p->csum_mode) {
-               case ILA_CSUM_ADJUST_TRANSPORT:
-                       ila_csum_adjust_transport(skb, p);
-                       break;
-               case ILA_CSUM_NEUTRAL_MAP:
-                       ila_csum_do_neutral(iaddr, p);
-                       break;
-               case ILA_CSUM_NO_ACTION:
+       switch (p->csum_mode) {
+       case ILA_CSUM_ADJUST_TRANSPORT:
+               ila_csum_adjust_transport(skb, p);
+               break;
+       case ILA_CSUM_NEUTRAL_MAP:
+               if (sir2ila) {
+                       if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) {
+                               /* Checksum flag should never be
+                                * set in a formatted SIR address.
+                                */
+                               break;
+                       }
+               } else if (!ila_csum_neutral_set(iaddr->ident)) {
+                       /* ILA to SIR translation and C-bit isn't
+                        * set so we're good.
+                        */
                        break;
                }
+               ila_csum_do_neutral_fmt(iaddr, p);
+               break;
+       case ILA_CSUM_NEUTRAL_MAP_AUTO:
+               ila_csum_do_neutral_nofmt(iaddr, p);
+               break;
+       case ILA_CSUM_NO_ACTION:
+               break;
        }
 
        /* Now change destination address */
index 696281b4bca2fb4ccd86d1e047528d7886926325..104af07d83a68fb95f514d14d3926b969059cdb7 100644 (file)
@@ -127,6 +127,7 @@ static int ila_build_state(struct nlattr *nla,
        struct lwtunnel_state *newts;
        const struct fib6_config *cfg6 = cfg;
        struct ila_addr *iaddr;
+       u8 csum_mode = ILA_CSUM_NO_ACTION;
        int ret;
 
        if (family != AF_INET6)
@@ -139,15 +140,6 @@ static int ila_build_state(struct nlattr *nla,
                return -EINVAL;
        }
 
-       iaddr = (struct ila_addr *)&cfg6->fc_dst;
-
-       if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) {
-               /* Don't allow translation for a non-ILA address or checksum
-                * neutral flag to be set.
-                */
-               return -EINVAL;
-       }
-
        ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
        if (ret < 0)
                return ret;
@@ -155,6 +147,19 @@ static int ila_build_state(struct nlattr *nla,
        if (!tb[ILA_ATTR_LOCATOR])
                return -EINVAL;
 
+       iaddr = (struct ila_addr *)&cfg6->fc_dst;
+
+       if (tb[ILA_ATTR_CSUM_MODE])
+               csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]);
+
+       if (csum_mode == ILA_CSUM_NEUTRAL_MAP &&
+           ila_csum_neutral_set(iaddr->ident)) {
+               /* Don't allow translation if checksum neutral bit is
+                * configured and it's set in the SIR address.
+                */
+               return -EINVAL;
+       }
+
        newts = lwtunnel_state_alloc(sizeof(*ilwt));
        if (!newts)
                return -ENOMEM;
@@ -168,17 +173,13 @@ static int ila_build_state(struct nlattr *nla,
 
        p = ila_params_lwtunnel(newts);
 
+       p->csum_mode = csum_mode;
        p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
 
        /* Precompute checksum difference for translation since we
         * know both the old locator and the new one.
         */
        p->locator_match = iaddr->loc;
-       p->csum_diff = compute_csum_diff8(
-               (__be32 *)&p->locator_match, (__be32 *)&p->locator);
-
-       if (tb[ILA_ATTR_CSUM_MODE])
-               p->csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]);
 
        ila_init_saved_csum(p);
 
index 3123b9de91b5eccef3c64e9a8d11e12ddfdcb85f..213259629e668445690068c1295ca68b7e9222cb 100644 (file)
@@ -138,6 +138,8 @@ static int parse_nl_config(struct genl_info *info,
 
        if (info->attrs[ILA_ATTR_CSUM_MODE])
                xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
+       else
+               xp->ip.csum_mode = ILA_CSUM_NO_ACTION;
 
        if (info->attrs[ILA_ATTR_IFINDEX])
                xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
@@ -198,7 +200,7 @@ static void ila_free_cb(void *ptr, void *arg)
        }
 }
 
-static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral);
+static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila);
 
 static unsigned int
 ila_nf_input(void *priv,
@@ -396,7 +398,7 @@ static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
                              (__force u64)ila->xp.ip.locator_match.v64,
                              ILA_ATTR_PAD) ||
            nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) ||
-           nla_put_u32(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode))
+           nla_put_u8(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode))
                return -1;
 
        return 0;
@@ -607,7 +609,7 @@ static struct pernet_operations ila_net_ops = {
        .size = sizeof(struct ila_net),
 };
 
-static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral)
+static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila)
 {
        struct ila_map *ila;
        struct ipv6hdr *ip6h = ipv6_hdr(skb);
@@ -626,7 +628,7 @@ static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral)
 
        ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
        if (ila)
-               ila_update_ipv6_locator(skb, &ila->xp.ip, set_csum_neutral);
+               ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila);
 
        rcu_read_unlock();