Commit 3de232554a91adc74e80dc15c304be806bd7e1f9

Authored by Benjamin Thery
Committed by YOSHIFUJI Hideaki
1 parent 2b5ead4644

ipv6 netns: Address labels per namespace

This pacth makes IPv6 address labels per network namespace.
It keeps the global label tables, ip6addrlbl_table, but
adds a 'net' member to each ip6addrlbl_entry.
This new member is taken into account when matching labels.

Changelog
=========
* v1: Initial version
* v2:
  * Minize the penalty when network namespaces are not configured:
      *  the 'net' member is added only if CONFIG_NET_NS is
         defined. This saves space when network namespaces are not
         configured.
      * 'net' value is retrieved with the inlined function
         ip6addrlbl_net() that always return &init_net when
         CONFIG_NET_NS is not defined.
  * 'net' member in ip6addrlbl_entry renamed to the less generic
    'lbl_net' name (helps code search).

Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

Showing 3 changed files with 84 additions and 37 deletions Side-by-side Diff

include/net/addrconf.h
... ... @@ -121,7 +121,8 @@
121 121 */
122 122 extern int ipv6_addr_label_init(void);
123 123 extern void ipv6_addr_label_rtnl_register(void);
124   -extern u32 ipv6_addr_label(const struct in6_addr *addr,
  124 +extern u32 ipv6_addr_label(struct net *net,
  125 + const struct in6_addr *addr,
125 126 int type, int ifindex);
126 127  
127 128 /*
... ... @@ -964,7 +964,8 @@
964 964 return 0;
965 965 }
966 966  
967   -static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
  967 +static int ipv6_get_saddr_eval(struct net *net,
  968 + struct ipv6_saddr_score *score,
968 969 struct ipv6_saddr_dst *dst,
969 970 int i)
970 971 {
... ... @@ -1043,7 +1044,8 @@
1043 1044 break;
1044 1045 case IPV6_SADDR_RULE_LABEL:
1045 1046 /* Rule 6: Prefer matching label */
1046   - ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
  1047 + ret = ipv6_addr_label(net,
  1048 + &score->ifa->addr, score->addr_type,
1047 1049 score->ifa->idev->dev->ifindex) == dst->label;
1048 1050 break;
1049 1051 #ifdef CONFIG_IPV6_PRIVACY
... ... @@ -1097,7 +1099,7 @@
1097 1099 dst.addr = daddr;
1098 1100 dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
1099 1101 dst.scope = __ipv6_addr_src_scope(dst_type);
1100   - dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
  1102 + dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
1101 1103 dst.prefs = prefs;
1102 1104  
1103 1105 hiscore->rule = -1;
... ... @@ -1165,8 +1167,8 @@
1165 1167 for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
1166 1168 int minihiscore, miniscore;
1167 1169  
1168   - minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
1169   - miniscore = ipv6_get_saddr_eval(score, &dst, i);
  1170 + minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
  1171 + miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
1170 1172  
1171 1173 if (minihiscore > miniscore) {
1172 1174 if (i == IPV6_SADDR_RULE_SCOPE &&
net/ipv6/addrlabel.c
... ... @@ -29,6 +29,9 @@
29 29 */
30 30 struct ip6addrlbl_entry
31 31 {
  32 +#ifdef CONFIG_NET_NS
  33 + struct net *lbl_net;
  34 +#endif
32 35 struct in6_addr prefix;
33 36 int prefixlen;
34 37 int ifindex;
... ... @@ -46,6 +49,16 @@
46 49 u32 seq;
47 50 } ip6addrlbl_table;
48 51  
  52 +static inline
  53 +struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
  54 +{
  55 +#ifdef CONFIG_NET_NS
  56 + return lbl->lbl_net;
  57 +#else
  58 + return &init_net;
  59 +#endif
  60 +}
  61 +
49 62 /*
50 63 * Default policy table (RFC3484 + extensions)
51 64 *
... ... @@ -65,7 +78,7 @@
65 78  
66 79 #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
67 80  
68   -static const __initdata struct ip6addrlbl_init_table
  81 +static const __net_initdata struct ip6addrlbl_init_table
69 82 {
70 83 const struct in6_addr *prefix;
71 84 int prefixlen;
... ... @@ -108,6 +121,9 @@
108 121 /* Object management */
109 122 static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
110 123 {
  124 +#ifdef CONFIG_NET_NS
  125 + release_net(p->lbl_net);
  126 +#endif
111 127 kfree(p);
112 128 }
113 129  
114 130  
... ... @@ -128,10 +144,13 @@
128 144 }
129 145  
130 146 /* Find label */
131   -static int __ip6addrlbl_match(struct ip6addrlbl_entry *p,
  147 +static int __ip6addrlbl_match(struct net *net,
  148 + struct ip6addrlbl_entry *p,
132 149 const struct in6_addr *addr,
133 150 int addrtype, int ifindex)
134 151 {
  152 + if (!net_eq(ip6addrlbl_net(p), net))
  153 + return 0;
135 154 if (p->ifindex && p->ifindex != ifindex)
136 155 return 0;
137 156 if (p->addrtype && p->addrtype != addrtype)
138 157  
139 158  
... ... @@ -141,19 +160,21 @@
141 160 return 1;
142 161 }
143 162  
144   -static struct ip6addrlbl_entry *__ipv6_addr_label(const struct in6_addr *addr,
  163 +static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
  164 + const struct in6_addr *addr,
145 165 int type, int ifindex)
146 166 {
147 167 struct hlist_node *pos;
148 168 struct ip6addrlbl_entry *p;
149 169 hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
150   - if (__ip6addrlbl_match(p, addr, type, ifindex))
  170 + if (__ip6addrlbl_match(net, p, addr, type, ifindex))
151 171 return p;
152 172 }
153 173 return NULL;
154 174 }
155 175  
156   -u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
  176 +u32 ipv6_addr_label(struct net *net,
  177 + const struct in6_addr *addr, int type, int ifindex)
157 178 {
158 179 u32 label;
159 180 struct ip6addrlbl_entry *p;
... ... @@ -161,7 +182,7 @@
161 182 type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
162 183  
163 184 rcu_read_lock();
164   - p = __ipv6_addr_label(addr, type, ifindex);
  185 + p = __ipv6_addr_label(net, addr, type, ifindex);
165 186 label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
166 187 rcu_read_unlock();
167 188  
... ... @@ -174,7 +195,8 @@
174 195 }
175 196  
176 197 /* allocate one entry */
177   -static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
  198 +static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
  199 + const struct in6_addr *prefix,
178 200 int prefixlen, int ifindex,
179 201 u32 label)
180 202 {
... ... @@ -216,6 +238,9 @@
216 238 newp->addrtype = addrtype;
217 239 newp->label = label;
218 240 INIT_HLIST_NODE(&newp->list);
  241 +#ifdef CONFIG_NET_NS
  242 + newp->lbl_net = hold_net(net);
  243 +#endif
219 244 atomic_set(&newp->refcnt, 1);
220 245 return newp;
221 246 }
... ... @@ -237,6 +262,7 @@
237 262 hlist_for_each_entry_safe(p, pos, n,
238 263 &ip6addrlbl_table.head, list) {
239 264 if (p->prefixlen == newp->prefixlen &&
  265 + net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
240 266 p->ifindex == newp->ifindex &&
241 267 ipv6_addr_equal(&p->prefix, &newp->prefix)) {
242 268 if (!replace) {
... ... @@ -261,7 +287,8 @@
261 287 }
262 288  
263 289 /* add a label */
264   -static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
  290 +static int ip6addrlbl_add(struct net *net,
  291 + const struct in6_addr *prefix, int prefixlen,
265 292 int ifindex, u32 label, int replace)
266 293 {
267 294 struct ip6addrlbl_entry *newp;
... ... @@ -274,7 +301,7 @@
274 301 (unsigned int)label,
275 302 replace);
276 303  
277   - newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label);
  304 + newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
278 305 if (IS_ERR(newp))
279 306 return PTR_ERR(newp);
280 307 spin_lock(&ip6addrlbl_table.lock);
... ... @@ -286,7 +313,8 @@
286 313 }
287 314  
288 315 /* remove a label */
289   -static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
  316 +static int __ip6addrlbl_del(struct net *net,
  317 + const struct in6_addr *prefix, int prefixlen,
290 318 int ifindex)
291 319 {
292 320 struct ip6addrlbl_entry *p = NULL;
... ... @@ -300,6 +328,7 @@
300 328  
301 329 hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
302 330 if (p->prefixlen == prefixlen &&
  331 + net_eq(ip6addrlbl_net(p), net) &&
303 332 p->ifindex == ifindex &&
304 333 ipv6_addr_equal(&p->prefix, prefix)) {
305 334 hlist_del_rcu(&p->list);
... ... @@ -311,7 +340,8 @@
311 340 return ret;
312 341 }
313 342  
314   -static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
  343 +static int ip6addrlbl_del(struct net *net,
  344 + const struct in6_addr *prefix, int prefixlen,
315 345 int ifindex)
316 346 {
317 347 struct in6_addr prefix_buf;
318 348  
... ... @@ -324,13 +354,13 @@
324 354  
325 355 ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
326 356 spin_lock(&ip6addrlbl_table.lock);
327   - ret = __ip6addrlbl_del(&prefix_buf, prefixlen, ifindex);
  357 + ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
328 358 spin_unlock(&ip6addrlbl_table.lock);
329 359 return ret;
330 360 }
331 361  
332 362 /* add default label */
333   -static __init int ip6addrlbl_init(void)
  363 +static int __net_init ip6addrlbl_net_init(struct net *net)
334 364 {
335 365 int err = 0;
336 366 int i;
... ... @@ -338,7 +368,8 @@
338 368 ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
339 369  
340 370 for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
341   - int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix,
  371 + int ret = ip6addrlbl_add(net,
  372 + ip6addrlbl_init_table[i].prefix,
342 373 ip6addrlbl_init_table[i].prefixlen,
343 374 0,
344 375 ip6addrlbl_init_table[i].label, 0);
345 376  
... ... @@ -349,11 +380,32 @@
349 380 return err;
350 381 }
351 382  
  383 +static void __net_exit ip6addrlbl_net_exit(struct net *net)
  384 +{
  385 + struct ip6addrlbl_entry *p = NULL;
  386 + struct hlist_node *pos, *n;
  387 +
  388 + /* Remove all labels belonging to the exiting net */
  389 + spin_lock(&ip6addrlbl_table.lock);
  390 + hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
  391 + if (net_eq(ip6addrlbl_net(p), net)) {
  392 + hlist_del_rcu(&p->list);
  393 + ip6addrlbl_put(p);
  394 + }
  395 + }
  396 + spin_unlock(&ip6addrlbl_table.lock);
  397 +}
  398 +
  399 +static struct pernet_operations ipv6_addr_label_ops = {
  400 + .init = ip6addrlbl_net_init,
  401 + .exit = ip6addrlbl_net_exit,
  402 +};
  403 +
352 404 int __init ipv6_addr_label_init(void)
353 405 {
354 406 spin_lock_init(&ip6addrlbl_table.lock);
355 407  
356   - return ip6addrlbl_init();
  408 + return register_pernet_subsys(&ipv6_addr_label_ops);
357 409 }
358 410  
359 411 static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
... ... @@ -371,9 +423,6 @@
371 423 u32 label;
372 424 int err = 0;
373 425  
374   - if (net != &init_net)
375   - return 0;
376   -
377 426 err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
378 427 if (err < 0)
379 428 return err;
... ... @@ -385,7 +434,7 @@
385 434 return -EINVAL;
386 435  
387 436 if (ifal->ifal_index &&
388   - !__dev_get_by_index(&init_net, ifal->ifal_index))
  437 + !__dev_get_by_index(net, ifal->ifal_index))
