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.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a275c6e1e25c..25661f968f3f 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) {
@@ -2102,6 +2106,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2102 if (rtm->rtm_type == RTN_UNREACHABLE) 2106 if (rtm->rtm_type == RTN_UNREACHABLE)
2103 cfg->fc_flags |= RTF_REJECT; 2107 cfg->fc_flags |= RTF_REJECT;
2104 2108
2109 if (rtm->rtm_type == RTN_LOCAL)
2110 cfg->fc_flags |= RTF_LOCAL;
2111
2105 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; 2112 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
2106 cfg->fc_nlinfo.nlh = nlh; 2113 cfg->fc_nlinfo.nlh = nlh;
2107 cfg->fc_nlinfo.nl_net = sock_net(skb->sk); 2114 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
@@ -2222,6 +2229,8 @@ static int rt6_fill_node(struct net *net,
2222 NLA_PUT_U32(skb, RTA_TABLE, table); 2229 NLA_PUT_U32(skb, RTA_TABLE, table);
2223 if (rt->rt6i_flags&RTF_REJECT) 2230 if (rt->rt6i_flags&RTF_REJECT)
2224 rtm->rtm_type = RTN_UNREACHABLE; 2231 rtm->rtm_type = RTN_UNREACHABLE;
2232 else if (rt->rt6i_flags&RTF_LOCAL)
2233 rtm->rtm_type = RTN_LOCAL;
2225 else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) 2234 else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
2226 rtm->rtm_type = RTN_LOCAL; 2235 rtm->rtm_type = RTN_LOCAL;
2227 else 2236 else
@@ -2516,7 +2525,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2516 net->ipv6.rt6_stats->fib_rt_alloc, 2525 net->ipv6.rt6_stats->fib_rt_alloc,
2517 net->ipv6.rt6_stats->fib_rt_entries, 2526 net->ipv6.rt6_stats->fib_rt_entries,
2518 net->ipv6.rt6_stats->fib_rt_cache, 2527 net->ipv6.rt6_stats->fib_rt_cache,
2519 atomic_read(&net->ipv6.ip6_dst_ops.entries), 2528 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
2520 net->ipv6.rt6_stats->fib_discarded_routes); 2529 net->ipv6.rt6_stats->fib_discarded_routes);
2521 2530
2522 return 0; 2531 return 0;
@@ -2658,11 +2667,14 @@ static int __net_init ip6_route_net_init(struct net *net)
2658 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, 2667 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2659 sizeof(net->ipv6.ip6_dst_ops)); 2668 sizeof(net->ipv6.ip6_dst_ops));
2660 2669
2670 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2671 goto out_ip6_dst_ops;
2672
2661 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 2673 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2662 sizeof(*net->ipv6.ip6_null_entry), 2674 sizeof(*net->ipv6.ip6_null_entry),
2663 GFP_KERNEL); 2675 GFP_KERNEL);
2664 if (!net->ipv6.ip6_null_entry) 2676 if (!net->ipv6.ip6_null_entry)
2665 goto out_ip6_dst_ops; 2677 goto out_ip6_dst_entries;
2666 net->ipv6.ip6_null_entry->dst.path = 2678 net->ipv6.ip6_null_entry->dst.path =
2667 (struct dst_entry *)net->ipv6.ip6_null_entry; 2679 (struct dst_entry *)net->ipv6.ip6_null_entry;
2668 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; 2680 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
@@ -2712,6 +2724,8 @@ out_ip6_prohibit_entry:
2712out_ip6_null_entry: 2724out_ip6_null_entry:
2713 kfree(net->ipv6.ip6_null_entry); 2725 kfree(net->ipv6.ip6_null_entry);
2714#endif 2726#endif
2727out_ip6_dst_entries:
2728 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
2715out_ip6_dst_ops: 2729out_ip6_dst_ops:
2716 goto out; 2730 goto out;
2717} 2731}
@@ -2750,10 +2764,14 @@ int __init ip6_route_init(void)
2750 if (!ip6_dst_ops_template.kmem_cachep) 2764 if (!ip6_dst_ops_template.kmem_cachep)
2751 goto out; 2765 goto out;
2752 2766
2753 ret = register_pernet_subsys(&ip6_route_net_ops); 2767 ret = dst_entries_init(&ip6_dst_blackhole_ops);
2754 if (ret) 2768 if (ret)
2755 goto out_kmem_cache; 2769 goto out_kmem_cache;
2756 2770
2771 ret = register_pernet_subsys(&ip6_route_net_ops);
2772 if (ret)
2773 goto out_dst_entries;
2774
2757 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; 2775 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
2758 2776
2759 /* Registering of the loopback is done before this portion of code, 2777 /* Registering of the loopback is done before this portion of code,
@@ -2800,6 +2818,8 @@ out_fib6_init:
2800 fib6_gc_cleanup(); 2818 fib6_gc_cleanup();
2801out_register_subsys: 2819out_register_subsys:
2802 unregister_pernet_subsys(&ip6_route_net_ops); 2820 unregister_pernet_subsys(&ip6_route_net_ops);
2821out_dst_entries:
2822 dst_entries_destroy(&ip6_dst_blackhole_ops);
2803out_kmem_cache: 2823out_kmem_cache:
2804 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); 2824 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
2805 goto out; 2825 goto out;