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.
Unified · Split
| @@ -41,6 +41,7 @@ enum { · 40 unmodified lines | ||
| 41 | 41 | ILA_CSUM_ADJUST_TRANSPORT, |
| 42 | 42 | ILA_CSUM_NEUTRAL_MAP, |
| 43 | 43 | ILA_CSUM_NO_ACTION, |
| 44 | + ILA_CSUM_NEUTRAL_MAP_AUTO, | |
| 44 | 45 | }; |
| 45 | 46 | |
| 46 | 47 | #endif /* _UAPI_LINUX_ILA_H */ |
| @@ -37,8 +37,8 @@ static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) · 36 unmodified lines | ||
| 37 | 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, | |
| 41 | − struct ila_params *p) | |
| 40 | +static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr, | |
| 41 | + struct ila_params *p) | |
| 42 | 42 | { |
| 43 | 43 | __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; |
| 44 | 44 | __wsum diff, fval; |
| @@ -60,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr, · 15 unmodified lines | ||
| 60 | 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 | 64 | struct ila_params *p) |
| 65 | 65 | { |
| 66 | + __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; | |
| 66 | 67 | __wsum diff; |
| 67 | − struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 68 | − struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); | |
| 68 | + | |
| 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 | 77 | size_t nhoff = sizeof(struct ipv6hdr); |
| 78 | + struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 79 | + __wsum diff; | |
| 70 | 80 | |
| 71 | 81 | switch (ip6h->nexthdr) { |
| 72 | 82 | case NEXTHDR_TCP: |
| @@ -105,36 +115,39 @@ static void ila_csum_adjust_transport(struct sk_buff *skb, · 32 unmodified lines | ||
| 105 | 115 | } |
| 106 | 116 | break; |
| 107 | 117 | } |
| 108 | − | |
| 109 | − /* Now change destination address */ | |
| 110 | − iaddr->loc = p->locator; | |
| 111 | 118 | } |
| 112 | 119 | |
| 113 | 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 | 123 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
| 117 | 124 | struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); |
| 118 | 125 | |
| 119 | − /* First deal with the transport checksum */ | |
| 120 | − if (ila_csum_neutral_set(iaddr->ident)) { | |
| 121 | − /* C-bit is set in the locator indicating that this | |
| 122 | − * is a locator being translated to a SIR address. | |
| 123 | − * Perform (receiver) checksum-neutral translation. | |
| 124 | − */ | |
| 125 | − if (!set_csum_neutral) | |
| 126 | − ila_csum_do_neutral(iaddr, p); | |
| 127 | − } else { | |
| 128 | − switch (p->csum_mode) { | |
| 129 | − case ILA_CSUM_ADJUST_TRANSPORT: | |
| 130 | − ila_csum_adjust_transport(skb, p); | |
| 131 | − break; | |
| 132 | − case ILA_CSUM_NEUTRAL_MAP: | |
| 133 | − ila_csum_do_neutral(iaddr, p); | |
| 134 | − break; | |
| 135 | − case ILA_CSUM_NO_ACTION: | |
| 126 | + switch (p->csum_mode) { | |
| 127 | + case ILA_CSUM_ADJUST_TRANSPORT: | |
| 128 | + ila_csum_adjust_transport(skb, p); | |
| 129 | + break; | |
| 130 | + case ILA_CSUM_NEUTRAL_MAP: | |
| 131 | + if (sir2ila) { | |
| 132 | + if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) { | |
| 133 | + /* Checksum flag should never be | |
| 134 | + * set in a formatted SIR address. | |
| 135 | + */ | |
| 136 | + break; | |
| 137 | + } | |
| 138 | + } else if (!ila_csum_neutral_set(iaddr->ident)) { | |
| 139 | + /* ILA to SIR translation and C-bit isn't | |
| 140 | + * set so we're good. | |
| 141 | + */ | |
| 136 | 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 | 153 | /* Now change destination address */ |
| @@ -127,6 +127,7 @@ static int ila_build_state(struct nlattr *nla, · 126 unmodified lines | ||
| 127 | 127 | struct lwtunnel_state *newts; |
| 128 | 128 | const struct fib6_config *cfg6 = cfg; |
| 129 | 129 | struct ila_addr *iaddr; |
| 130 | + u8 csum_mode = ILA_CSUM_NO_ACTION; | |
| 130 | 131 | int ret; |
| 131 | 132 | |
| 132 | 133 | if (family != AF_INET6) |
| @@ -139,15 +140,6 @@ static int ila_build_state(struct nlattr *nla, · 6 unmodified lines | ||
| 139 | 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 | 143 | ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); |
| 152 | 144 | if (ret < 0) |
| 153 | 145 | return ret; |
| @@ -155,6 +147,19 @@ static int ila_build_state(struct nlattr *nla, · 1 unmodified line | ||
| 155 | 147 | if (!tb[ILA_ATTR_LOCATOR]) |
| 156 | 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 | 163 | newts = lwtunnel_state_alloc(sizeof(*ilwt)); |
| 159 | 164 | if (!newts) |
| 160 | 165 | return -ENOMEM; |
| @@ -168,17 +173,13 @@ static int ila_build_state(struct nlattr *nla, · 7 unmodified lines | ||
| 168 | 173 | |
| 169 | 174 | p = ila_params_lwtunnel(newts); |
| 170 | 175 | |
| 176 | + p->csum_mode = csum_mode; | |
| 171 | 177 | p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); |
| 172 | 178 | |
| 173 | 179 | /* Precompute checksum difference for translation since we |
| 174 | 180 | * know both the old locator and the new one. |
| 175 | 181 | */ |
| 176 | 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 | 184 | ila_init_saved_csum(p); |
| 184 | 185 | |
| @@ -138,6 +138,8 @@ static int parse_nl_config(struct genl_info *info, · 137 unmodified lines | ||
| 138 | 138 | |
| 139 | 139 | if (info->attrs[ILA_ATTR_CSUM_MODE]) |
| 140 | 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 | 144 | if (info->attrs[ILA_ATTR_IFINDEX]) |
| 143 | 145 | xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]); |
| @@ -198,7 +200,7 @@ static void ila_free_cb(void *ptr, void *arg) · 54 unmodified lines | ||
| 198 | 200 | } |
| 199 | 201 | } |
| 200 | 202 | |
| 201 | −static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral); | |
| 203 | +static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila); | |
| 202 | 204 | |
| 203 | 205 | static unsigned int |
| 204 | 206 | ila_nf_input(void *priv, |
| @@ -396,7 +398,7 @@ static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg) · 191 unmodified lines | ||
| 396 | 398 | (__force u64)ila->xp.ip.locator_match.v64, |
| 397 | 399 | ILA_ATTR_PAD) || |
| 398 | 400 | nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) || |
| 399 | − nla_put_u32(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode)) | |
| 401 | + nla_put_u8(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode)) | |
| 400 | 402 | return -1; |
| 401 | 403 | |
| 402 | 404 | return 0; |
| @@ -607,7 +609,7 @@ static struct pernet_operations ila_net_ops = { · 204 unmodified lines | ||
| 607 | 609 | .size = sizeof(struct ila_net), |
| 608 | 610 | }; |
| 609 | 611 | |
| 610 | −static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral) | |
| 612 | +static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila) | |
| 611 | 613 | { |
| 612 | 614 | struct ila_map *ila; |
| 613 | 615 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
| @@ -626,7 +628,7 @@ static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral) · 12 unmodified lines | ||
| 626 | 628 | |
| 627 | 629 | ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan); |
| 628 | 630 | if (ila) |
| 629 | − ila_update_ipv6_locator(skb, &ila->xp.ip, set_csum_neutral); | |
| 631 | + ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila); | |
| 630 | 632 | |
| 631 | 633 | rcu_read_unlock(); |
| 632 | 634 | |