aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c56
1 files changed, 35 insertions, 21 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 3c5d6bb3b850..d3f87ceb3408 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1759,6 +1759,10 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
1759 int addr_type; 1759 int addr_type;
1760 int err = -EINVAL; 1760 int err = -EINVAL;
1761 1761
1762 /* RTF_PCPU is an internal flag; can not be set by userspace */
1763 if (cfg->fc_flags & RTF_PCPU)
1764 goto out;
1765
1762 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) 1766 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
1763 goto out; 1767 goto out;
1764#ifndef CONFIG_IPV6_SUBTREES 1768#ifndef CONFIG_IPV6_SUBTREES
@@ -2085,6 +2089,8 @@ static int ip6_route_del(struct fib6_config *cfg)
2085 continue; 2089 continue;
2086 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) 2090 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
2087 continue; 2091 continue;
2092 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2093 continue;
2088 dst_hold(&rt->dst); 2094 dst_hold(&rt->dst);
2089 read_unlock_bh(&table->tb6_lock); 2095 read_unlock_bh(&table->tb6_lock);
2090 2096
@@ -2819,17 +2825,11 @@ static int ip6_route_info_append(struct list_head *rt6_nh_list,
2819 struct rt6_info *rt, struct fib6_config *r_cfg) 2825 struct rt6_info *rt, struct fib6_config *r_cfg)
2820{ 2826{
2821 struct rt6_nh *nh; 2827 struct rt6_nh *nh;
2822 struct rt6_info *rtnh;
2823 int err = -EEXIST; 2828 int err = -EEXIST;
2824 2829
2825 list_for_each_entry(nh, rt6_nh_list, next) { 2830 list_for_each_entry(nh, rt6_nh_list, next) {
2826 /* check if rt6_info already exists */ 2831 /* check if rt6_info already exists */
2827 rtnh = nh->rt6_info; 2832 if (rt6_duplicate_nexthop(nh->rt6_info, rt))
2828
2829 if (rtnh->dst.dev == rt->dst.dev &&
2830 rtnh->rt6i_idev == rt->rt6i_idev &&
2831 ipv6_addr_equal(&rtnh->rt6i_gateway,
2832 &rt->rt6i_gateway))
2833 return err; 2833 return err;
2834 } 2834 }
2835 2835
@@ -3188,7 +3188,8 @@ static int rt6_fill_node(struct net *net,
3188 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) 3188 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3189 goto nla_put_failure; 3189 goto nla_put_failure;
3190 3190
3191 lwtunnel_fill_encap(skb, rt->dst.lwtstate); 3191 if (lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
3192 goto nla_put_failure;
3192 3193
3193 nlmsg_end(skb, nlh); 3194 nlmsg_end(skb, nlh);
3194 return 0; 3195 return 0;
@@ -3354,7 +3355,10 @@ static int ip6_route_dev_notify(struct notifier_block *this,
3354 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 3355 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
3355 struct net *net = dev_net(dev); 3356 struct net *net = dev_net(dev);
3356 3357
3357 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { 3358 if (!(dev->flags & IFF_LOOPBACK))
3359 return NOTIFY_OK;
3360
3361 if (event == NETDEV_REGISTER) {
3358 net->ipv6.ip6_null_entry->dst.dev = dev; 3362 net->ipv6.ip6_null_entry->dst.dev = dev;
3359 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); 3363 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3360#ifdef CONFIG_IPV6_MULTIPLE_TABLES 3364#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -3363,6 +3367,12 @@ static int ip6_route_dev_notify(struct notifier_block *this,
3363 net->ipv6.ip6_blk_hole_entry->dst.dev = dev; 3367 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
3364 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); 3368 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3365#endif 3369#endif
3370 } else if (event == NETDEV_UNREGISTER) {
3371 in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev);
3372#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3373 in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev);
3374 in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev);
3375#endif
3366 } 3376 }
3367 3377
3368 return NOTIFY_OK; 3378 return NOTIFY_OK;
@@ -3669,9 +3679,24 @@ static struct pernet_operations ip6_route_net_late_ops = {
3669 3679
3670static struct notifier_block ip6_route_dev_notifier = { 3680static struct notifier_block ip6_route_dev_notifier = {
3671 .notifier_call = ip6_route_dev_notify, 3681 .notifier_call = ip6_route_dev_notify,
3672 .priority = 0, 3682 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
3673}; 3683};
3674 3684
3685void __init ip6_route_init_special_entries(void)
3686{
3687 /* Registering of the loopback is done before this portion of code,
3688 * the loopback reference in rt6_info will not be taken, do it
3689 * manually for init_net */
3690 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
3691 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3692 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
3693 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
3694 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3695 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
3696 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3697 #endif
3698}
3699
3675int __init ip6_route_init(void) 3700int __init ip6_route_init(void)
3676{ 3701{
3677 int ret; 3702 int ret;
@@ -3698,17 +3723,6 @@ int __init ip6_route_init(void)
3698 3723
3699 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; 3724 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3700 3725
3701 /* Registering of the loopback is done before this portion of code,
3702 * the loopback reference in rt6_info will not be taken, do it
3703 * manually for init_net */
3704 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
3705 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3706 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
3707 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
3708 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3709 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
3710 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3711 #endif
3712 ret = fib6_init(); 3726 ret = fib6_init();
3713 if (ret) 3727 if (ret)
3714 goto out_register_subsys; 3728 goto out_register_subsys;