History

ila: add checksum neutral map auto

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.

Tom Herbert committed 9 years ago

Commit 84287bb1 parent 80661e74 files · +61 −44Browse files

Unified · Split

4 files
  1. include/uapi/linux/ila.h +1 −0
  2. net/ipv6/ila/ila_common.c +39 −26
  3. net/ipv6/ila/ila_lwt.c +15 −14
  4. net/ipv6/ila/ila_xlat.c +6 −4
include/uapi/linux/ila.h+1−0
@@ -41,6 +41,7 @@ enum { · 40 unmodified lines
4141 ILA_CSUM_ADJUST_TRANSPORT,
4242 ILA_CSUM_NEUTRAL_MAP,
4343 ILA_CSUM_NO_ACTION,
44+ ILA_CSUM_NEUTRAL_MAP_AUTO,
4445 };
4546
4647 #endif /* _UAPI_LINUX_ILA_H */
net/ipv6/ila/ila_common.c+39−26
@@ -37,8 +37,8 @@ static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) · 36 unmodified lines
3737 return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p);
3838 }
3939
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)
4242 {
4343 __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
4444 __wsum diff, fval;
@@ -60,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr, · 15 unmodified lines
6060 iaddr->ident.csum_neutral ^= 1;
6161 }
6262
63−static void ila_csum_adjust_transport(struct sk_buff *skb,
63+static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr,
6464 struct ila_params *p)
6565 {
66+ __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
6667 __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+{
6977 size_t nhoff = sizeof(struct ipv6hdr);
78+ struct ipv6hdr *ip6h = ipv6_hdr(skb);
79+ __wsum diff;
7080
7181 switch (ip6h->nexthdr) {
7282 case NEXTHDR_TCP:
@@ -105,36 +115,39 @@ static void ila_csum_adjust_transport(struct sk_buff *skb, · 32 unmodified lines
105115 }
106116 break;
107117 }
108−
109− /* Now change destination address */
110− iaddr->loc = p->locator;
111118 }
112119
113120 void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
114− bool set_csum_neutral)
121+ bool sir2ila)
115122 {
116123 struct ipv6hdr *ip6h = ipv6_hdr(skb);
117124 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
118125
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+ */
136142 break;
137143 }
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;
138151 }
139152
140153 /* Now change destination address */
net/ipv6/ila/ila_lwt.c+15−14
@@ -127,6 +127,7 @@ static int ila_build_state(struct nlattr *nla, · 126 unmodified lines
127127 struct lwtunnel_state *newts;
128128 const struct fib6_config *cfg6 = cfg;
129129 struct ila_addr *iaddr;
130+ u8 csum_mode = ILA_CSUM_NO_ACTION;
130131 int ret;
131132
132133 if (family != AF_INET6)
@@ -139,15 +140,6 @@ static int ila_build_state(struct nlattr *nla, · 6 unmodified lines
139140 return -EINVAL;
140141 }
141142
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−
151143 ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
152144 if (ret < 0)
153145 return ret;
@@ -155,6 +147,19 @@ static int ila_build_state(struct nlattr *nla, · 1 unmodified line
155147 if (!tb[ILA_ATTR_LOCATOR])
156148 return -EINVAL;
157149
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+
158163 newts = lwtunnel_state_alloc(sizeof(*ilwt));
159164 if (!newts)
160165 return -ENOMEM;
@@ -168,17 +173,13 @@ static int ila_build_state(struct nlattr *nla, · 7 unmodified lines
168173
169174 p = ila_params_lwtunnel(newts);
170175
176+ p->csum_mode = csum_mode;
171177 p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
172178
173179 /* Precompute checksum difference for translation since we
174180 * know both the old locator and the new one.
175181 */
176182 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]);
182183
183184 ila_init_saved_csum(p);
184185
net/ipv6/ila/ila_xlat.c+6−4
@@ -138,6 +138,8 @@ static int parse_nl_config(struct genl_info *info, · 137 unmodified lines
138138
139139 if (info->attrs[ILA_ATTR_CSUM_MODE])
140140 xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
141+ else
142+ xp->ip.csum_mode = ILA_CSUM_NO_ACTION;
141143
142144 if (info->attrs[ILA_ATTR_IFINDEX])
143145 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
198200 }
199201 }
200202
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);
202204
203205 static unsigned int
204206 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
396398 (__force u64)ila->xp.ip.locator_match.v64,
397399 ILA_ATTR_PAD) ||
398400 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))
400402 return -1;
401403
402404 return 0;
@@ -607,7 +609,7 @@ static struct pernet_operations ila_net_ops = { · 204 unmodified lines
607609 .size = sizeof(struct ila_net),
608610 };
609611
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)
611613 {
612614 struct ila_map *ila;
613615 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
626628
627629 ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
628630 if (ila)
629− ila_update_ipv6_locator(skb, &ila->xp.ip, set_csum_neutral);
631+ ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila);
630632
631633 rcu_read_unlock();
632634