aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/ila.h1
-rw-r--r--net/ipv6/ila/ila_common.c65
-rw-r--r--net/ipv6/ila/ila_lwt.c29
-rw-r--r--net/ipv6/ila/ila_xlat.c10
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
40static void ila_csum_do_neutral(struct ila_addr *iaddr, 40static 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
63static void ila_csum_adjust_transport(struct sk_buff *skb, 63static 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
74static 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
113void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p, 120void 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