aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ila
diff options
context:
space:
mode:
authorTom Herbert <tom@herbertland.com>2016-04-23 14:46:56 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-26 01:26:04 -0400
commit642c2c95585dac4ea977140dbb1149fd1e2e7f7f (patch)
treedd683ae12ceeb58b32b3004d48e7038cfe639c14 /net/ipv6/ila
parent351596aad54a7e07de63fde38496656514661b07 (diff)
ila: xlat changes
Change model of xlat to be used only for input where lookup is done on the locator part of an address (comparing to locator_match as key in rhashtable). This is needed for checksum neutral translation which obfuscates the low order 16 bits of the identifier. It also permits hosts to be in muliple ILA domains (each locator can map to a different SIR address). A check is also added to disallow translating non-ILA addresses (check of type in identifier). Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ila')
-rw-r--r--net/ipv6/ila/ila_xlat.c103
1 files changed, 34 insertions, 69 deletions
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 020153bc47f5..2e6cb97aee19 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -11,9 +11,7 @@
11 11
12struct ila_xlat_params { 12struct ila_xlat_params {
13 struct ila_params ip; 13 struct ila_params ip;
14 struct ila_identifier identifier;
15 int ifindex; 14 int ifindex;
16 unsigned int dir;
17}; 15};
18 16
19struct ila_map { 17struct ila_map {
@@ -66,35 +64,29 @@ static __always_inline void __ila_hash_secret_init(void)
66 net_get_random_once(&hashrnd, sizeof(hashrnd)); 64 net_get_random_once(&hashrnd, sizeof(hashrnd));
67} 65}
68 66
69static inline u32 ila_identifier_hash(struct ila_identifier ident) 67static inline u32 ila_locator_hash(struct ila_locator loc)
70{ 68{
71 u32 *v = (u32 *)ident.v32; 69 u32 *v = (u32 *)loc.v32;
72 70
73 return jhash_2words(v[0], v[1], hashrnd); 71 return jhash_2words(v[0], v[1], hashrnd);
74} 72}
75 73
76static inline spinlock_t *ila_get_lock(struct ila_net *ilan, 74static inline spinlock_t *ila_get_lock(struct ila_net *ilan,
77 struct ila_identifier ident) 75 struct ila_locator loc)
78{ 76{
79 return &ilan->locks[ila_identifier_hash(ident) & ilan->locks_mask]; 77 return &ilan->locks[ila_locator_hash(loc) & ilan->locks_mask];
80} 78}
81 79
82static inline int ila_cmp_wildcards(struct ila_map *ila, 80static inline int ila_cmp_wildcards(struct ila_map *ila,
83 struct ila_addr *iaddr, int ifindex, 81 struct ila_addr *iaddr, int ifindex)
84 unsigned int dir)
85{ 82{
86 return (ila->xp.ip.locator_match.v64 && 83 return (ila->xp.ifindex && ila->xp.ifindex != ifindex);
87 ila->xp.ip.locator_match.v64 != iaddr->loc.v64) ||
88 (ila->xp.ifindex && ila->xp.ifindex != ifindex) ||
89 !(ila->xp.dir & dir);
90} 84}
91 85
92static inline int ila_cmp_params(struct ila_map *ila, 86static inline int ila_cmp_params(struct ila_map *ila,
93 struct ila_xlat_params *xp) 87 struct ila_xlat_params *xp)
94{ 88{
95 return (ila->xp.ip.locator_match.v64 != xp->ip.locator_match.v64) || 89 return (ila->xp.ifindex != xp->ifindex);
96 (ila->xp.ifindex != xp->ifindex) ||
97 (ila->xp.dir != xp->dir);
98} 90}
99 91
100static int ila_cmpfn(struct rhashtable_compare_arg *arg, 92static int ila_cmpfn(struct rhashtable_compare_arg *arg,
@@ -102,16 +94,13 @@ static int ila_cmpfn(struct rhashtable_compare_arg *arg,
102{ 94{
103 const struct ila_map *ila = obj; 95 const struct ila_map *ila = obj;
104 96
105 return (ila->xp.identifier.v64 != *(__be64 *)arg->key); 97 return (ila->xp.ip.locator_match.v64 != *(__be64 *)arg->key);
106} 98}
107 99
108static inline int ila_order(struct ila_map *ila) 100static inline int ila_order(struct ila_map *ila)
109{ 101{
110 int score = 0; 102 int score = 0;
111 103
112 if (ila->xp.ip.locator_match.v64)
113 score += 1 << 0;
114
115 if (ila->xp.ifindex) 104 if (ila->xp.ifindex)
116 score += 1 << 1; 105 score += 1 << 1;
117 106
@@ -121,7 +110,7 @@ static inline int ila_order(struct ila_map *ila)
121static const struct rhashtable_params rht_params = { 110static const struct rhashtable_params rht_params = {
122 .nelem_hint = 1024, 111 .nelem_hint = 1024,
123 .head_offset = offsetof(struct ila_map, node), 112 .head_offset = offsetof(struct ila_map, node),
124 .key_offset = offsetof(struct ila_map, xp.identifier), 113 .key_offset = offsetof(struct ila_map, xp.ip.locator_match),
125 .key_len = sizeof(u64), /* identifier */ 114 .key_len = sizeof(u64), /* identifier */
126 .max_size = 1048576, 115 .max_size = 1048576,
127 .min_size = 256, 116 .min_size = 256,
@@ -140,11 +129,9 @@ static struct genl_family ila_nl_family = {
140}; 129};
141 130
142static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { 131static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
143 [ILA_ATTR_IDENTIFIER] = { .type = NLA_U64, },
144 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, 132 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
145 [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, }, 133 [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
146 [ILA_ATTR_IFINDEX] = { .type = NLA_U32, }, 134 [ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
147 [ILA_ATTR_DIR] = { .type = NLA_U32, },
148}; 135};
149 136
150static int parse_nl_config(struct genl_info *info, 137static int parse_nl_config(struct genl_info *info,
@@ -152,10 +139,6 @@ static int parse_nl_config(struct genl_info *info,
152{ 139{
153 memset(xp, 0, sizeof(*xp)); 140 memset(xp, 0, sizeof(*xp));
154 141
155 if (info->attrs[ILA_ATTR_IDENTIFIER])
156 xp->identifier.v64 = (__force __be64)nla_get_u64(
157 info->attrs[ILA_ATTR_IDENTIFIER]);
158
159 if (info->attrs[ILA_ATTR_LOCATOR]) 142 if (info->attrs[ILA_ATTR_LOCATOR])
160 xp->ip.locator.v64 = (__force __be64)nla_get_u64( 143 xp->ip.locator.v64 = (__force __be64)nla_get_u64(
161 info->attrs[ILA_ATTR_LOCATOR]); 144 info->attrs[ILA_ATTR_LOCATOR]);
@@ -167,24 +150,20 @@ static int parse_nl_config(struct genl_info *info,
167 if (info->attrs[ILA_ATTR_IFINDEX]) 150 if (info->attrs[ILA_ATTR_IFINDEX])
168 xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]); 151 xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
169 152
170 if (info->attrs[ILA_ATTR_DIR])
171 xp->dir = nla_get_u32(info->attrs[ILA_ATTR_DIR]);
172
173 return 0; 153 return 0;
174} 154}
175 155
176/* Must be called with rcu readlock */ 156/* Must be called with rcu readlock */
177static inline struct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr, 157static inline struct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr,
178 int ifindex, 158 int ifindex,
179 unsigned int dir,
180 struct ila_net *ilan) 159 struct ila_net *ilan)
181{ 160{
182 struct ila_map *ila; 161 struct ila_map *ila;
183 162
184 ila = rhashtable_lookup_fast(&ilan->rhash_table, &iaddr->ident, 163 ila = rhashtable_lookup_fast(&ilan->rhash_table, &iaddr->loc,
185 rht_params); 164 rht_params);
186 while (ila) { 165 while (ila) {
187 if (!ila_cmp_wildcards(ila, iaddr, ifindex, dir)) 166 if (!ila_cmp_wildcards(ila, iaddr, ifindex))
188 return ila; 167 return ila;
189 ila = rcu_access_pointer(ila->next); 168 ila = rcu_access_pointer(ila->next);
190 } 169 }
@@ -198,7 +177,8 @@ static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *xp,
198{ 177{
199 struct ila_map *ila; 178 struct ila_map *ila;
200 179
201 ila = rhashtable_lookup_fast(&ilan->rhash_table, &xp->identifier, 180 ila = rhashtable_lookup_fast(&ilan->rhash_table,
181 &xp->ip.locator_match,
202 rht_params); 182 rht_params);
203 while (ila) { 183 while (ila) {
204 if (!ila_cmp_params(ila, xp)) 184 if (!ila_cmp_params(ila, xp))
@@ -226,14 +206,14 @@ static void ila_free_cb(void *ptr, void *arg)
226 } 206 }
227} 207}
228 208
229static int ila_xlat_addr(struct sk_buff *skb, int dir); 209static int ila_xlat_addr(struct sk_buff *skb);
230 210
231static unsigned int 211static unsigned int
232ila_nf_input(void *priv, 212ila_nf_input(void *priv,
233 struct sk_buff *skb, 213 struct sk_buff *skb,
234 const struct nf_hook_state *state) 214 const struct nf_hook_state *state)
235{ 215{
236 ila_xlat_addr(skb, ILA_DIR_IN); 216 ila_xlat_addr(skb);
237 return NF_ACCEPT; 217 return NF_ACCEPT;
238} 218}
239 219
@@ -250,7 +230,7 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
250{ 230{
251 struct ila_net *ilan = net_generic(net, ila_net_id); 231 struct ila_net *ilan = net_generic(net, ila_net_id);
252 struct ila_map *ila, *head; 232 struct ila_map *ila, *head;
253 spinlock_t *lock = ila_get_lock(ilan, xp->identifier); 233 spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
254 int err = 0, order; 234 int err = 0, order;
255 235
256 if (!ilan->hooks_registered) { 236 if (!ilan->hooks_registered) {
@@ -271,20 +251,19 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
271 251
272 ila->xp = *xp; 252 ila->xp = *xp;
273 253
274 if (xp->ip.locator_match.v64) { 254 /* Precompute checksum difference for translation since we
275 /* Precompute checksum difference for translation since we 255 * know both the old identifier and the new one.
276 * know both the old identifier and the new one. 256 */
277 */ 257 ila->xp.ip.csum_diff = compute_csum_diff8(
278 ila->xp.ip.csum_diff = compute_csum_diff8( 258 (__be32 *)&xp->ip.locator_match,
279 (__be32 *)&xp->ip.locator_match, 259 (__be32 *)&xp->ip.locator);
280 (__be32 *)&xp->ip.locator);
281 }
282 260
283 order = ila_order(ila); 261 order = ila_order(ila);
284 262
285 spin_lock(lock); 263 spin_lock(lock);
286 264
287 head = rhashtable_lookup_fast(&ilan->rhash_table, &xp->identifier, 265 head = rhashtable_lookup_fast(&ilan->rhash_table,
266 &xp->ip.locator_match,
288 rht_params); 267 rht_params);
289 if (!head) { 268 if (!head) {
290 /* New entry for the rhash_table */ 269 /* New entry for the rhash_table */
@@ -335,13 +314,13 @@ static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
335{ 314{
336 struct ila_net *ilan = net_generic(net, ila_net_id); 315 struct ila_net *ilan = net_generic(net, ila_net_id);
337 struct ila_map *ila, *head, *prev; 316 struct ila_map *ila, *head, *prev;
338 spinlock_t *lock = ila_get_lock(ilan, xp->identifier); 317 spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
339 int err = -ENOENT; 318 int err = -ENOENT;
340 319
341 spin_lock(lock); 320 spin_lock(lock);
342 321
343 head = rhashtable_lookup_fast(&ilan->rhash_table, 322 head = rhashtable_lookup_fast(&ilan->rhash_table,
344 &xp->identifier, rht_params); 323 &xp->ip.locator_match, rht_params);
345 ila = head; 324 ila = head;
346 325
347 prev = NULL; 326 prev = NULL;
@@ -423,17 +402,13 @@ static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
423 402
424static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg) 403static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
425{ 404{
426 if (nla_put_u64_64bit(msg, ILA_ATTR_IDENTIFIER, 405 if (nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
427 (__force u64)ila->xp.identifier.v64,
428 ILA_ATTR_PAD) ||
429 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
430 (__force u64)ila->xp.ip.locator.v64, 406 (__force u64)ila->xp.ip.locator.v64,
431 ILA_ATTR_PAD) || 407 ILA_ATTR_PAD) ||
432 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR_MATCH, 408 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR_MATCH,
433 (__force u64)ila->xp.ip.locator_match.v64, 409 (__force u64)ila->xp.ip.locator_match.v64,
434 ILA_ATTR_PAD) || 410 ILA_ATTR_PAD) ||
435 nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) || 411 nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex))
436 nla_put_u32(msg, ILA_ATTR_DIR, ila->xp.dir))
437 return -1; 412 return -1;
438 413
439 return 0; 414 return 0;
@@ -622,22 +597,24 @@ static struct pernet_operations ila_net_ops = {
622 .size = sizeof(struct ila_net), 597 .size = sizeof(struct ila_net),
623}; 598};
624 599
625static int ila_xlat_addr(struct sk_buff *skb, int dir) 600static int ila_xlat_addr(struct sk_buff *skb)
626{ 601{
627 struct ila_map *ila; 602 struct ila_map *ila;
628 struct ipv6hdr *ip6h = ipv6_hdr(skb); 603 struct ipv6hdr *ip6h = ipv6_hdr(skb);
629 struct net *net = dev_net(skb->dev); 604 struct net *net = dev_net(skb->dev);
630 struct ila_net *ilan = net_generic(net, ila_net_id); 605 struct ila_net *ilan = net_generic(net, ila_net_id);
631 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); 606 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
632 size_t nhoff;
633 607
634 /* Assumes skb contains a valid IPv6 header that is pulled */ 608 /* Assumes skb contains a valid IPv6 header that is pulled */
635 609
636 nhoff = sizeof(struct ipv6hdr); 610 if (!ila_addr_is_ila(iaddr)) {
611 /* Type indicates this is not an ILA address */
612 return 0;
613 }
637 614
638 rcu_read_lock(); 615 rcu_read_lock();
639 616
640 ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, dir, ilan); 617 ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
641 if (ila) 618 if (ila)
642 ila_update_ipv6_locator(skb, &ila->xp.ip); 619 ila_update_ipv6_locator(skb, &ila->xp.ip);
643 620
@@ -646,18 +623,6 @@ static int ila_xlat_addr(struct sk_buff *skb, int dir)
646 return 0; 623 return 0;
647} 624}
648 625
649int ila_xlat_incoming(struct sk_buff *skb)
650{
651 return ila_xlat_addr(skb, ILA_DIR_IN);
652}
653EXPORT_SYMBOL(ila_xlat_incoming);
654
655int ila_xlat_outgoing(struct sk_buff *skb)
656{
657 return ila_xlat_addr(skb, ILA_DIR_OUT);
658}
659EXPORT_SYMBOL(ila_xlat_outgoing);
660
661int ila_xlat_init(void) 626int ila_xlat_init(void)
662{ 627{
663 int ret; 628 int ret;