Commit 421842ed authored by David Ahern's avatar David Ahern Committed by David S. Miller

net/ipv6: Add fib6_null_entry

ip6_null_entry will stay a dst based return for lookups that fail to
match an entry.

Add a new fib6_null_entry which constitutes the root node and leafs
for fibs. Replace existing references to ip6_null_entry with the
new fib6_null_entry when dealing with FIBs.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 14895687
...@@ -60,7 +60,8 @@ struct netns_ipv6 { ...@@ -60,7 +60,8 @@ struct netns_ipv6 {
#endif #endif
struct xt_table *ip6table_nat; struct xt_table *ip6table_nat;
#endif #endif
struct rt6_info *ip6_null_entry; struct rt6_info *fib6_null_entry;
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;
......
...@@ -231,7 +231,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id) ...@@ -231,7 +231,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
if (table) { if (table) {
table->tb6_id = id; table->tb6_id = id;
rcu_assign_pointer(table->tb6_root.leaf, rcu_assign_pointer(table->tb6_root.leaf,
net->ipv6.ip6_null_entry); net->ipv6.fib6_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;
inet_peer_base_init(&table->tb6_peers); inet_peer_base_init(&table->tb6_peers);
} }
...@@ -369,7 +369,7 @@ struct fib6_dump_arg { ...@@ -369,7 +369,7 @@ struct fib6_dump_arg {
static void fib6_rt_dump(struct rt6_info *rt, struct fib6_dump_arg *arg) static void fib6_rt_dump(struct rt6_info *rt, struct fib6_dump_arg *arg)
{ {
if (rt == arg->net->ipv6.ip6_null_entry) if (rt == arg->net->ipv6.fib6_null_entry)
return; return;
call_fib6_entry_notifier(arg->nb, arg->net, FIB_EVENT_ENTRY_ADD, rt); call_fib6_entry_notifier(arg->nb, arg->net, FIB_EVENT_ENTRY_ADD, rt);
} }
...@@ -658,7 +658,7 @@ static struct fib6_node *fib6_add_1(struct net *net, ...@@ -658,7 +658,7 @@ static struct fib6_node *fib6_add_1(struct net *net,
/* remove null_entry in the root node */ /* remove null_entry in the root node */
} else if (fn->fn_flags & RTN_TL_ROOT && } else if (fn->fn_flags & RTN_TL_ROOT &&
rcu_access_pointer(fn->leaf) == rcu_access_pointer(fn->leaf) ==
net->ipv6.ip6_null_entry) { net->ipv6.fib6_null_entry) {
RCU_INIT_POINTER(fn->leaf, NULL); RCU_INIT_POINTER(fn->leaf, NULL);
} }
...@@ -1171,9 +1171,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, ...@@ -1171,9 +1171,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
if (!sfn) if (!sfn)
goto failure; goto failure;
atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); atomic_inc(&info->nl_net->ipv6.fib6_null_entry->rt6i_ref);
rcu_assign_pointer(sfn->leaf, rcu_assign_pointer(sfn->leaf,
info->nl_net->ipv6.ip6_null_entry); info->nl_net->ipv6.fib6_null_entry);
sfn->fn_flags = RTN_ROOT; sfn->fn_flags = RTN_ROOT;
/* Now add the first leaf node to new subtree */ /* Now add the first leaf node to new subtree */
...@@ -1212,7 +1212,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, ...@@ -1212,7 +1212,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
if (fn->fn_flags & RTN_TL_ROOT) { if (fn->fn_flags & RTN_TL_ROOT) {
/* put back null_entry for root node */ /* put back null_entry for root node */
rcu_assign_pointer(fn->leaf, rcu_assign_pointer(fn->leaf,
info->nl_net->ipv6.ip6_null_entry); info->nl_net->ipv6.fib6_null_entry);
} else { } else {
atomic_inc(&rt->rt6i_ref); atomic_inc(&rt->rt6i_ref);
rcu_assign_pointer(fn->leaf, rt); rcu_assign_pointer(fn->leaf, rt);
...@@ -1251,7 +1251,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, ...@@ -1251,7 +1251,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
if (!pn_leaf) { if (!pn_leaf) {
WARN_ON(!pn_leaf); WARN_ON(!pn_leaf);
pn_leaf = pn_leaf =
info->nl_net->ipv6.ip6_null_entry; info->nl_net->ipv6.fib6_null_entry;
} }
#endif #endif
atomic_inc(&pn_leaf->rt6i_ref); atomic_inc(&pn_leaf->rt6i_ref);
...@@ -1494,7 +1494,7 @@ static struct rt6_info *fib6_find_prefix(struct net *net, ...@@ -1494,7 +1494,7 @@ static struct rt6_info *fib6_find_prefix(struct net *net,
struct fib6_node *child_left, *child_right; struct fib6_node *child_left, *child_right;
if (fn->fn_flags & RTN_ROOT) if (fn->fn_flags & RTN_ROOT)
return net->ipv6.ip6_null_entry; return net->ipv6.fib6_null_entry;
while (fn) { while (fn) {
child_left = rcu_dereference_protected(fn->left, child_left = rcu_dereference_protected(fn->left,
...@@ -1531,7 +1531,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net, ...@@ -1531,7 +1531,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
/* Set fn->leaf to null_entry for root node. */ /* Set fn->leaf to null_entry for root node. */
if (fn->fn_flags & RTN_TL_ROOT) { if (fn->fn_flags & RTN_TL_ROOT) {
rcu_assign_pointer(fn->leaf, net->ipv6.ip6_null_entry); rcu_assign_pointer(fn->leaf, net->ipv6.fib6_null_entry);
return fn; return fn;
} }
...@@ -1576,7 +1576,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net, ...@@ -1576,7 +1576,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
#if RT6_DEBUG >= 2 #if RT6_DEBUG >= 2
if (!new_fn_leaf) { if (!new_fn_leaf) {
WARN_ON(!new_fn_leaf); WARN_ON(!new_fn_leaf);
new_fn_leaf = net->ipv6.ip6_null_entry; new_fn_leaf = net->ipv6.fib6_null_entry;
} }
#endif #endif
atomic_inc(&new_fn_leaf->rt6i_ref); atomic_inc(&new_fn_leaf->rt6i_ref);
...@@ -1726,7 +1726,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) ...@@ -1726,7 +1726,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
return -ENOENT; return -ENOENT;
} }
#endif #endif
if (!fn || rt == net->ipv6.ip6_null_entry) if (!fn || rt == net->ipv6.fib6_null_entry)
return -ENOENT; return -ENOENT;
WARN_ON(!(fn->fn_flags & RTN_RTINFO)); WARN_ON(!(fn->fn_flags & RTN_RTINFO));
...@@ -2087,7 +2087,7 @@ static int __net_init fib6_net_init(struct net *net) ...@@ -2087,7 +2087,7 @@ static int __net_init fib6_net_init(struct net *net)
net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
rcu_assign_pointer(net->ipv6.fib6_main_tbl->tb6_root.leaf, rcu_assign_pointer(net->ipv6.fib6_main_tbl->tb6_root.leaf,
net->ipv6.ip6_null_entry); net->ipv6.fib6_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;
inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers); inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers);
...@@ -2099,7 +2099,7 @@ static int __net_init fib6_net_init(struct net *net) ...@@ -2099,7 +2099,7 @@ static int __net_init fib6_net_init(struct net *net)
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;
rcu_assign_pointer(net->ipv6.fib6_local_tbl->tb6_root.leaf, rcu_assign_pointer(net->ipv6.fib6_local_tbl->tb6_root.leaf,
net->ipv6.ip6_null_entry); net->ipv6.fib6_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;
inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers); inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers);
......
...@@ -276,6 +276,15 @@ static const u32 ip6_template_metrics[RTAX_MAX] = { ...@@ -276,6 +276,15 @@ static const u32 ip6_template_metrics[RTAX_MAX] = {
[RTAX_HOPLIMIT - 1] = 0, [RTAX_HOPLIMIT - 1] = 0,
}; };
static const struct rt6_info fib6_null_entry_template = {
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
.rt6i_metric = ~(u32)0,
.rt6i_ref = ATOMIC_INIT(1),
.fib6_type = RTN_UNREACHABLE,
.fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
};
static const struct rt6_info ip6_null_entry_template = { static const struct rt6_info ip6_null_entry_template = {
.dst = { .dst = {
.__refcnt = ATOMIC_INIT(1), .__refcnt = ATOMIC_INIT(1),
...@@ -522,10 +531,10 @@ static inline struct rt6_info *rt6_device_match(struct net *net, ...@@ -522,10 +531,10 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
return local; return local;
if (flags & RT6_LOOKUP_F_IFACE) if (flags & RT6_LOOKUP_F_IFACE)
return net->ipv6.ip6_null_entry; return net->ipv6.fib6_null_entry;
} }
return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
} }
#ifdef CONFIG_IPV6_ROUTER_PREF #ifdef CONFIG_IPV6_ROUTER_PREF
...@@ -758,8 +767,8 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn, ...@@ -758,8 +767,8 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn,
bool do_rr = false; bool do_rr = false;
int key_plen; int key_plen;
if (!leaf || leaf == net->ipv6.ip6_null_entry) if (!leaf || leaf == net->ipv6.fib6_null_entry)
return net->ipv6.ip6_null_entry; return net->ipv6.fib6_null_entry;
rt0 = rcu_dereference(fn->rr_ptr); rt0 = rcu_dereference(fn->rr_ptr);
if (!rt0) if (!rt0)
...@@ -776,7 +785,7 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn, ...@@ -776,7 +785,7 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn,
key_plen = rt0->rt6i_src.plen; key_plen = rt0->rt6i_src.plen;
#endif #endif
if (fn->fn_bit != key_plen) if (fn->fn_bit != key_plen)
return net->ipv6.ip6_null_entry; return net->ipv6.fib6_null_entry;
match = find_rr_leaf(fn, leaf, rt0, rt0->rt6i_metric, oif, strict, match = find_rr_leaf(fn, leaf, rt0, rt0->rt6i_metric, oif, strict,
&do_rr); &do_rr);
...@@ -797,7 +806,7 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn, ...@@ -797,7 +806,7 @@ static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn,
} }
} }
return match ? match : net->ipv6.ip6_null_entry; return match ? match : net->ipv6.fib6_null_entry;
} }
static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt) static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
...@@ -1063,7 +1072,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, ...@@ -1063,7 +1072,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
restart: restart:
rt = rcu_dereference(fn->leaf); rt = rcu_dereference(fn->leaf);
if (!rt) { if (!rt) {
rt = net->ipv6.ip6_null_entry; rt = net->ipv6.fib6_null_entry;
} else { } else {
rt = rt6_device_match(net, rt, &fl6->saddr, rt = rt6_device_match(net, rt, &fl6->saddr,
fl6->flowi6_oif, flags); fl6->flowi6_oif, flags);
...@@ -1071,7 +1080,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, ...@@ -1071,7 +1080,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
rt = rt6_multipath_select(net, rt, fl6, fl6->flowi6_oif, rt = rt6_multipath_select(net, rt, fl6, fl6->flowi6_oif,
skb, flags); skb, flags);
} }
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.fib6_null_entry) {
fn = fib6_backtrack(fn, &fl6->saddr); fn = fib6_backtrack(fn, &fl6->saddr);
if (fn) if (fn)
goto restart; goto restart;
...@@ -1820,7 +1829,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, ...@@ -1820,7 +1829,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
rt = rt6_select(net, fn, oif, strict); rt = rt6_select(net, fn, oif, strict);
if (rt->rt6i_nsiblings) if (rt->rt6i_nsiblings)
rt = rt6_multipath_select(net, rt, fl6, oif, skb, strict); rt = rt6_multipath_select(net, rt, fl6, oif, skb, strict);
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.fib6_null_entry) {
fn = fib6_backtrack(fn, &fl6->saddr); fn = fib6_backtrack(fn, &fl6->saddr);
if (fn) if (fn)
goto redo_rt6_select; goto redo_rt6_select;
...@@ -1837,7 +1846,8 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, ...@@ -1837,7 +1846,8 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
if (rt_cache) if (rt_cache)
rt = rt_cache; rt = rt_cache;
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.fib6_null_entry) {
rt = net->ipv6.ip6_null_entry;
rcu_read_unlock(); rcu_read_unlock();
dst_hold(&rt->dst); dst_hold(&rt->dst);
trace_fib6_table_lookup(net, rt, table, fl6); trace_fib6_table_lookup(net, rt, table, fl6);
...@@ -2412,13 +2422,13 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, ...@@ -2412,13 +2422,13 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
} }
if (!rt) if (!rt)
rt = net->ipv6.ip6_null_entry; rt = net->ipv6.fib6_null_entry;
else if (rt->rt6i_flags & RTF_REJECT) { else if (rt->rt6i_flags & RTF_REJECT) {
rt = net->ipv6.ip6_null_entry; rt = net->ipv6.ip6_null_entry;
goto out; goto out;
} }
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.fib6_null_entry) {
fn = fib6_backtrack(fn, &fl6->saddr); fn = fib6_backtrack(fn, &fl6->saddr);
if (fn) if (fn)
goto restart; goto restart;
...@@ -3051,7 +3061,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) ...@@ -3051,7 +3061,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
struct fib6_table *table; struct fib6_table *table;
int err; int err;
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.fib6_null_entry) {
err = -ENOENT; err = -ENOENT;
goto out; goto out;
} }
...@@ -3081,7 +3091,7 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg) ...@@ -3081,7 +3091,7 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
struct fib6_table *table; struct fib6_table *table;
int err = -ENOENT; int err = -ENOENT;
if (rt == net->ipv6.ip6_null_entry) if (rt == net->ipv6.fib6_null_entry)
goto out_put; goto out_put;
table = rt->rt6i_table; table = rt->rt6i_table;
spin_lock_bh(&table->tb6_lock); spin_lock_bh(&table->tb6_lock);
...@@ -3634,7 +3644,7 @@ static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) ...@@ -3634,7 +3644,7 @@ static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
if (((void *)rt->fib6_nh.nh_dev == dev || !dev) && if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
rt != net->ipv6.ip6_null_entry && rt != net->ipv6.fib6_null_entry &&
ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
spin_lock_bh(&rt6_exception_lock); spin_lock_bh(&rt6_exception_lock);
/* remove prefsrc entry */ /* remove prefsrc entry */
...@@ -3789,7 +3799,7 @@ static int fib6_ifup(struct rt6_info *rt, void *p_arg) ...@@ -3789,7 +3799,7 @@ static int fib6_ifup(struct rt6_info *rt, void *p_arg)
const struct arg_netdev_event *arg = p_arg; const struct arg_netdev_event *arg = p_arg;
struct net *net = dev_net(arg->dev); struct net *net = dev_net(arg->dev);
if (rt != net->ipv6.ip6_null_entry && rt->fib6_nh.nh_dev == arg->dev) { if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
rt->fib6_nh.nh_flags &= ~arg->nh_flags; rt->fib6_nh.nh_flags &= ~arg->nh_flags;
fib6_update_sernum_upto_root(net, rt); fib6_update_sernum_upto_root(net, rt);
rt6_multipath_rebalance(rt); rt6_multipath_rebalance(rt);
...@@ -3873,7 +3883,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) ...@@ -3873,7 +3883,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg)
const struct net_device *dev = arg->dev; const struct net_device *dev = arg->dev;
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
if (rt == net->ipv6.ip6_null_entry) if (rt == net->ipv6.fib6_null_entry)
return 0; return 0;
switch (arg->event) { switch (arg->event) {
...@@ -4624,7 +4634,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) ...@@ -4624,7 +4634,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
struct net *net = arg->net; struct net *net = arg->net;
if (rt == net->ipv6.ip6_null_entry) if (rt == net->ipv6.fib6_null_entry)
return 0; return 0;
if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
...@@ -4813,6 +4823,8 @@ static int ip6_route_dev_notify(struct notifier_block *this, ...@@ -4813,6 +4823,8 @@ static int ip6_route_dev_notify(struct notifier_block *this,
return NOTIFY_OK; return NOTIFY_OK;
if (event == NETDEV_REGISTER) { if (event == NETDEV_REGISTER) {
net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
net->ipv6.fib6_null_entry->rt6i_idev = in6_dev_get(dev);
net->ipv6.ip6_null_entry->dst.dev = dev; net->ipv6.ip6_null_entry->dst.dev = dev;
net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
...@@ -4826,6 +4838,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, ...@@ -4826,6 +4838,7 @@ static int ip6_route_dev_notify(struct notifier_block *this,
/* NETDEV_UNREGISTER could be fired for multiple times by /* NETDEV_UNREGISTER could be fired for multiple times by
* netdev_wait_allrefs(). Make sure we only call this once. * netdev_wait_allrefs(). Make sure we only call this once.
*/ */
in6_dev_put_clear(&net->ipv6.fib6_null_entry->rt6i_idev);
in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
...@@ -5009,11 +5022,17 @@ static int __net_init ip6_route_net_init(struct net *net) ...@@ -5009,11 +5022,17 @@ static int __net_init ip6_route_net_init(struct net *net)
if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
goto out_ip6_dst_ops; goto out_ip6_dst_ops;
net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
sizeof(*net->ipv6.fib6_null_entry),
GFP_KERNEL);
if (!net->ipv6.fib6_null_entry)
goto out_ip6_dst_entries;
net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
sizeof(*net->ipv6.ip6_null_entry), sizeof(*net->ipv6.ip6_null_entry),
GFP_KERNEL); GFP_KERNEL);
if (!net->ipv6.ip6_null_entry) if (!net->ipv6.ip6_null_entry)
goto out_ip6_dst_entries; goto out_fib6_null_entry;
net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_null_entry->dst, dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
ip6_template_metrics, true); ip6_template_metrics, true);
...@@ -5060,6 +5079,8 @@ static int __net_init ip6_route_net_init(struct net *net) ...@@ -5060,6 +5079,8 @@ static int __net_init ip6_route_net_init(struct net *net)
out_ip6_null_entry: out_ip6_null_entry:
kfree(net->ipv6.ip6_null_entry); kfree(net->ipv6.ip6_null_entry);
#endif #endif
out_fib6_null_entry:
kfree(net->ipv6.fib6_null_entry);
out_ip6_dst_entries: out_ip6_dst_entries:
dst_entries_destroy(&net->ipv6.ip6_dst_ops); dst_entries_destroy(&net->ipv6.ip6_dst_ops);
out_ip6_dst_ops: out_ip6_dst_ops:
...@@ -5068,6 +5089,7 @@ static int __net_init ip6_route_net_init(struct net *net) ...@@ -5068,6 +5089,7 @@ static int __net_init ip6_route_net_init(struct net *net)
static void __net_exit ip6_route_net_exit(struct net *net) static void __net_exit ip6_route_net_exit(struct net *net)
{ {
kfree(net->ipv6.fib6_null_entry);
kfree(net->ipv6.ip6_null_entry); kfree(net->ipv6.ip6_null_entry);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(net->ipv6.ip6_prohibit_entry); kfree(net->ipv6.ip6_prohibit_entry);
...@@ -5138,6 +5160,8 @@ void __init ip6_route_init_special_entries(void) ...@@ -5138,6 +5160,8 @@ void __init ip6_route_init_special_entries(void)
/* Registering of the loopback is done before this portion of code, /* Registering of the loopback is done before this portion of code,
* the loopback reference in rt6_info will not be taken, do it * the loopback reference in rt6_info will not be taken, do it
* manually for init_net */ * manually for init_net */
init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
init_net.ipv6.fib6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment