|
@@ -97,7 +97,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
|
|
struct in6_addr *gwaddr, int ifindex);
|
|
struct in6_addr *gwaddr, int ifindex);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static struct dst_ops ip6_dst_ops = {
|
|
|
|
|
|
+static struct dst_ops ip6_dst_ops_template = {
|
|
.family = AF_INET6,
|
|
.family = AF_INET6,
|
|
.protocol = __constant_htons(ETH_P_IPV6),
|
|
.protocol = __constant_htons(ETH_P_IPV6),
|
|
.gc = ip6_dst_gc,
|
|
.gc = ip6_dst_gc,
|
|
@@ -113,6 +113,8 @@ static struct dst_ops ip6_dst_ops = {
|
|
.entries = ATOMIC_INIT(0),
|
|
.entries = ATOMIC_INIT(0),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct dst_ops *ip6_dst_ops;
|
|
|
|
+
|
|
static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
|
|
static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
|
|
{
|
|
{
|
|
}
|
|
}
|
|
@@ -137,7 +139,6 @@ static struct rt6_info ip6_null_entry_template = {
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.input = ip6_pkt_discard,
|
|
.input = ip6_pkt_discard,
|
|
.output = ip6_pkt_discard_out,
|
|
.output = ip6_pkt_discard_out,
|
|
- .ops = &ip6_dst_ops,
|
|
|
|
}
|
|
}
|
|
},
|
|
},
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
@@ -160,7 +161,6 @@ struct rt6_info ip6_prohibit_entry_template = {
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.input = ip6_pkt_prohibit,
|
|
.input = ip6_pkt_prohibit,
|
|
.output = ip6_pkt_prohibit_out,
|
|
.output = ip6_pkt_prohibit_out,
|
|
- .ops = &ip6_dst_ops,
|
|
|
|
}
|
|
}
|
|
},
|
|
},
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
@@ -178,7 +178,6 @@ static struct rt6_info ip6_blk_hole_entry_template = {
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
|
|
.input = dst_discard,
|
|
.input = dst_discard,
|
|
.output = dst_discard,
|
|
.output = dst_discard,
|
|
- .ops = &ip6_dst_ops,
|
|
|
|
}
|
|
}
|
|
},
|
|
},
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
|
@@ -191,7 +190,7 @@ static struct rt6_info ip6_blk_hole_entry_template = {
|
|
/* allocate dst with ip6_dst_ops */
|
|
/* allocate dst with ip6_dst_ops */
|
|
static __inline__ struct rt6_info *ip6_dst_alloc(void)
|
|
static __inline__ struct rt6_info *ip6_dst_alloc(void)
|
|
{
|
|
{
|
|
- return (struct rt6_info *)dst_alloc(&ip6_dst_ops);
|
|
|
|
|
|
+ return (struct rt6_info *)dst_alloc(ip6_dst_ops);
|
|
}
|
|
}
|
|
|
|
|
|
static void ip6_dst_destroy(struct dst_entry *dst)
|
|
static void ip6_dst_destroy(struct dst_entry *dst)
|
|
@@ -1000,18 +999,18 @@ static int ip6_dst_gc(struct dst_ops *ops)
|
|
unsigned long now = jiffies;
|
|
unsigned long now = jiffies;
|
|
|
|
|
|
if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) &&
|
|
if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) &&
|
|
- atomic_read(&ip6_dst_ops.entries) <= init_net.ipv6.sysctl.ip6_rt_max_size)
|
|
|
|
|
|
+ atomic_read(&ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
expire++;
|
|
expire++;
|
|
fib6_run_gc(expire, &init_net);
|
|
fib6_run_gc(expire, &init_net);
|
|
last_gc = now;
|
|
last_gc = now;
|
|
- if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
|
|
|
|
|
|
+ if (atomic_read(&ip6_dst_ops->entries) < ip6_dst_ops->gc_thresh)
|
|
expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
|
|
expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
|
|
|
|
|
|
out:
|
|
out:
|
|
expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity;
|
|
expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity;
|
|
- return (atomic_read(&ip6_dst_ops.entries) > init_net.ipv6.sysctl.ip6_rt_max_size);
|
|
|
|
|
|
+ return (atomic_read(&ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size);
|
|
}
|
|
}
|
|
|
|
|
|
/* Clean host part of a prefix. Not necessary in radix tree,
|
|
/* Clean host part of a prefix. Not necessary in radix tree,
|
|
@@ -2408,7 +2407,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
|
|
net->ipv6.rt6_stats->fib_rt_alloc,
|
|
net->ipv6.rt6_stats->fib_rt_alloc,
|
|
net->ipv6.rt6_stats->fib_rt_entries,
|
|
net->ipv6.rt6_stats->fib_rt_entries,
|
|
net->ipv6.rt6_stats->fib_rt_cache,
|
|
net->ipv6.rt6_stats->fib_rt_cache,
|
|
- atomic_read(&ip6_dst_ops.entries),
|
|
|
|
|
|
+ atomic_read(&ip6_dst_ops->entries),
|
|
net->ipv6.rt6_stats->fib_discarded_routes);
|
|
net->ipv6.rt6_stats->fib_discarded_routes);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -2464,7 +2463,7 @@ ctl_table ipv6_route_table_template[] = {
|
|
{
|
|
{
|
|
.ctl_name = NET_IPV6_ROUTE_GC_THRESH,
|
|
.ctl_name = NET_IPV6_ROUTE_GC_THRESH,
|
|
.procname = "gc_thresh",
|
|
.procname = "gc_thresh",
|
|
- .data = &ip6_dst_ops.gc_thresh,
|
|
|
|
|
|
+ .data = &ip6_dst_ops_template.gc_thresh,
|
|
.maxlen = sizeof(int),
|
|
.maxlen = sizeof(int),
|
|
.mode = 0644,
|
|
.mode = 0644,
|
|
.proc_handler = &proc_dointvec,
|
|
.proc_handler = &proc_dointvec,
|
|
@@ -2553,8 +2552,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
|
|
|
|
|
|
if (table) {
|
|
if (table) {
|
|
table[0].data = &net->ipv6.sysctl.flush_delay;
|
|
table[0].data = &net->ipv6.sysctl.flush_delay;
|
|
- /* table[1].data will be handled when we have
|
|
|
|
- routes per namespace */
|
|
|
|
|
|
+ table[1].data = &ip6_dst_ops_template.gc_thresh;
|
|
table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
|
|
table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
|
|
table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
|
|
table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
|
|
table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
|
|
table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
|
|
@@ -2580,6 +2578,7 @@ static int ip6_route_net_init(struct net *net)
|
|
goto out;
|
|
goto out;
|
|
net->ipv6.ip6_null_entry->u.dst.path =
|
|
net->ipv6.ip6_null_entry->u.dst.path =
|
|
(struct dst_entry *)net->ipv6.ip6_null_entry;
|
|
(struct dst_entry *)net->ipv6.ip6_null_entry;
|
|
|
|
+ net->ipv6.ip6_null_entry->u.dst.ops = ip6_dst_ops;
|
|
|
|
|
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
|
|
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
|
|
@@ -2591,6 +2590,7 @@ static int ip6_route_net_init(struct net *net)
|
|
}
|
|
}
|
|
net->ipv6.ip6_prohibit_entry->u.dst.path =
|
|
net->ipv6.ip6_prohibit_entry->u.dst.path =
|
|
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
|
|
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
|
|
|
|
+ net->ipv6.ip6_prohibit_entry->u.dst.ops = ip6_dst_ops;
|
|
|
|
|
|
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
|
|
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
|
|
sizeof(*net->ipv6.ip6_blk_hole_entry),
|
|
sizeof(*net->ipv6.ip6_blk_hole_entry),
|
|
@@ -2602,6 +2602,7 @@ static int ip6_route_net_init(struct net *net)
|
|
}
|
|
}
|
|
net->ipv6.ip6_blk_hole_entry->u.dst.path =
|
|
net->ipv6.ip6_blk_hole_entry->u.dst.path =
|
|
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
|
|
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
|
|
|
|
+ net->ipv6.ip6_blk_hole_entry->u.dst.ops = ip6_dst_ops;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
#ifdef CONFIG_PROC_FS
|
|
@@ -2640,13 +2641,20 @@ int __init ip6_route_init(void)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ip6_dst_ops.kmem_cachep =
|
|
|
|
|
|
+ ip6_dst_ops = kmemdup(&ip6_dst_ops_template,
|
|
|
|
+ sizeof(*ip6_dst_ops), GFP_KERNEL);
|
|
|
|
+ if (!ip6_dst_ops)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ ip6_dst_ops_template.kmem_cachep =
|
|
kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
|
|
kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
|
|
SLAB_HWCACHE_ALIGN, NULL);
|
|
SLAB_HWCACHE_ALIGN, NULL);
|
|
- if (!ip6_dst_ops.kmem_cachep)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ if (!ip6_dst_ops_template.kmem_cachep)
|
|
|
|
+ goto out_ip6_dst_ops;
|
|
|
|
|
|
- ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
|
|
|
|
|
|
+ ip6_dst_ops->kmem_cachep = ip6_dst_ops_template.kmem_cachep;
|
|
|
|
+ ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
|
|
|
|
|
|
ret = register_pernet_subsys(&ip6_route_net_ops);
|
|
ret = register_pernet_subsys(&ip6_route_net_ops);
|
|
if (ret)
|
|
if (ret)
|
|
@@ -2697,7 +2705,9 @@ out_fib6_init:
|
|
out_register_subsys:
|
|
out_register_subsys:
|
|
unregister_pernet_subsys(&ip6_route_net_ops);
|
|
unregister_pernet_subsys(&ip6_route_net_ops);
|
|
out_kmem_cache:
|
|
out_kmem_cache:
|
|
- kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
|
|
|
|
|
|
+ kmem_cache_destroy(ip6_dst_ops->kmem_cachep);
|
|
|
|
+out_ip6_dst_ops:
|
|
|
|
+ kfree(ip6_dst_ops);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2708,5 +2718,6 @@ void ip6_route_cleanup(void)
|
|
xfrm6_fini();
|
|
xfrm6_fini();
|
|
fib6_gc_cleanup();
|
|
fib6_gc_cleanup();
|
|
unregister_pernet_subsys(&ip6_route_net_ops);
|
|
unregister_pernet_subsys(&ip6_route_net_ops);
|
|
- kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
|
|
|
|
|
|
+ kmem_cache_destroy(ip6_dst_ops->kmem_cachep);
|
|
|
|
+ kfree(ip6_dst_ops);
|
|
}
|
|
}
|