aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a275c6e1e25c..96455ffb76fb 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -109,7 +109,6 @@ static struct dst_ops ip6_dst_ops_template = {
109 .link_failure = ip6_link_failure, 109 .link_failure = ip6_link_failure,
110 .update_pmtu = ip6_rt_update_pmtu, 110 .update_pmtu = ip6_rt_update_pmtu,
111 .local_out = __ip6_local_out, 111 .local_out = __ip6_local_out,
112 .entries = ATOMIC_INIT(0),
113}; 112};
114 113
115static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) 114static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -122,7 +121,6 @@ static struct dst_ops ip6_dst_blackhole_ops = {
122 .destroy = ip6_dst_destroy, 121 .destroy = ip6_dst_destroy,
123 .check = ip6_dst_check, 122 .check = ip6_dst_check,
124 .update_pmtu = ip6_rt_blackhole_update_pmtu, 123 .update_pmtu = ip6_rt_blackhole_update_pmtu,
125 .entries = ATOMIC_INIT(0),
126}; 124};
127 125
128static struct rt6_info ip6_null_entry_template = { 126static struct rt6_info ip6_null_entry_template = {
@@ -217,14 +215,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
217 215
218static __inline__ int rt6_check_expired(const struct rt6_info *rt) 216static __inline__ int rt6_check_expired(const struct rt6_info *rt)
219{ 217{
220 return (rt->rt6i_flags & RTF_EXPIRES && 218 return (rt->rt6i_flags & RTF_EXPIRES) &&
221 time_after(jiffies, rt->rt6i_expires)); 219 time_after(jiffies, rt->rt6i_expires);
222} 220}
223 221
224static inline int rt6_need_strict(struct in6_addr *daddr) 222static inline int rt6_need_strict(struct in6_addr *daddr)
225{ 223{
226 return (ipv6_addr_type(daddr) & 224 return ipv6_addr_type(daddr) &
227 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); 225 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
228} 226}
229 227
230/* 228/*
@@ -440,7 +438,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
440 __func__, match); 438 __func__, match);
441 439
442 net = dev_net(rt0->rt6i_dev); 440 net = dev_net(rt0->rt6i_dev);
443 return (match ? match : net->ipv6.ip6_null_entry); 441 return match ? match : net->ipv6.ip6_null_entry;
444} 442}
445 443
446#ifdef CONFIG_IPV6_ROUTE_INFO 444#ifdef CONFIG_IPV6_ROUTE_INFO
@@ -859,7 +857,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
859 857
860 dst_release(*dstp); 858 dst_release(*dstp);
861 *dstp = new; 859 *dstp = new;
862 return (new ? 0 : -ENOMEM); 860 return new ? 0 : -ENOMEM;
863} 861}
864EXPORT_SYMBOL_GPL(ip6_dst_blackhole); 862EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
865 863
@@ -1058,19 +1056,22 @@ static int ip6_dst_gc(struct dst_ops *ops)
1058 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; 1056 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1059 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; 1057 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1060 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; 1058 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
1059 int entries;
1061 1060
1061 entries = dst_entries_get_fast(ops);
1062 if (time_after(rt_last_gc + rt_min_interval, now) && 1062 if (time_after(rt_last_gc + rt_min_interval, now) &&
1063 atomic_read(&ops->entries) <= rt_max_size) 1063 entries <= rt_max_size)
1064 goto out; 1064 goto out;
1065 1065
1066 net->ipv6.ip6_rt_gc_expire++; 1066 net->ipv6.ip6_rt_gc_expire++;
1067 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); 1067 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
1068 net->ipv6.ip6_rt_last_gc = now; 1068 net->ipv6.ip6_rt_last_gc = now;
1069 if (atomic_read(&ops->entries) < ops->gc_thresh) 1069 entries = dst_entries_get_slow(ops);
1070 if (entries < ops->gc_thresh)
1070 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; 1071 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
1071out: 1072out:
1072 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; 1073 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
1073 return (atomic_read(&ops->entries) > rt_max_size); 1074 return entries > rt_max_size;
1074} 1075}
1075 1076
1076/* Clean host part of a prefix. Not necessary in radix tree, 1077/* Clean host part of a prefix. Not necessary in radix tree,
@@ -1169,6 +1170,8 @@ int ip6_route_add(struct fib6_config *cfg)
1169 1170
1170 if (addr_type & IPV6_ADDR_MULTICAST) 1171 if (addr_type & IPV6_ADDR_MULTICAST)
1171 rt->dst.input = ip6_mc_input; 1172 rt->dst.input = ip6_mc_input;
1173 else if (cfg->fc_flags & RTF_LOCAL)
1174 rt->dst.input = ip6_input;
1172 else 1175 else
1173 rt->dst.input = ip6_forward; 1176 rt->dst.input = ip6_forward;
1174 1177
@@ -1190,7 +1193,8 @@ int ip6_route_add(struct fib6_config *cfg)
1190 they would result in kernel looping; promote them to reject routes 1193 they would result in kernel looping; promote them to reject routes
1191 */ 1194 */
1192 if ((cfg->fc_flags & RTF_REJECT) || 1195 if ((cfg->fc_flags & RTF_REJECT) ||
1193 (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { 1196 (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK)
1197 && !(cfg->fc_flags&RTF_LOCAL))) {
1194 /* hold loopback dev/idev if we haven't done so. */ 1198 /* hold loopback dev/idev if we haven't done so. */
1195 if (dev != net->loopback_dev) { 1199 if (dev != net->loopback_dev) {
1196 if (dev) { 1200 if (dev) {
@@ -1941,8 +1945,12 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1941 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); 1945 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
1942 struct neighbour *neigh; 1946 struct neighbour *neigh;
1943 1947
1944 if (rt == NULL) 1948 if (rt == NULL) {
1949 if (net_ratelimit())
1950 pr_warning("IPv6: Maximum number of routes reached,"
1951 " consider increasing route/max_size.\n");
1945 return ERR_PTR(-ENOMEM); 1952 return ERR_PTR(-ENOMEM);
1953 }
1946 1954
1947 dev_hold(net->loopback_dev); 1955 dev_hold(net->loopback_dev);
1948 in6_dev_hold(idev); 1956 in6_dev_hold(idev);
@@ -2102,6 +2110,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2102 if (rtm->rtm_type == RTN_UNREACHABLE) 2110 if (rtm->rtm_type == RTN_UNREACHABLE)
2103 cfg->fc_flags |= RTF_REJECT; 2111 cfg->fc_flags |= RTF_REJECT;
2104 2112
2113 if (rtm->rtm_type == RTN_LOCAL)
2114 cfg->fc_flags |= RTF_LOCAL;
2115
2105 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; 2116 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
2106 cfg->fc_nlinfo.nlh = nlh; 2117 cfg->fc_nlinfo.nlh = nlh;
2107 cfg->fc_nlinfo.nl_net = sock_net(skb->sk); 2118 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
@@ -2222,6 +2233,8 @@ static int rt6_fill_node(struct net *net,
2222 NLA_PUT_U32(skb, RTA_TABLE, table); 2233 NLA_PUT_U32(skb, RTA_TABLE, table);
2223 if (rt->rt6i_flags&RTF_REJECT) 2234 if (rt->rt6i_flags&RTF_REJECT)
2224 rtm->rtm_type = RTN_UNREACHABLE; 2235 rtm->rtm_type = RTN_UNREACHABLE;
2236 else if (rt->rt6i_flags&RTF_LOCAL)
2237 rtm->rtm_type = RTN_LOCAL;
2225 else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) 2238 else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
2226 rtm->rtm_type = RTN_LOCAL; 2239 rtm->rtm_type = RTN_LOCAL;
2227 else 2240 else
@@ -2516,7 +2529,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2516 net->ipv6.rt6_stats->fib_rt_alloc, 2529 net->ipv6.rt6_stats->fib_rt_alloc,
2517 net->ipv6.rt6_stats->fib_rt_entries, 2530 net->ipv6.rt6_stats->fib_rt_entries,
2518 net->ipv6.rt6_stats->fib_rt_cache, 2531 net->ipv6.rt6_stats->fib_rt_cache,
2519 atomic_read(&net->ipv6.ip6_dst_ops.entries), 2532 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
2520 net->ipv6.rt6_stats->fib_discarded_routes); 2533 net->ipv6.rt6_stats->fib_discarded_routes);
2521 2534
2522 return 0; 2535 return 0;
@@ -2658,11 +2671,14 @@ static int __net_init ip6_route_net_init(struct net *net)
2658 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, 2671 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2659 sizeof(net->ipv6.ip6_dst_ops)); 2672 sizeof(net->ipv6.ip6_dst_ops));
2660 2673
2674 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2675 goto out_ip6_dst_ops;
2676
2661 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 2677 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2662 sizeof(*net->ipv6.ip6_null_entry), 2678 sizeof(*net->ipv6.ip6_null_entry),
2663 GFP_KERNEL); 2679 GFP_KERNEL);
2664 if (!net->ipv6.ip6_null_entry) 2680 if (!net->ipv6.ip6_null_entry)
2665 goto out_ip6_dst_ops; 2681 goto out_ip6_dst_entries;
2666 net->ipv6.ip6_null_entry->dst.path = 2682 net->ipv6.ip6_null_entry->dst.path =
2667 (struct dst_entry *)net->ipv6.ip6_null_entry; 2683 (struct dst_entry *)net->ipv6.ip6_null_entry;
2668 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; 2684 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
@@ -2712,6 +2728,8 @@ out_ip6_prohibit_entry:
2712out_ip6_null_entry: 2728out_ip6_null_entry:
2713 kfree(net->ipv6.ip6_null_entry); 2729 kfree(net->ipv6.ip6_null_entry);
2714#endif 2730#endif
2731out_ip6_dst_entries:
2732 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
2715out_ip6_dst_ops: 2733out_ip6_dst_ops:
2716 goto out; 2734 goto out;
2717} 2735}
@@ -2727,6 +2745,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
2727 kfree(net->ipv6.ip6_prohibit_entry); 2745 kfree(net->ipv6.ip6_prohibit_entry);
2728 kfree(net->ipv6.ip6_blk_hole_entry); 2746 kfree(net->ipv6.ip6_blk_hole_entry);
2729#endif 2747#endif
2748 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
2730} 2749}
2731 2750
2732static struct pernet_operations ip6_route_net_ops = { 2751static struct pernet_operations ip6_route_net_ops = {
@@ -2750,10 +2769,14 @@ int __init ip6_route_init(void)
2750 if (!ip6_dst_ops_template.kmem_cachep) 2769 if (!ip6_dst_ops_template.kmem_cachep)
2751 goto out; 2770 goto out;
2752 2771
2753 ret = register_pernet_subsys(&ip6_route_net_ops); 2772 ret = dst_entries_init(&ip6_dst_blackhole_ops);
2754 if (ret) 2773 if (ret)
2755 goto out_kmem_cache; 2774 goto out_kmem_cache;
2756 2775
2776 ret = register_pernet_subsys(&ip6_route_net_ops);
2777 if (ret)
2778 goto out_dst_entries;
2779
2757 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; 2780 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
2758 2781
2759 /* Registering of the loopback is done before this portion of code, 2782 /* Registering of the loopback is done before this portion of code,
@@ -2800,6 +2823,8 @@ out_fib6_init:
2800 fib6_gc_cleanup(); 2823 fib6_gc_cleanup();
2801out_register_subsys: 2824out_register_subsys:
2802 unregister_pernet_subsys(&ip6_route_net_ops); 2825 unregister_pernet_subsys(&ip6_route_net_ops);
2826out_dst_entries:
2827 dst_entries_destroy(&ip6_dst_blackhole_ops);
2803out_kmem_cache: 2828out_kmem_cache:
2804 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); 2829 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
2805 goto out; 2830 goto out;
@@ -2812,5 +2837,6 @@ void ip6_route_cleanup(void)
2812 xfrm6_fini(); 2837 xfrm6_fini();
2813 fib6_gc_cleanup(); 2838 fib6_gc_cleanup();
2814 unregister_pernet_subsys(&ip6_route_net_ops); 2839 unregister_pernet_subsys(&ip6_route_net_ops);
2840 dst_entries_destroy(&ip6_dst_blackhole_ops);
2815 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); 2841 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
2816} 2842}