diff options
| -rw-r--r-- | include/uapi/linux/ila.h | 1 | ||||
| -rw-r--r-- | net/ipv6/ila/ila_common.c | 65 | ||||
| -rw-r--r-- | net/ipv6/ila/ila_lwt.c | 29 | ||||
| -rw-r--r-- | net/ipv6/ila/ila_xlat.c | 10 |
4 files changed, 61 insertions, 44 deletions
diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h index f54853288f99..0744881dcef3 100644 --- a/include/uapi/linux/ila.h +++ b/include/uapi/linux/ila.h | |||
| @@ -41,6 +41,7 @@ enum { | |||
| 41 | ILA_CSUM_ADJUST_TRANSPORT, | 41 | ILA_CSUM_ADJUST_TRANSPORT, |
| 42 | ILA_CSUM_NEUTRAL_MAP, | 42 | ILA_CSUM_NEUTRAL_MAP, |
| 43 | ILA_CSUM_NO_ACTION, | 43 | ILA_CSUM_NO_ACTION, |
| 44 | ILA_CSUM_NEUTRAL_MAP_AUTO, | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | #endif /* _UAPI_LINUX_ILA_H */ | 47 | #endif /* _UAPI_LINUX_ILA_H */ |
diff --git a/net/ipv6/ila/ila_common.c b/net/ipv6/ila/ila_common.c index f1d9248d8b86..8c88ecf29b93 100644 --- a/net/ipv6/ila/ila_common.c +++ b/net/ipv6/ila/ila_common.c | |||
| @@ -37,8 +37,8 @@ static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) | |||
| 37 | return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p); | 37 | return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static void ila_csum_do_neutral(struct ila_addr *iaddr, | 40 | static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr, |
| 41 | struct ila_params *p) | 41 | struct ila_params *p) |
| 42 | { | 42 | { |
| 43 | __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; | 43 | __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; |
| 44 | __wsum diff, fval; | 44 | __wsum diff, fval; |
| @@ -60,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr, | |||
| 60 | iaddr->ident.csum_neutral ^= 1; | 60 | iaddr->ident.csum_neutral ^= 1; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static void ila_csum_adjust_transport(struct sk_buff *skb, | 63 | static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr, |
| 64 | struct ila_params *p) | 64 | struct ila_params *p) |
| 65 | { | 65 | { |
| 66 | __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; | ||
| 66 | __wsum diff; | 67 | __wsum diff; |
| 67 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 68 | |
| 68 | struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); | 69 | diff = get_csum_diff_iaddr(iaddr, p); |
| 70 | |||
| 71 | *adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust))); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void ila_csum_adjust_transport(struct sk_buff *skb, | ||
| 75 | struct ila_params *p) | ||
| 76 | { | ||
| 69 | size_t nhoff = sizeof(struct ipv6hdr); | 77 | size_t nhoff = sizeof(struct ipv6hdr); |
| 78 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
| 79 | __wsum diff; | ||
| 70 | 80 | ||
| 71 | switch (ip6h->nexthdr) { | 81 | switch (ip6h->nexthdr) { |
| 72 | case NEXTHDR_TCP: | 82 | case NEXTHDR_TCP: |
| @@ -105,36 +115,39 @@ static void ila_csum_adjust_transport(struct sk_buff *skb, | |||
| 105 | } | 115 | } |
| 106 | break; | 116 | break; |
| 107 | } | 117 | } |
| 108 | |||
| 109 | /* Now change destination address */ | ||
| 110 | iaddr->loc = p->locator; | ||
| 111 | } | 118 | } |
| 112 | 119 | ||
| 113 | void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p, | 120 | void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p, |
| 114 | bool set_csum_neutral) | 121 | bool sir2ila) |
| 115 | { | 122 | { |
| 116 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 123 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
| 117 | struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); | 124 | struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); |
| 118 | 125 | ||
| 119 | /* First deal with the transport checksum */ | 126 | switch (p->csum_mode) { |
| 120 | if (ila_csum_neutral_set(iaddr->ident)) { | 127 | case ILA_CSUM_ADJUST_TRANSPORT: |
| 121 | /* C-bit is set in the locator indicating that this | 128 | ila_csum_adjust_transport(skb, p); |
| 122 | * is a locator being translated to a SIR address. | 129 | break; |
| 123 | * Perform (receiver) checksum-neutral translation. | 130 | case ILA_CSUM_NEUTRAL_MAP: |
| 124 | */ | 131 | if (sir2ila) { |
| 125 | if (!set_csum_neutral) | 132 | if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) { |
| 126 | ila_csum_do_neutral(iaddr, p); | 133 | /* Checksum flag should never be |
| 127 | } else { | 134 | * set in a formatted SIR address. |
| 128 | switch (p->csum_mode) { | 135 | */ |
| 129 | case ILA_CSUM_ADJUST_TRANSPORT: | 136 | break; |
| 130 | ila_csum_adjust_transport(skb, p); | 137 | } |
| 131 | break; | 138 | } else if (!ila_csum_neutral_set(iaddr->ident)) { |
| 132 | case ILA_CSUM_NEUTRAL_MAP: | 139 | /* ILA to SIR translation and C-bit isn't |
| 133 | ila_csum_do_neutral(iaddr, p); | 140 | * set so we're good. |
| 134 | break; | 141 | */ |
| 135 | case ILA_CSUM_NO_ACTION: | ||
| 136 | break; | 142 | break; |
| 137 | } | 143 | } |
| 144 | ila_csum_do_neutral_fmt(iaddr, p); | ||
| 145 | break; | ||
| 146 | case ILA_CSUM_NEUTRAL_MAP_AUTO: | ||
| 147 | ila_csum_do_neutral_nofmt(iaddr, p); | ||
| 148 | break; | ||
| 149 | case ILA_CSUM_NO_ACTION: | ||
| 150 | break; | ||
| 138 | } | 151 | } |
| 139 | 152 | ||
| 140 | /* Now change destination address */ | 153 | /* Now change destination address */ |
diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c index 696281b4bca2..104af07d83a6 100644 --- a/net/ipv6/ila/ila_lwt.c +++ b/net/ipv6/ila/ila_lwt.c | |||
| @@ -127,6 +127,7 @@ static int ila_build_state(struct nlattr *nla, | |||
| 127 | struct lwtunnel_state *newts; | 127 | struct lwtunnel_state *newts; |
| 128 | const struct fib6_config *cfg6 = cfg; | 128 | const struct fib6_config *cfg6 = cfg; |
| 129 | struct ila_addr *iaddr; | 129 | struct ila_addr *iaddr; |
| 130 | u8 csum_mode = ILA_CSUM_NO_ACTION; | ||
| 130 | int ret; | 131 | int ret; |
| 131 | 132 | ||
| 132 | if (family != AF_INET6) | 133 | if (family != AF_INET6) |
| @@ -139,15 +140,6 @@ static int ila_build_state(struct nlattr *nla, | |||
| 139 | return -EINVAL; | 140 | return -EINVAL; |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | iaddr = (struct ila_addr *)&cfg6->fc_dst; | ||
| 143 | |||
| 144 | if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) { | ||
| 145 | /* Don't allow translation for a non-ILA address or checksum | ||
| 146 | * neutral flag to be set. | ||
| 147 | */ | ||
| 148 | return -EINVAL; | ||
| 149 | } | ||
| 150 | |||
| 151 | ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); | 143 | ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); |
| 152 | if (ret < 0) | 144 | if (ret < 0) |
| 153 | return ret; | 145 | return ret; |
| @@ -155,6 +147,19 @@ static int ila_build_state(struct nlattr *nla, | |||
| 155 | if (!tb[ILA_ATTR_LOCATOR]) | 147 | if (!tb[ILA_ATTR_LOCATOR]) |
| 156 | return -EINVAL; | 148 | return -EINVAL; |
| 157 | 149 | ||
| 150 | iaddr = (struct ila_addr *)&cfg6->fc_dst; | ||
| 151 | |||
| 152 | if (tb[ILA_ATTR_CSUM_MODE]) | ||
| 153 | csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]); | ||
| 154 | |||
| 155 | if (csum_mode == ILA_CSUM_NEUTRAL_MAP && | ||
| 156 | ila_csum_neutral_set(iaddr->ident)) { | ||
| 157 | /* Don't allow translation if checksum neutral bit is | ||
| 158 | * configured and it's set in the SIR address. | ||
| 159 | */ | ||
| 160 | return -EINVAL; | ||
| 161 | } | ||
| 162 | |||
| 158 | newts = lwtunnel_state_alloc(sizeof(*ilwt)); | 163 | newts = lwtunnel_state_alloc(sizeof(*ilwt)); |
| 159 | if (!newts) | 164 | if (!newts) |
| 160 | return -ENOMEM; | 165 | return -ENOMEM; |
| @@ -168,17 +173,13 @@ static int ila_build_state(struct nlattr *nla, | |||
| 168 | 173 | ||
| 169 | p = ila_params_lwtunnel(newts); | 174 | p = ila_params_lwtunnel(newts); |
| 170 | 175 | ||
| 176 | p->csum_mode = csum_mode; | ||
| 171 | p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); | 177 | p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); |
| 172 | 178 | ||
| 173 | /* Precompute checksum difference for translation since we | 179 | /* Precompute checksum difference for translation since we |
| 174 | * know both the old locator and the new one. | 180 | * know both the old locator and the new one. |
| 175 | */ | 181 | */ |
| 176 | p->locator_match = iaddr->loc; | 182 | p->locator_match = iaddr->loc; |
| 177 | p->csum_diff = compute_csum_diff8( | ||
| 178 | (__be32 *)&p->locator_match, (__be32 *)&p->locator); | ||
| 179 | |||
| 180 | if (tb[ILA_ATTR_CSUM_MODE]) | ||
| 181 | p->csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]); | ||
| 182 | 183 | ||
| 183 | ila_init_saved_csum(p); | 184 | ila_init_saved_csum(p); |
| 184 | 185 | ||
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c index 3123b9de91b5..213259629e66 100644 --- a/net/ipv6/ila/ila_xlat.c +++ b/net/ipv6/ila/ila_xlat.c | |||
| @@ -138,6 +138,8 @@ static int parse_nl_config(struct genl_info *info, | |||
| 138 | 138 | ||
| 139 | if (info->attrs[ILA_ATTR_CSUM_MODE]) | 139 | if (info->attrs[ILA_ATTR_CSUM_MODE]) |
| 140 | xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]); | 140 | xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]); |
| 141 | else | ||
| 142 | xp->ip.csum_mode = ILA_CSUM_NO_ACTION; | ||
| 141 | 143 | ||
| 142 | if (info->attrs[ILA_ATTR_IFINDEX]) | 144 | if (info->attrs[ILA_ATTR_IFINDEX]) |
| 143 | |||
