[NETNS][IPV6] rt6_info - move rt6_info structure inside the namespace
The rt6_info structures are moved inside the network namespace structure. All references to these structures are now relative to the initial network namespace. Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com> Signed-off-by: Benjamin Thery <benjamin.thery@bull.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
bdb3289f73
commit
8ed6778967
@@ -174,7 +174,8 @@ struct fib6_table {
|
|||||||
#define RT6_TABLE_LOCAL RT6_TABLE_MAIN
|
#define RT6_TABLE_LOCAL RT6_TABLE_MAIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
|
typedef struct rt6_info *(*pol_lookup_t)(struct net *,
|
||||||
|
struct fib6_table *,
|
||||||
struct flowi *, int);
|
struct flowi *, int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -36,11 +36,14 @@ struct netns_ipv6 {
|
|||||||
struct xt_table *ip6table_mangle;
|
struct xt_table *ip6table_mangle;
|
||||||
struct xt_table *ip6table_raw;
|
struct xt_table *ip6table_raw;
|
||||||
#endif
|
#endif
|
||||||
|
struct rt6_info *ip6_null_entry;
|
||||||
struct rt6_statistics *rt6_stats;
|
struct rt6_statistics *rt6_stats;
|
||||||
struct timer_list *ip6_fib_timer;
|
struct timer_list *ip6_fib_timer;
|
||||||
struct hlist_head *fib_table_hash;
|
struct hlist_head *fib_table_hash;
|
||||||
struct fib6_table *fib6_main_tbl;
|
struct fib6_table *fib6_main_tbl;
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
struct rt6_info *ip6_prohibit_entry;
|
||||||
|
struct rt6_info *ip6_blk_hole_entry;
|
||||||
struct fib6_table *fib6_local_tbl;
|
struct fib6_table *fib6_local_tbl;
|
||||||
struct fib_rules_ops *fib6_rules_ops;
|
struct fib_rules_ops *fib6_rules_ops;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -4301,15 +4301,6 @@ int __init addrconf_init(void)
|
|||||||
if (err)
|
if (err)
|
||||||
goto errlo;
|
goto errlo;
|
||||||
|
|
||||||
ip6_null_entry->u.dst.dev = init_net.loopback_dev;
|
|
||||||
ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
||||||
ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
|
|
||||||
ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
|
||||||
ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
|
|
||||||
ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
register_netdevice_notifier(&ipv6_dev_notf);
|
register_netdevice_notifier(&ipv6_dev_notf);
|
||||||
|
|
||||||
addrconf_verify(0);
|
addrconf_verify(0);
|
||||||
|
@@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
|
|||||||
if (arg.result)
|
if (arg.result)
|
||||||
return arg.result;
|
return arg.result;
|
||||||
|
|
||||||
dst_hold(&ip6_null_entry->u.dst);
|
dst_hold(&net->ipv6.ip6_null_entry->u.dst);
|
||||||
return &ip6_null_entry->u.dst;
|
return &net->ipv6.ip6_null_entry->u.dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
|
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
|
||||||
@@ -52,28 +52,29 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
|
|||||||
{
|
{
|
||||||
struct rt6_info *rt = NULL;
|
struct rt6_info *rt = NULL;
|
||||||
struct fib6_table *table;
|
struct fib6_table *table;
|
||||||
|
struct net *net = rule->fr_net;
|
||||||
pol_lookup_t lookup = arg->lookup_ptr;
|
pol_lookup_t lookup = arg->lookup_ptr;
|
||||||
|
|
||||||
switch (rule->action) {
|
switch (rule->action) {
|
||||||
case FR_ACT_TO_TBL:
|
case FR_ACT_TO_TBL:
|
||||||
break;
|
break;
|
||||||
case FR_ACT_UNREACHABLE:
|
case FR_ACT_UNREACHABLE:
|
||||||
rt = ip6_null_entry;
|
rt = net->ipv6.ip6_null_entry;
|
||||||
goto discard_pkt;
|
goto discard_pkt;
|
||||||
default:
|
default:
|
||||||
case FR_ACT_BLACKHOLE:
|
case FR_ACT_BLACKHOLE:
|
||||||
rt = ip6_blk_hole_entry;
|
rt = net->ipv6.ip6_blk_hole_entry;
|
||||||
goto discard_pkt;
|
goto discard_pkt;
|
||||||
case FR_ACT_PROHIBIT:
|
case FR_ACT_PROHIBIT:
|
||||||
rt = ip6_prohibit_entry;
|
rt = net->ipv6.ip6_prohibit_entry;
|
||||||
goto discard_pkt;
|
goto discard_pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
table = fib6_get_table(rule->fr_net, rule->table);
|
table = fib6_get_table(net, rule->table);
|
||||||
if (table)
|
if (table)
|
||||||
rt = lookup(table, flp, flags);
|
rt = lookup(net, table, flp, flags);
|
||||||
|
|
||||||
if (rt != ip6_null_entry) {
|
if (rt != net->ipv6.ip6_null_entry) {
|
||||||
struct fib6_rule *r = (struct fib6_rule *)rule;
|
struct fib6_rule *r = (struct fib6_rule *)rule;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -79,8 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock);
|
|||||||
|
|
||||||
static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
|
static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
|
||||||
struct rt6_info *rt);
|
struct rt6_info *rt);
|
||||||
static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
|
static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
|
||||||
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
|
static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
|
||||||
static int fib6_walk(struct fib6_walker_t *w);
|
static int fib6_walk(struct fib6_walker_t *w);
|
||||||
static int fib6_walk_continue(struct fib6_walker_t *w);
|
static int fib6_walk_continue(struct fib6_walker_t *w);
|
||||||
|
|
||||||
@@ -193,14 +193,14 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
|
|||||||
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
|
||||||
static struct fib6_table *fib6_alloc_table(u32 id)
|
static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
|
||||||
{
|
{
|
||||||
struct fib6_table *table;
|
struct fib6_table *table;
|
||||||
|
|
||||||
table = kzalloc(sizeof(*table), GFP_ATOMIC);
|
table = kzalloc(sizeof(*table), GFP_ATOMIC);
|
||||||
if (table != NULL) {
|
if (table != NULL) {
|
||||||
table->tb6_id = id;
|
table->tb6_id = id;
|
||||||
table->tb6_root.leaf = ip6_null_entry;
|
table->tb6_root.leaf = net->ipv6.ip6_null_entry;
|
||||||
table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id)
|
|||||||
if (tb)
|
if (tb)
|
||||||
return tb;
|
return tb;
|
||||||
|
|
||||||
tb = fib6_alloc_table(id);
|
tb = fib6_alloc_table(net, id);
|
||||||
if (tb != NULL)
|
if (tb != NULL)
|
||||||
fib6_link_table(net, tb);
|
fib6_link_table(net, tb);
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
|
|||||||
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
|
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
|
||||||
int flags, pol_lookup_t lookup)
|
int flags, pol_lookup_t lookup)
|
||||||
{
|
{
|
||||||
return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags);
|
return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fib6_tables_init(struct net *net)
|
static void fib6_tables_init(struct net *net)
|
||||||
@@ -717,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
|
|||||||
if (sfn == NULL)
|
if (sfn == NULL)
|
||||||
goto st_failure;
|
goto st_failure;
|
||||||
|
|
||||||
sfn->leaf = ip6_null_entry;
|
sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
|
||||||
atomic_inc(&ip6_null_entry->rt6i_ref);
|
atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
|
||||||
sfn->fn_flags = RTN_ROOT;
|
sfn->fn_flags = RTN_ROOT;
|
||||||
sfn->fn_sernum = fib6_new_sernum();
|
sfn->fn_sernum = fib6_new_sernum();
|
||||||
|
|
||||||
@@ -773,11 +773,11 @@ out:
|
|||||||
* super-tree leaf node we have to find a new one for it.
|
* super-tree leaf node we have to find a new one for it.
|
||||||
*/
|
*/
|
||||||
if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
|
if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
|
||||||
pn->leaf = fib6_find_prefix(pn);
|
pn->leaf = fib6_find_prefix(info->nl_net, pn);
|
||||||
#if RT6_DEBUG >= 2
|
#if RT6_DEBUG >= 2
|
||||||
if (!pn->leaf) {
|
if (!pn->leaf) {
|
||||||
BUG_TRAP(pn->leaf != NULL);
|
BUG_TRAP(pn->leaf != NULL);
|
||||||
pn->leaf = ip6_null_entry;
|
pn->leaf = info->nl_net->ipv6.ip6_null_entry;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
atomic_inc(&pn->leaf->rt6i_ref);
|
atomic_inc(&pn->leaf->rt6i_ref);
|
||||||
@@ -793,7 +793,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
st_failure:
|
st_failure:
|
||||||
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
|
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
|
||||||
fib6_repair_tree(fn);
|
fib6_repair_tree(info->nl_net, fn);
|
||||||
dst_free(&rt->u.dst);
|
dst_free(&rt->u.dst);
|
||||||
return err;
|
return err;
|
||||||
#endif
|
#endif
|
||||||
@@ -959,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
|
static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
|
||||||
{
|
{
|
||||||
if (fn->fn_flags&RTN_ROOT)
|
if (fn->fn_flags&RTN_ROOT)
|
||||||
return ip6_null_entry;
|
return net->ipv6.ip6_null_entry;
|
||||||
|
|
||||||
while(fn) {
|
while(fn) {
|
||||||
if(fn->left)
|
if(fn->left)
|
||||||
@@ -981,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
|
|||||||
* is the node we want to try and remove.
|
* is the node we want to try and remove.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
|
static struct fib6_node *fib6_repair_tree(struct net *net,
|
||||||
|
struct fib6_node *fn)
|
||||||
{
|
{
|
||||||
int children;
|
int children;
|
||||||
int nstate;
|
int nstate;
|
||||||
@@ -1008,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
|
|||||||
|| (children && fn->fn_flags&RTN_ROOT)
|
|| (children && fn->fn_flags&RTN_ROOT)
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
fn->leaf = fib6_find_prefix(fn);
|
fn->leaf = fib6_find_prefix(net, fn);
|
||||||
#if RT6_DEBUG >= 2
|
#if RT6_DEBUG >= 2
|
||||||
if (fn->leaf==NULL) {
|
if (fn->leaf==NULL) {
|
||||||
BUG_TRAP(fn->leaf);
|
BUG_TRAP(fn->leaf);
|
||||||
fn->leaf = ip6_null_entry;
|
fn->leaf = net->ipv6.ip6_null_entry;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
atomic_inc(&fn->leaf->rt6i_ref);
|
atomic_inc(&fn->leaf->rt6i_ref);
|
||||||
@@ -1117,7 +1118,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
|
|||||||
if (fn->leaf == NULL) {
|
if (fn->leaf == NULL) {
|
||||||
fn->fn_flags &= ~RTN_RTINFO;
|
fn->fn_flags &= ~RTN_RTINFO;
|
||||||
net->ipv6.rt6_stats->fib_route_nodes--;
|
net->ipv6.rt6_stats->fib_route_nodes--;
|
||||||
fn = fib6_repair_tree(fn);
|
fn = fib6_repair_tree(net, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_read(&rt->rt6i_ref) != 1) {
|
if (atomic_read(&rt->rt6i_ref) != 1) {
|
||||||
@@ -1129,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
|
|||||||
*/
|
*/
|
||||||
while (fn) {
|
while (fn) {
|
||||||
if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
|
if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
|
||||||
fn->leaf = fib6_find_prefix(fn);
|
fn->leaf = fib6_find_prefix(net, fn);
|
||||||
atomic_inc(&fn->leaf->rt6i_ref);
|
atomic_inc(&fn->leaf->rt6i_ref);
|
||||||
rt6_release(rt);
|
rt6_release(rt);
|
||||||
}
|
}
|
||||||
@@ -1145,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
|
|||||||
|
|
||||||
int fib6_del(struct rt6_info *rt, struct nl_info *info)
|
int fib6_del(struct rt6_info *rt, struct nl_info *info)
|
||||||
{
|
{
|
||||||
|
struct net *net = info->nl_net;
|
||||||
struct fib6_node *fn = rt->rt6i_node;
|
struct fib6_node *fn = rt->rt6i_node;
|
||||||
struct rt6_info **rtp;
|
struct rt6_info **rtp;
|
||||||
|
|
||||||
@@ -1154,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (fn == NULL || rt == ip6_null_entry)
|
if (fn == NULL || rt == net->ipv6.ip6_null_entry)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
BUG_TRAP(fn->fn_flags&RTN_RTINFO);
|
BUG_TRAP(fn->fn_flags&RTN_RTINFO);
|
||||||
@@ -1501,7 +1503,7 @@ static int fib6_net_init(struct net *net)
|
|||||||
goto out_fib_table_hash;
|
goto out_fib_table_hash;
|
||||||
|
|
||||||
net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
|
net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
|
||||||
net->ipv6.fib6_main_tbl->tb6_root.leaf = ip6_null_entry;
|
net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
|
||||||
net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
|
net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
|
||||||
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
||||||
|
|
||||||
@@ -1511,7 +1513,7 @@ static int fib6_net_init(struct net *net)
|
|||||||
if (!net->ipv6.fib6_local_tbl)
|
if (!net->ipv6.fib6_local_tbl)
|
||||||
goto out_fib6_main_tbl;
|
goto out_fib6_main_tbl;
|
||||||
net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
|
net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
|
||||||
net->ipv6.fib6_local_tbl->tb6_root.leaf = ip6_null_entry;
|
net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
|
||||||
net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
|
net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
|
||||||
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
|
||||||
#endif
|
#endif
|
||||||
@@ -1536,6 +1538,7 @@ out_timer:
|
|||||||
|
|
||||||
static void fib6_net_exit(struct net *net)
|
static void fib6_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
|
rt6_ifdown(net, NULL);
|
||||||
del_timer(net->ipv6.ip6_fib_timer);
|
del_timer(net->ipv6.ip6_fib_timer);
|
||||||
kfree(net->ipv6.ip6_fib_timer);
|
kfree(net->ipv6.ip6_fib_timer);
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
202
net/ipv6/route.c
202
net/ipv6/route.c
@@ -145,8 +145,6 @@ static struct rt6_info ip6_null_entry_template = {
|
|||||||
.rt6i_ref = ATOMIC_INIT(1),
|
.rt6i_ref = ATOMIC_INIT(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rt6_info *ip6_null_entry;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
|
||||||
static int ip6_pkt_prohibit(struct sk_buff *skb);
|
static int ip6_pkt_prohibit(struct sk_buff *skb);
|
||||||
@@ -170,8 +168,6 @@ struct rt6_info ip6_prohibit_entry_template = {
|
|||||||
.rt6i_ref = ATOMIC_INIT(1),
|
.rt6i_ref = ATOMIC_INIT(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rt6_info *ip6_prohibit_entry;
|
|
||||||
|
|
||||||
static struct rt6_info ip6_blk_hole_entry_template = {
|
static struct rt6_info ip6_blk_hole_entry_template = {
|
||||||
.u = {
|
.u = {
|
||||||
.dst = {
|
.dst = {
|
||||||
@@ -190,8 +186,6 @@ static struct rt6_info ip6_blk_hole_entry_template = {
|
|||||||
.rt6i_ref = ATOMIC_INIT(1),
|
.rt6i_ref = ATOMIC_INIT(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rt6_info *ip6_blk_hole_entry;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* allocate dst with ip6_dst_ops */
|
/* allocate dst with ip6_dst_ops */
|
||||||
@@ -245,7 +239,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
|
|||||||
* Route lookup. Any table->tb6_lock is implied.
|
* Route lookup. Any table->tb6_lock is implied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
|
static inline struct rt6_info *rt6_device_match(struct net *net,
|
||||||
|
struct rt6_info *rt,
|
||||||
int oif,
|
int oif,
|
||||||
int strict)
|
int strict)
|
||||||
{
|
{
|
||||||
@@ -274,7 +269,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
|
|||||||
return local;
|
return local;
|
||||||
|
|
||||||
if (strict)
|
if (strict)
|
||||||
return ip6_null_entry;
|
return net->ipv6.ip6_null_entry;
|
||||||
}
|
}
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
@@ -415,6 +410,7 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
|
|||||||
static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
|
static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
|
||||||
{
|
{
|
||||||
struct rt6_info *match, *rt0;
|
struct rt6_info *match, *rt0;
|
||||||
|
struct net *net;
|
||||||
|
|
||||||
RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
|
RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
|
||||||
__FUNCTION__, fn->leaf, oif);
|
__FUNCTION__, fn->leaf, oif);
|
||||||
@@ -440,7 +436,8 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
|
|||||||
RT6_TRACE("%s() => %p\n",
|
RT6_TRACE("%s() => %p\n",
|
||||||
__FUNCTION__, match);
|
__FUNCTION__, match);
|
||||||
|
|
||||||
return (match ? match : ip6_null_entry);
|
net = rt0->rt6i_dev->nd_net;
|
||||||
|
return (match ? match : net->ipv6.ip6_null_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_ROUTE_INFO
|
#ifdef CONFIG_IPV6_ROUTE_INFO
|
||||||
@@ -523,9 +520,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BACKTRACK(saddr) \
|
#define BACKTRACK(__net, saddr) \
|
||||||
do { \
|
do { \
|
||||||
if (rt == ip6_null_entry) { \
|
if (rt == __net->ipv6.ip6_null_entry) { \
|
||||||
struct fib6_node *pn; \
|
struct fib6_node *pn; \
|
||||||
while (1) { \
|
while (1) { \
|
||||||
if (fn->fn_flags & RTN_TL_ROOT) \
|
if (fn->fn_flags & RTN_TL_ROOT) \
|
||||||
@@ -541,7 +538,8 @@ do { \
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
|
static struct rt6_info *ip6_pol_route_lookup(struct net *net,
|
||||||
|
struct fib6_table *table,
|
||||||
struct flowi *fl, int flags)
|
struct flowi *fl, int flags)
|
||||||
{
|
{
|
||||||
struct fib6_node *fn;
|
struct fib6_node *fn;
|
||||||
@@ -551,8 +549,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
|
|||||||
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
|
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
|
||||||
restart:
|
restart:
|
||||||
rt = fn->leaf;
|
rt = fn->leaf;
|
||||||
rt = rt6_device_match(rt, fl->oif, flags);
|
rt = rt6_device_match(net, rt, fl->oif, flags);
|
||||||
BACKTRACK(&fl->fl6_src);
|
BACKTRACK(net, &fl->fl6_src);
|
||||||
out:
|
out:
|
||||||
dst_use(&rt->u.dst, jiffies);
|
dst_use(&rt->u.dst, jiffies);
|
||||||
read_unlock_bh(&table->tb6_lock);
|
read_unlock_bh(&table->tb6_lock);
|
||||||
@@ -668,8 +666,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
|
|||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,
|
static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
|
||||||
struct flowi *fl, int flags)
|
struct flowi *fl, int flags)
|
||||||
{
|
{
|
||||||
struct fib6_node *fn;
|
struct fib6_node *fn;
|
||||||
struct rt6_info *rt, *nrt;
|
struct rt6_info *rt, *nrt;
|
||||||
@@ -688,8 +686,9 @@ restart_2:
|
|||||||
|
|
||||||
restart:
|
restart:
|
||||||
rt = rt6_select(fn, oif, strict | reachable);
|
rt = rt6_select(fn, oif, strict | reachable);
|
||||||
BACKTRACK(&fl->fl6_src);
|
|
||||||
if (rt == ip6_null_entry ||
|
BACKTRACK(net, &fl->fl6_src);
|
||||||
|
if (rt == net->ipv6.ip6_null_entry ||
|
||||||
rt->rt6i_flags & RTF_CACHE)
|
rt->rt6i_flags & RTF_CACHE)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -707,7 +706,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
dst_release(&rt->u.dst);
|
dst_release(&rt->u.dst);
|
||||||
rt = nrt ? : ip6_null_entry;
|
rt = nrt ? : net->ipv6.ip6_null_entry;
|
||||||
|
|
||||||
dst_hold(&rt->u.dst);
|
dst_hold(&rt->u.dst);
|
||||||
if (nrt) {
|
if (nrt) {
|
||||||
@@ -740,10 +739,10 @@ out2:
|
|||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
|
static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
|
||||||
struct flowi *fl, int flags)
|
struct flowi *fl, int flags)
|
||||||
{
|
{
|
||||||
return ip6_pol_route(table, fl->iif, fl, flags);
|
return ip6_pol_route(net, table, fl->iif, fl, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ip6_route_input(struct sk_buff *skb)
|
void ip6_route_input(struct sk_buff *skb)
|
||||||
@@ -770,10 +769,10 @@ void ip6_route_input(struct sk_buff *skb)
|
|||||||
skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
|
skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
|
static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
|
||||||
struct flowi *fl, int flags)
|
struct flowi *fl, int flags)
|
||||||
{
|
{
|
||||||
return ip6_pol_route(table, fl->oif, fl, flags);
|
return ip6_pol_route(net, table, fl->oif, fl, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
|
struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
|
||||||
@@ -1259,8 +1258,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct fib6_table *table;
|
struct fib6_table *table;
|
||||||
|
struct net *net = rt->rt6i_dev->nd_net;
|
||||||
|
|
||||||
if (rt == ip6_null_entry)
|
if (rt == net->ipv6.ip6_null_entry)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
table = rt->rt6i_table;
|
table = rt->rt6i_table;
|
||||||
@@ -1329,7 +1329,8 @@ struct ip6rd_flowi {
|
|||||||
struct in6_addr gateway;
|
struct in6_addr gateway;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
|
static struct rt6_info *__ip6_route_redirect(struct net *net,
|
||||||
|
struct fib6_table *table,
|
||||||
struct flowi *fl,
|
struct flowi *fl,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
@@ -1372,8 +1373,8 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rt)
|
if (!rt)
|
||||||
rt = ip6_null_entry;
|
rt = net->ipv6.ip6_null_entry;
|
||||||
BACKTRACK(&fl->fl6_src);
|
BACKTRACK(net, &fl->fl6_src);
|
||||||
out:
|
out:
|
||||||
dst_hold(&rt->u.dst);
|
dst_hold(&rt->u.dst);
|
||||||
|
|
||||||
@@ -1415,10 +1416,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
|
|||||||
{
|
{
|
||||||
struct rt6_info *rt, *nrt = NULL;
|
struct rt6_info *rt, *nrt = NULL;
|
||||||
struct netevent_redirect netevent;
|
struct netevent_redirect netevent;
|
||||||
|
struct net *net = neigh->dev->nd_net;
|
||||||
|
|
||||||
rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
|
rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
|
||||||
|
|
||||||
if (rt == ip6_null_entry) {
|
if (rt == net->ipv6.ip6_null_entry) {
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
|
printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
|
||||||
"for redirect target\n");
|
"for redirect target\n");
|
||||||
@@ -1886,10 +1888,18 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
|
|||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct arg_dev_net {
|
||||||
|
struct net_device *dev;
|
||||||
|
struct net *net;
|
||||||
|
};
|
||||||
|
|
||||||
static int fib6_ifdown(struct rt6_info *rt, void *arg)
|
static int fib6_ifdown(struct rt6_info *rt, void *arg)
|
||||||
{
|
{
|
||||||
if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
|
struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
|
||||||
rt != ip6_null_entry) {
|
struct net *net = ((struct arg_dev_net *)arg)->net;
|
||||||
|
|
||||||
|
if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
|
||||||
|
rt != net->ipv6.ip6_null_entry) {
|
||||||
RT6_TRACE("deleted by ifdown %p\n", rt);
|
RT6_TRACE("deleted by ifdown %p\n", rt);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1898,7 +1908,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
|
|||||||
|
|
||||||
void rt6_ifdown(struct net *net, struct net_device *dev)
|
void rt6_ifdown(struct net *net, struct net_device *dev)
|
||||||
{
|
{
|
||||||
fib6_clean_all(net, fib6_ifdown, 0, dev);
|
struct arg_dev_net adn = {
|
||||||
|
.dev = dev,
|
||||||
|
.net = net,
|
||||||
|
};
|
||||||
|
|
||||||
|
fib6_clean_all(net, fib6_ifdown, 0, &adn);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rt6_mtu_change_arg
|
struct rt6_mtu_change_arg
|
||||||
@@ -2289,6 +2304,26 @@ errout:
|
|||||||
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
|
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ip6_route_dev_notify(struct notifier_block *this,
|
||||||
|
unsigned long event, void *data)
|
||||||
|
{
|
||||||
|
struct net_device *dev = (struct net_device *)data;
|
||||||
|
struct net *net = dev->nd_net;
|
||||||
|
|
||||||
|
if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
|
||||||
|
net->ipv6.ip6_null_entry->u.dst.dev = dev;
|
||||||
|
net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
|
||||||
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
|
||||||
|
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
|
||||||
|
net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
|
||||||
|
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* /proc
|
* /proc
|
||||||
*/
|
*/
|
||||||
@@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
|
|||||||
|
|
||||||
static int ip6_route_net_init(struct net *net)
|
static int ip6_route_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = -ENOMEM;
|
||||||
|
net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
|
||||||
|
sizeof(*net->ipv6.ip6_null_entry),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!net->ipv6.ip6_null_entry)
|
||||||
|
goto out;
|
||||||
|
net->ipv6.ip6_null_entry->u.dst.path =
|
||||||
|
(struct dst_entry *)net->ipv6.ip6_null_entry;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
|
||||||
|
sizeof(*net->ipv6.ip6_prohibit_entry),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!net->ipv6.ip6_prohibit_entry) {
|
||||||
|
kfree(net->ipv6.ip6_null_entry);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
net->ipv6.ip6_prohibit_entry->u.dst.path =
|
||||||
|
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
|
||||||
|
|
||||||
|
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
|
||||||
|
sizeof(*net->ipv6.ip6_blk_hole_entry),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!net->ipv6.ip6_blk_hole_entry) {
|
||||||
|
kfree(net->ipv6.ip6_null_entry);
|
||||||
|
kfree(net->ipv6.ip6_prohibit_entry);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
net->ipv6.ip6_blk_hole_entry->u.dst.path =
|
||||||
|
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
|
proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
|
||||||
proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
|
proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ip6_route_net_exit(struct net *net)
|
static void ip6_route_net_exit(struct net *net)
|
||||||
@@ -2548,7 +2619,11 @@ static void ip6_route_net_exit(struct net *net)
|
|||||||
proc_net_remove(net, "ipv6_route");
|
proc_net_remove(net, "ipv6_route");
|
||||||
proc_net_remove(net, "rt6_stats");
|
proc_net_remove(net, "rt6_stats");
|
||||||
#endif
|
#endif
|
||||||
rt6_ifdown(net, NULL);
|
kfree(net->ipv6.ip6_null_entry);
|
||||||
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
kfree(net->ipv6.ip6_prohibit_entry);
|
||||||
|
kfree(net->ipv6.ip6_blk_hole_entry);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pernet_operations ip6_route_net_ops = {
|
static struct pernet_operations ip6_route_net_ops = {
|
||||||
@@ -2556,6 +2631,11 @@ static struct pernet_operations ip6_route_net_ops = {
|
|||||||
.exit = ip6_route_net_exit,
|
.exit = ip6_route_net_exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct notifier_block ip6_route_dev_notifier = {
|
||||||
|
.notifier_call = ip6_route_dev_notify,
|
||||||
|
.priority = 0,
|
||||||
|
};
|
||||||
|
|
||||||
int __init ip6_route_init(void)
|
int __init ip6_route_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -2568,30 +2648,24 @@ int __init ip6_route_init(void)
|
|||||||
|
|
||||||
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
|
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = register_pernet_subsys(&ip6_route_net_ops);
|
||||||
ip6_null_entry = kmemdup(&ip6_null_entry_template,
|
if (ret)
|
||||||
sizeof(*ip6_null_entry), GFP_KERNEL);
|
|
||||||
if (!ip6_null_entry)
|
|
||||||
goto out_kmem_cache;
|
goto out_kmem_cache;
|
||||||
ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
||||||
ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
|
|
||||||
sizeof(*ip6_prohibit_entry), GFP_KERNEL);
|
|
||||||
if (!ip6_prohibit_entry)
|
|
||||||
goto out_ip6_null_entry;
|
|
||||||
ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry;
|
|
||||||
|
|
||||||
ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
|
|
||||||
sizeof(*ip6_blk_hole_entry), GFP_KERNEL);
|
|
||||||
if (!ip6_blk_hole_entry)
|
|
||||||
goto out_ip6_prohibit_entry;
|
|
||||||
ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* Registering of the loopback is done before this portion of code,
|
||||||
|
* the loopback reference in rt6_info will not be taken, do it
|
||||||
|
* manually for init_net */
|
||||||
|
init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
|
||||||
|
init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
||||||
|
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||||
|
init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
|
||||||
|
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
||||||
|
init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
|
||||||
|
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
||||||
|
#endif
|
||||||
ret = fib6_init();
|
ret = fib6_init();
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_ip6_blk_hole_entry;
|
goto out_register_subsys;
|
||||||
|
|
||||||
ret = xfrm6_init();
|
ret = xfrm6_init();
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -2607,9 +2681,10 @@ int __init ip6_route_init(void)
|
|||||||
__rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
|
__rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
|
||||||
goto fib6_rules_init;
|
goto fib6_rules_init;
|
||||||
|
|
||||||
ret = register_pernet_subsys(&ip6_route_net_ops);
|
ret = register_netdevice_notifier(&ip6_route_dev_notifier);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fib6_rules_init;
|
goto fib6_rules_init;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -2619,14 +2694,8 @@ xfrm6_init:
|
|||||||
xfrm6_fini();
|
xfrm6_fini();
|
||||||
out_fib6_init:
|
out_fib6_init:
|
||||||
fib6_gc_cleanup();
|
fib6_gc_cleanup();
|
||||||
out_ip6_blk_hole_entry:
|
out_register_subsys:
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
unregister_pernet_subsys(&ip6_route_net_ops);
|
||||||
kfree(ip6_blk_hole_entry);
|
|
||||||
out_ip6_prohibit_entry:
|
|
||||||
kfree(ip6_prohibit_entry);
|
|
||||||
out_ip6_null_entry:
|
|
||||||
#endif
|
|
||||||
kfree(ip6_null_entry);
|
|
||||||
out_kmem_cache:
|
out_kmem_cache:
|
||||||
kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
|
kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -2634,15 +2703,10 @@ out_kmem_cache:
|
|||||||
|
|
||||||
void ip6_route_cleanup(void)
|
void ip6_route_cleanup(void)
|
||||||
{
|
{
|
||||||
unregister_pernet_subsys(&ip6_route_net_ops);
|
unregister_netdevice_notifier(&ip6_route_dev_notifier);
|
||||||
fib6_rules_cleanup();
|
fib6_rules_cleanup();
|
||||||
xfrm6_fini();
|
xfrm6_fini();
|
||||||
fib6_gc_cleanup();
|
fib6_gc_cleanup();
|
||||||
|
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_null_entry);
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
||||||
kfree(ip6_prohibit_entry);
|
|
||||||
kfree(ip6_blk_hole_entry);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user