xref: /openbmc/linux/net/ipv6/addrlabel.c (revision 15e47304)
1 /*
2  * IPv6 Address Label subsystem
3  * for the IPv6 "Default" Source Address Selection
4  *
5  * Copyright (C)2007 USAGI/WIDE Project
6  */
7 /*
8  * Author:
9  * 	YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/list.h>
14 #include <linux/rcupdate.h>
15 #include <linux/in6.h>
16 #include <linux/slab.h>
17 #include <net/addrconf.h>
18 #include <linux/if_addrlabel.h>
19 #include <linux/netlink.h>
20 #include <linux/rtnetlink.h>
21 
22 #if 0
23 #define ADDRLABEL(x...) printk(x)
24 #else
25 #define ADDRLABEL(x...) do { ; } while(0)
26 #endif
27 
28 /*
29  * Policy Table
30  */
31 struct ip6addrlbl_entry
32 {
33 #ifdef CONFIG_NET_NS
34 	struct net *lbl_net;
35 #endif
36 	struct in6_addr prefix;
37 	int prefixlen;
38 	int ifindex;
39 	int addrtype;
40 	u32 label;
41 	struct hlist_node list;
42 	atomic_t refcnt;
43 	struct rcu_head rcu;
44 };
45 
46 static struct ip6addrlbl_table
47 {
48 	struct hlist_head head;
49 	spinlock_t lock;
50 	u32 seq;
51 } ip6addrlbl_table;
52 
53 static inline
54 struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
55 {
56 	return read_pnet(&lbl->lbl_net);
57 }
58 
59 /*
60  * Default policy table (RFC3484 + extensions)
61  *
62  * prefix		addr_type	label
63  * -------------------------------------------------------------------------
64  * ::1/128		LOOPBACK	0
65  * ::/0			N/A		1
66  * 2002::/16		N/A		2
67  * ::/96		COMPATv4	3
68  * ::ffff:0:0/96	V4MAPPED	4
69  * fc00::/7		N/A		5		ULA (RFC 4193)
70  * 2001::/32		N/A		6		Teredo (RFC 4380)
71  * 2001:10::/28		N/A		7		ORCHID (RFC 4843)
72  *
73  * Note: 0xffffffff is used if we do not have any policies.
74  */
75 
76 #define IPV6_ADDR_LABEL_DEFAULT	0xffffffffUL
77 
78 static const __net_initdata struct ip6addrlbl_init_table
79 {
80 	const struct in6_addr *prefix;
81 	int prefixlen;
82 	u32 label;
83 } ip6addrlbl_init_table[] = {
84 	{	/* ::/0 */
85 		.prefix = &in6addr_any,
86 		.label = 1,
87 	},{	/* fc00::/7 */
88 		.prefix = &(struct in6_addr){{{ 0xfc }}},
89 		.prefixlen = 7,
90 		.label = 5,
91 	},{	/* 2002::/16 */
92 		.prefix = &(struct in6_addr){{{ 0x20, 0x02 }}},
93 		.prefixlen = 16,
94 		.label = 2,
95 	},{	/* 2001::/32 */
96 		.prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
97 		.prefixlen = 32,
98 		.label = 6,
99 	},{	/* 2001:10::/28 */
100 		.prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
101 		.prefixlen = 28,
102 		.label = 7,
103 	},{	/* ::ffff:0:0 */
104 		.prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
105 		.prefixlen = 96,
106 		.label = 4,
107 	},{	/* ::/96 */
108 		.prefix = &in6addr_any,
109 		.prefixlen = 96,
110 		.label = 3,
111 	},{	/* ::1/128 */
112 		.prefix = &in6addr_loopback,
113 		.prefixlen = 128,
114 		.label = 0,
115 	}
116 };
117 
118 /* Object management */
119 static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
120 {
121 #ifdef CONFIG_NET_NS
122 	release_net(p->lbl_net);
123 #endif
124 	kfree(p);
125 }
126 
127 static void ip6addrlbl_free_rcu(struct rcu_head *h)
128 {
129 	ip6addrlbl_free(container_of(h, struct ip6addrlbl_entry, rcu));
130 }
131 
132 static bool ip6addrlbl_hold(struct ip6addrlbl_entry *p)
133 {
134 	return atomic_inc_not_zero(&p->refcnt);
135 }
136 
137 static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p)
138 {
139 	if (atomic_dec_and_test(&p->refcnt))
140 		call_rcu(&p->rcu, ip6addrlbl_free_rcu);
141 }
142 
143 /* Find label */
144 static bool __ip6addrlbl_match(struct net *net,
145 			       const struct ip6addrlbl_entry *p,
146 			       const struct in6_addr *addr,
147 			       int addrtype, int ifindex)
148 {
149 	if (!net_eq(ip6addrlbl_net(p), net))
150 		return false;
151 	if (p->ifindex && p->ifindex != ifindex)
152 		return false;
153 	if (p->addrtype && p->addrtype != addrtype)
154 		return false;
155 	if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen))
156 		return false;
157 	return true;
158 }
159 
160 static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
161 						  const struct in6_addr *addr,
162 						  int type, int ifindex)
163 {
164 	struct hlist_node *pos;
165 	struct ip6addrlbl_entry *p;
166 	hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
167 		if (__ip6addrlbl_match(net, p, addr, type, ifindex))
168 			return p;
169 	}
170 	return NULL;
171 }
172 
173 u32 ipv6_addr_label(struct net *net,
174 		    const struct in6_addr *addr, int type, int ifindex)
175 {
176 	u32 label;
177 	struct ip6addrlbl_entry *p;
178 
179 	type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
180 
181 	rcu_read_lock();
182 	p = __ipv6_addr_label(net, addr, type, ifindex);
183 	label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
184 	rcu_read_unlock();
185 
186 	ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n",
187 		  __func__, addr, type, ifindex, label);
188 
189 	return label;
190 }
191 
192 /* allocate one entry */
193 static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
194 						 const struct in6_addr *prefix,
195 						 int prefixlen, int ifindex,
196 						 u32 label)
197 {
198 	struct ip6addrlbl_entry *newp;
199 	int addrtype;
200 
201 	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n",
202 		  __func__, prefix, prefixlen, ifindex, (unsigned int)label);
203 
204 	addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK);
205 
206 	switch (addrtype) {
207 	case IPV6_ADDR_MAPPED:
208 		if (prefixlen > 96)
209 			return ERR_PTR(-EINVAL);
210 		if (prefixlen < 96)
211 			addrtype = 0;
212 		break;
213 	case IPV6_ADDR_COMPATv4:
214 		if (prefixlen != 96)
215 			addrtype = 0;
216 		break;
217 	case IPV6_ADDR_LOOPBACK:
218 		if (prefixlen != 128)
219 			addrtype = 0;
220 		break;
221 	}
222 
223 	newp = kmalloc(sizeof(*newp), GFP_KERNEL);
224 	if (!newp)
225 		return ERR_PTR(-ENOMEM);
226 
227 	ipv6_addr_prefix(&newp->prefix, prefix, prefixlen);
228 	newp->prefixlen = prefixlen;
229 	newp->ifindex = ifindex;
230 	newp->addrtype = addrtype;
231 	newp->label = label;
232 	INIT_HLIST_NODE(&newp->list);
233 #ifdef CONFIG_NET_NS
234 	newp->lbl_net = hold_net(net);
235 #endif
236 	atomic_set(&newp->refcnt, 1);
237 	return newp;
238 }
239 
240 /* add a label */
241 static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
242 {
243 	int ret = 0;
244 
245 	ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
246 			__func__,
247 			newp, replace);
248 
249 	if (hlist_empty(&ip6addrlbl_table.head)) {
250 		hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
251 	} else {
252 		struct hlist_node *pos, *n;
253 		struct ip6addrlbl_entry *p = NULL;
254 		hlist_for_each_entry_safe(p, pos, n,
255 					  &ip6addrlbl_table.head, list) {
256 			if (p->prefixlen == newp->prefixlen &&
257 			    net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
258 			    p->ifindex == newp->ifindex &&
259 			    ipv6_addr_equal(&p->prefix, &newp->prefix)) {
260 				if (!replace) {
261 					ret = -EEXIST;
262 					goto out;
263 				}
264 				hlist_replace_rcu(&p->list, &newp->list);
265 				ip6addrlbl_put(p);
266 				goto out;
267 			} else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
268 				   (p->prefixlen < newp->prefixlen)) {
269 				hlist_add_before_rcu(&newp->list, &p->list);
270 				goto out;
271 			}
272 		}
273 		hlist_add_after_rcu(&p->list, &newp->list);
274 	}
275 out:
276 	if (!ret)
277 		ip6addrlbl_table.seq++;
278 	return ret;
279 }
280 
281 /* add a label */
282 static int ip6addrlbl_add(struct net *net,
283 			  const struct in6_addr *prefix, int prefixlen,
284 			  int ifindex, u32 label, int replace)
285 {
286 	struct ip6addrlbl_entry *newp;
287 	int ret = 0;
288 
289 	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
290 		  __func__, prefix, prefixlen, ifindex, (unsigned int)label,
291 		  replace);
292 
293 	newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
294 	if (IS_ERR(newp))
295 		return PTR_ERR(newp);
296 	spin_lock(&ip6addrlbl_table.lock);
297 	ret = __ip6addrlbl_add(newp, replace);
298 	spin_unlock(&ip6addrlbl_table.lock);
299 	if (ret)
300 		ip6addrlbl_free(newp);
301 	return ret;
302 }
303 
304 /* remove a label */
305 static int __ip6addrlbl_del(struct net *net,
306 			    const struct in6_addr *prefix, int prefixlen,
307 			    int ifindex)
308 {
309 	struct ip6addrlbl_entry *p = NULL;
310 	struct hlist_node *pos, *n;
311 	int ret = -ESRCH;
312 
313 	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
314 		  __func__, prefix, prefixlen, ifindex);
315 
316 	hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
317 		if (p->prefixlen == prefixlen &&
318 		    net_eq(ip6addrlbl_net(p), net) &&
319 		    p->ifindex == ifindex &&
320 		    ipv6_addr_equal(&p->prefix, prefix)) {
321 			hlist_del_rcu(&p->list);
322 			ip6addrlbl_put(p);
323 			ret = 0;
324 			break;
325 		}
326 	}
327 	return ret;
328 }
329 
330 static int ip6addrlbl_del(struct net *net,
331 			  const struct in6_addr *prefix, int prefixlen,
332 			  int ifindex)
333 {
334 	struct in6_addr prefix_buf;
335 	int ret;
336 
337 	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
338 		  __func__, prefix, prefixlen, ifindex);
339 
340 	ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
341 	spin_lock(&ip6addrlbl_table.lock);
342 	ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
343 	spin_unlock(&ip6addrlbl_table.lock);
344 	return ret;
345 }
346 
347 /* add default label */
348 static int __net_init ip6addrlbl_net_init(struct net *net)
349 {
350 	int err = 0;
351 	int i;
352 
353 	ADDRLABEL(KERN_DEBUG "%s\n", __func__);
354 
355 	for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
356 		int ret = ip6addrlbl_add(net,
357 					 ip6addrlbl_init_table[i].prefix,
358 					 ip6addrlbl_init_table[i].prefixlen,
359 					 0,
360 					 ip6addrlbl_init_table[i].label, 0);
361 		/* XXX: should we free all rules when we catch an error? */
362 		if (ret && (!err || err != -ENOMEM))
363 			err = ret;
364 	}
365 	return err;
366 }
367 
368 static void __net_exit ip6addrlbl_net_exit(struct net *net)
369 {
370 	struct ip6addrlbl_entry *p = NULL;
371 	struct hlist_node *pos, *n;
372 
373 	/* Remove all labels belonging to the exiting net */
374 	spin_lock(&ip6addrlbl_table.lock);
375 	hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
376 		if (net_eq(ip6addrlbl_net(p), net)) {
377 			hlist_del_rcu(&p->list);
378 			ip6addrlbl_put(p);
379 		}
380 	}
381 	spin_unlock(&ip6addrlbl_table.lock);
382 }
383 
384 static struct pernet_operations ipv6_addr_label_ops = {
385 	.init = ip6addrlbl_net_init,
386 	.exit = ip6addrlbl_net_exit,
387 };
388 
389 int __init ipv6_addr_label_init(void)
390 {
391 	spin_lock_init(&ip6addrlbl_table.lock);
392 
393 	return register_pernet_subsys(&ipv6_addr_label_ops);
394 }
395 
396 void ipv6_addr_label_cleanup(void)
397 {
398 	unregister_pernet_subsys(&ipv6_addr_label_ops);
399 }
400 
401 static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
402 	[IFAL_ADDRESS]		= { .len = sizeof(struct in6_addr), },
403 	[IFAL_LABEL]		= { .len = sizeof(u32), },
404 };
405 
406 static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
407 			     void *arg)
408 {
409 	struct net *net = sock_net(skb->sk);
410 	struct ifaddrlblmsg *ifal;
411 	struct nlattr *tb[IFAL_MAX+1];
412 	struct in6_addr *pfx;
413 	u32 label;
414 	int err = 0;
415 
416 	err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
417 	if (err < 0)
418 		return err;
419 
420 	ifal = nlmsg_data(nlh);
421 
422 	if (ifal->ifal_family != AF_INET6 ||
423 	    ifal->ifal_prefixlen > 128)
424 		return -EINVAL;
425 
426 	if (!tb[IFAL_ADDRESS])
427 		return -EINVAL;
428 
429 	pfx = nla_data(tb[IFAL_ADDRESS]);
430 	if (!pfx)
431 		return -EINVAL;
432 
433 	if (!tb[IFAL_LABEL])
434 		return -EINVAL;
435 	label = nla_get_u32(tb[IFAL_LABEL]);
436 	if (label == IPV6_ADDR_LABEL_DEFAULT)
437 		return -EINVAL;
438 
439 	switch(nlh->nlmsg_type) {
440 	case RTM_NEWADDRLABEL:
441 		if (ifal->ifal_index &&
442 		    !__dev_get_by_index(net, ifal->ifal_index))
443 			return -EINVAL;
444 
445 		err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
446 				     ifal->ifal_index, label,
447 				     nlh->nlmsg_flags & NLM_F_REPLACE);
448 		break;
449 	case RTM_DELADDRLABEL:
450 		err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
451 				     ifal->ifal_index);
452 		break;
453 	default:
454 		err = -EOPNOTSUPP;
455 	}
456 	return err;
457 }
458 
459 static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
460 			      int prefixlen, int ifindex, u32 lseq)
461 {
462 	struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
463 	ifal->ifal_family = AF_INET6;
464 	ifal->ifal_prefixlen = prefixlen;
465 	ifal->ifal_flags = 0;
466 	ifal->ifal_index = ifindex;
467 	ifal->ifal_seq = lseq;
468 };
469 
470 static int ip6addrlbl_fill(struct sk_buff *skb,
471 			   struct ip6addrlbl_entry *p,
472 			   u32 lseq,
473 			   u32 portid, u32 seq, int event,
474 			   unsigned int flags)
475 {
476 	struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event,
477 					 sizeof(struct ifaddrlblmsg), flags);
478 	if (!nlh)
479 		return -EMSGSIZE;
480 
481 	ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
482 
483 	if (nla_put(skb, IFAL_ADDRESS, 16, &p->prefix) < 0 ||
484 	    nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
485 		nlmsg_cancel(skb, nlh);
486 		return -EMSGSIZE;
487 	}
488 
489 	return nlmsg_end(skb, nlh);
490 }
491 
492 static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
493 {
494 	struct net *net = sock_net(skb->sk);
495 	struct ip6addrlbl_entry *p;
496 	struct hlist_node *pos;
497 	int idx = 0, s_idx = cb->args[0];
498 	int err;
499 
500 	rcu_read_lock();
501 	hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
502 		if (idx >= s_idx &&
503 		    net_eq(ip6addrlbl_net(p), net)) {
504 			if ((err = ip6addrlbl_fill(skb, p,
505 						   ip6addrlbl_table.seq,
506 						   NETLINK_CB(cb->skb).portid,
507 						   cb->nlh->nlmsg_seq,
508 						   RTM_NEWADDRLABEL,
509 						   NLM_F_MULTI)) <= 0)
510 				break;
511 		}
512 		idx++;
513 	}
514 	rcu_read_unlock();
515 	cb->args[0] = idx;
516 	return skb->len;
517 }
518 
519 static inline int ip6addrlbl_msgsize(void)
520 {
521 	return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
522 		+ nla_total_size(16)	/* IFAL_ADDRESS */
523 		+ nla_total_size(4);	/* IFAL_LABEL */
524 }
525 
526 static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
527 			  void *arg)
528 {
529 	struct net *net = sock_net(in_skb->sk);
530 	struct ifaddrlblmsg *ifal;
531 	struct nlattr *tb[IFAL_MAX+1];
532 	struct in6_addr *addr;
533 	u32 lseq;
534 	int err = 0;
535 	struct ip6addrlbl_entry *p;
536 	struct sk_buff *skb;
537 
538 	err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
539 	if (err < 0)
540 		return err;
541 
542 	ifal = nlmsg_data(nlh);
543 
544 	if (ifal->ifal_family != AF_INET6 ||
545 	    ifal->ifal_prefixlen != 128)
546 		return -EINVAL;
547 
548 	if (ifal->ifal_index &&
549 	    !__dev_get_by_index(net, ifal->ifal_index))
550 		return -EINVAL;
551 
552 	if (!tb[IFAL_ADDRESS])
553 		return -EINVAL;
554 
555 	addr = nla_data(tb[IFAL_ADDRESS]);
556 	if (!addr)
557 		return -EINVAL;
558 
559 	rcu_read_lock();
560 	p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
561 	if (p && ip6addrlbl_hold(p))
562 		p = NULL;
563 	lseq = ip6addrlbl_table.seq;
564 	rcu_read_unlock();
565 
566 	if (!p) {
567 		err = -ESRCH;
568 		goto out;
569 	}
570 
571 	if (!(skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL))) {
572 		ip6addrlbl_put(p);
573 		return -ENOBUFS;
574 	}
575 
576 	err = ip6addrlbl_fill(skb, p, lseq,
577 			      NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
578 			      RTM_NEWADDRLABEL, 0);
579 
580 	ip6addrlbl_put(p);
581 
582 	if (err < 0) {
583 		WARN_ON(err == -EMSGSIZE);
584 		kfree_skb(skb);
585 		goto out;
586 	}
587 
588 	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
589 out:
590 	return err;
591 }
592 
593 void __init ipv6_addr_label_rtnl_register(void)
594 {
595 	__rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel,
596 			NULL, NULL);
597 	__rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel,
598 			NULL, NULL);
599 	__rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get,
600 			ip6addrlbl_dump, NULL);
601 }
602 
603