aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorMatti Vaittinen <matti.vaittinen@nsn.com>2011-11-13 19:15:14 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-14 14:35:33 -0500
commit4a287eba2de395713d8b2b2aeaa69fa086832d34 (patch)
tree96962825dab1262bc46c8d5cc067103faea1d9ea /net/ipv6
parentd71314b4ac88637f9ac2770a9f635babdf6f2ff9 (diff)
IPv6 routing, NLM_F_* flag support: REPLACE and EXCL flags support, warn about missing CREATE flag
The support for NLM_F_* flags at IPv6 routing requests. If NLM_F_CREATE flag is not defined for RTM_NEWROUTE request, warning is printed, but no error is returned. Instead new route is added. Later NLM_F_CREATE may be required for new route creation. Exception is when NLM_F_REPLACE flag is given without NLM_F_CREATE, and no matching route is found. In this case it should be safe to assume that the request issuer is familiar with NLM_F_* flags, and does really not want route to be created. Specifying NLM_F_REPLACE flag will now make the kernel to search for matching route, and replace it with new one. If no route is found and NLM_F_CREATE is specified as well, then new route is created. Also, specifying NLM_F_EXCL will yield returning of error if matching route is found. Patch created against linux-3.2-rc1 Signed-off-by: Matti Vaittinen <Mazziesaccount@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_fib.c109
1 files changed, 94 insertions, 15 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 93718f3db79b..9239d559b41b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -425,7 +425,8 @@ out:
425 425
426static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, 426static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
427 int addrlen, int plen, 427 int addrlen, int plen,
428 int offset) 428 int offset, int allow_create,
429 int replace_required)
429{ 430{
430 struct fib6_node *fn, *in, *ln; 431 struct fib6_node *fn, *in, *ln;
431 struct fib6_node *pn = NULL; 432 struct fib6_node *pn = NULL;
@@ -447,8 +448,12 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
447 * Prefix match 448 * Prefix match
448 */ 449 */
449 if (plen < fn->fn_bit || 450 if (plen < fn->fn_bit ||
450 !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) 451 !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) {
452 if (!allow_create)
453 printk(KERN_WARNING
454 "IPv6: NLM_F_CREATE should be set when creating new route\n");
451 goto insert_above; 455 goto insert_above;
456 }
452 457
453 /* 458 /*
454 * Exact match ? 459 * Exact match ?
@@ -477,10 +482,26 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
477 fn = dir ? fn->right: fn->left; 482 fn = dir ? fn->right: fn->left;
478 } while (fn); 483 } while (fn);
479 484
485 if (replace_required && !allow_create) {
486 /* We should not create new node because
487 * NLM_F_REPLACE was specified without NLM_F_CREATE
488 * I assume it is safe to require NLM_F_CREATE when
489 * REPLACE flag is used! Later we may want to remove the
490 * check for replace_required, because according
491 * to netlink specification, NLM_F_CREATE
492 * MUST be specified if new route is created.
493 * That would keep IPv6 consistent with IPv4
494 */
495 printk(KERN_WARNING
496 "IPv6: NLM_F_CREATE should be set when creating new route - ignoring request\n");
497 return ERR_PTR(-ENOENT);
498 }
480 /* 499 /*
481 * We walked to the bottom of tree. 500 * We walked to the bottom of tree.
482 * Create new leaf node without children. 501 * Create new leaf node without children.
483 */ 502 */
503 if (!allow_create)
504 printk(KERN_WARNING "IPv6: NLM_F_CREATE should be set when creating new route\n");
484 505
485 ln = node_alloc(); 506 ln = node_alloc();
486 507
@@ -614,6 +635,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
614{ 635{
615 struct rt6_info *iter = NULL; 636 struct rt6_info *iter = NULL;
616 struct rt6_info **ins; 637 struct rt6_info **ins;
638 int replace = (NULL != info &&
639 NULL != info->nlh &&
640 (info->nlh->nlmsg_flags&NLM_F_REPLACE));
641 int add = ((NULL == info || NULL == info->nlh) ||
642 (info->nlh->nlmsg_flags&NLM_F_CREATE));
643 int found = 0;
617 644
618 ins = &fn->leaf; 645 ins = &fn->leaf;
619 646
@@ -626,6 +653,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
626 /* 653 /*
627 * Same priority level 654 * Same priority level
628 */ 655 */
656 if (NULL != info->nlh &&
657 (info->nlh->nlmsg_flags&NLM_F_EXCL))
658 return -EEXIST;
659 if (replace) {
660 found++;
661 break;
662 }
629 663
630 if (iter->rt6i_dev == rt->rt6i_dev && 664 if (iter->rt6i_dev == rt->rt6i_dev &&
631 iter->rt6i_idev == rt->rt6i_idev && 665 iter->rt6i_idev == rt->rt6i_idev &&
@@ -655,17 +689,40 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
655 /* 689 /*
656 * insert node 690 * insert node
657 */ 691 */
692 if (!replace) {
693 if (!add)
694 printk(KERN_WARNING "IPv6: NLM_F_CREATE should be set when creating new route\n");
695
696add:
697 rt->dst.rt6_next = iter;
698 *ins = rt;
699 rt->rt6i_node = fn;
700 atomic_inc(&rt->rt6i_ref);
701 inet6_rt_notify(RTM_NEWROUTE, rt, info);
702 info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
703
704 if ((fn->fn_flags & RTN_RTINFO) == 0) {
705 info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
706 fn->fn_flags |= RTN_RTINFO;
707 }
658 708
659 rt->dst.rt6_next = iter; 709 } else {
660 *ins = rt; 710 if (!found) {
661 rt->rt6i_node = fn; 711 if (add)
662 atomic_inc(&rt->rt6i_ref); 712 goto add;
663 inet6_rt_notify(RTM_NEWROUTE, rt, info); 713 printk(KERN_WARNING "IPv6: NLM_F_REPLACE set, but no existing node found!\n");
664 info->nl_net->ipv6.rt6_stats->fib_rt_entries++; 714 return -ENOENT;
665 715 }
666 if ((fn->fn_flags & RTN_RTINFO) == 0) { 716 *ins = rt;
667 info->nl_net->ipv6.rt6_stats->fib_route_nodes++; 717 rt->rt6i_node = fn;
668 fn->fn_flags |= RTN_RTINFO; 718 rt->dst.rt6_next = iter->dst.rt6_next;
719 atomic_inc(&rt->rt6i_ref);
720 inet6_rt_notify(RTM_NEWROUTE, rt, info);
721 rt6_release(iter);
722 if ((fn->fn_flags & RTN_RTINFO) == 0) {
723 info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
724 fn->fn_flags |= RTN_RTINFO;
725 }
669 } 726 }
670 727
671 return 0; 728 return 0;
@@ -696,9 +753,25 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
696{ 753{
697 struct fib6_node *fn, *pn = NULL; 754 struct fib6_node *fn, *pn = NULL;
698 int err = -ENOMEM; 755 int err = -ENOMEM;
756 int allow_create = 1;
757 int replace_required = 0;
758 if (NULL != info && NULL != info->nlh) {
759 if (!(info->nlh->nlmsg_flags&NLM_F_CREATE))
760 allow_create = 0;
761 if ((info->nlh->nlmsg_flags&NLM_F_REPLACE))
762 replace_required = 1;
763 }
764 if (!allow_create && !replace_required)
765 printk(KERN_WARNING "IPv6: RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
699 766
700 fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), 767 fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
701 rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst)); 768 rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst),
769 allow_create, replace_required);
770
771 if (IS_ERR(fn)) {
772 err = PTR_ERR(fn);
773 fn = NULL;
774 }
702 775
703 if (fn == NULL) 776 if (fn == NULL)
704 goto out; 777 goto out;
@@ -736,7 +809,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
736 809
737 sn = fib6_add_1(sfn, &rt->rt6i_src.addr, 810 sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
738 sizeof(struct in6_addr), rt->rt6i_src.plen, 811 sizeof(struct in6_addr), rt->rt6i_src.plen,
739 offsetof(struct rt6_info, rt6i_src)); 812 offsetof(struct rt6_info, rt6i_src),
813 allow_create, replace_required);
740 814
741 if (sn == NULL) { 815 if (sn == NULL) {
742 /* If it is failed, discard just allocated 816 /* If it is failed, discard just allocated
@@ -753,8 +827,13 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
753 } else { 827 } else {
754 sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, 828 sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
755 sizeof(struct in6_addr), rt->rt6i_src.plen, 829 sizeof(struct in6_addr), rt->rt6i_src.plen,
756 offsetof(struct rt6_info, rt6i_src)); 830 offsetof(struct rt6_info, rt6i_src),
831 allow_create, replace_required);
757 832
833 if (IS_ERR(sn)) {
834 err = PTR_ERR(sn);
835 sn = NULL;
836 }
758 if (sn == NULL) 837 if (sn == NULL)
759 goto st_failure; 838 goto st_failure;
760 } 839 }