389 438 return -EINVAL;
390 439  
391 440 if (!tb[IFAL_ADDRESS])
392 441  
... ... @@ -403,12 +452,12 @@
403 452  
404 453 switch(nlh->nlmsg_type) {
405 454 case RTM_NEWADDRLABEL:
406   - err = ip6addrlbl_add(pfx, ifal->ifal_prefixlen,
  455 + err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
407 456 ifal->ifal_index, label,
408 457 nlh->nlmsg_flags & NLM_F_REPLACE);
409 458 break;
410 459 case RTM_DELADDRLABEL:
411   - err = ip6addrlbl_del(pfx, ifal->ifal_prefixlen,
  460 + err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
412 461 ifal->ifal_index);
413 462 break;
414 463 default:
415 464  
... ... @@ -458,12 +507,10 @@
458 507 int idx = 0, s_idx = cb->args[0];
459 508 int err;
460 509  
461   - if (net != &init_net)
462   - return 0;
463   -
464 510 rcu_read_lock();
465 511 hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
466   - if (idx >= s_idx) {
  512 + if (idx >= s_idx &&
  513 + net_eq(ip6addrlbl_net(p), net)) {
467 514 if ((err = ip6addrlbl_fill(skb, p,
468 515 ip6addrlbl_table.seq,
469 516 NETLINK_CB(cb->skb).pid,
... ... @@ -499,9 +546,6 @@
499 546 struct ip6addrlbl_entry *p;
500 547 struct sk_buff *skb;
501 548  
502   - if (net != &init_net)
503   - return 0;
504   -
505 549 err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
506 550 if (err < 0)
507 551 return err;
... ... @@ -513,7 +557,7 @@
513 557 return -EINVAL;
514 558  
515 559 if (ifal->ifal_index &&
516   - !__dev_get_by_index(&init_net, ifal->ifal_index))
  560 + !__dev_get_by_index(net, ifal->ifal_index))
517 561 return -EINVAL;
518 562  
519 563 if (!tb[IFAL_ADDRESS])
... ... @@ -524,7 +568,7 @@
524 568 return -EINVAL;
525 569  
526 570 rcu_read_lock();
527   - p = __ipv6_addr_label(addr, ipv6_addr_type(addr), ifal->ifal_index);
  571 + p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
528 572 if (p && ip6addrlbl_hold(p))
529 573 p = NULL;
530 574 lseq = ip6addrlbl_table.seq;
... ... @@ -552,7 +596,7 @@
552 596 goto out;
553 597 }
554 598  
555   - err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
  599 + err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
556 600 out:
557 601 return err;
558 602 }