Commit 3f4fe759 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipv6-followup-to-fib6_info-change'

David Ahern says:

====================
net/ipv6: followup to fib6_info change

Followup to fib change for IPv6.

First 2 patches rename fib6_info struct elements to match its name,
and rename addrconf_dst_alloc to match what it returns.

Patches 3-7 refactor the code to remove the need for fib6_idev reducing
fib6_info by another 8 bytes to 200 bytes.

Patch 8 fixes the gfp flags argument to addrconf_prefix_route in a
couple of places.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 88078d98 27b10608
...@@ -4705,17 +4705,17 @@ static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt) ...@@ -4705,17 +4705,17 @@ static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
* are trapped to the CPU, so no need to program specific routes * are trapped to the CPU, so no need to program specific routes
* for them. * for them.
*/ */
if (ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LINKLOCAL) if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_LINKLOCAL)
return true; return true;
/* Multicast routes aren't supported, so ignore them. Neighbour /* Multicast routes aren't supported, so ignore them. Neighbour
* Discovery packets are specifically trapped. * Discovery packets are specifically trapped.
*/ */
if (ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_MULTICAST) if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_MULTICAST)
return true; return true;
/* Cloned routes are irrelevant in the forwarding path. */ /* Cloned routes are irrelevant in the forwarding path. */
if (rt->rt6i_flags & RTF_CACHE) if (rt->fib6_flags & RTF_CACHE)
return true; return true;
return false; return false;
...@@ -4759,7 +4759,7 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6) ...@@ -4759,7 +4759,7 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt) static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
{ {
/* RTF_CACHE routes are ignored */ /* RTF_CACHE routes are ignored */
return (rt->rt6i_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY; return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
} }
static struct fib6_info * static struct fib6_info *
...@@ -4784,16 +4784,16 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, ...@@ -4784,16 +4784,16 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
/* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same
* virtual router. * virtual router.
*/ */
if (rt->rt6i_table->tb6_id > nrt->rt6i_table->tb6_id) if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id)
continue; continue;
if (rt->rt6i_table->tb6_id != nrt->rt6i_table->tb6_id) if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
break; break;
if (rt->rt6i_metric < nrt->rt6i_metric) if (rt->fib6_metric < nrt->fib6_metric)
continue; continue;
if (rt->rt6i_metric == nrt->rt6i_metric && if (rt->fib6_metric == nrt->fib6_metric &&
mlxsw_sp_fib6_rt_can_mp(rt)) mlxsw_sp_fib6_rt_can_mp(rt))
return fib6_entry; return fib6_entry;
if (rt->rt6i_metric > nrt->rt6i_metric) if (rt->fib6_metric > nrt->fib6_metric)
break; break;
} }
...@@ -4899,7 +4899,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp, ...@@ -4899,7 +4899,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp, static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
const struct fib6_info *rt) const struct fib6_info *rt)
{ {
return rt->rt6i_flags & RTF_GATEWAY || return rt->fib6_flags & RTF_GATEWAY ||
mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL); mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
} }
...@@ -5092,9 +5092,9 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, ...@@ -5092,9 +5092,9 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
* local, which will cause them to be trapped with a lower * local, which will cause them to be trapped with a lower
* priority than packets that need to be locally received. * priority than packets that need to be locally received.
*/ */
if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
else if (rt->rt6i_flags & RTF_REJECT) else if (rt->fib6_flags & RTF_REJECT)
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
...@@ -5175,18 +5175,18 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, ...@@ -5175,18 +5175,18 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry); struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
if (rt->rt6i_table->tb6_id > nrt->rt6i_table->tb6_id) if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id)
continue; continue;
if (rt->rt6i_table->tb6_id != nrt->rt6i_table->tb6_id) if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
break; break;
if (replace && rt->rt6i_metric == nrt->rt6i_metric) { if (replace && rt->fib6_metric == nrt->fib6_metric) {
if (mlxsw_sp_fib6_rt_can_mp(rt) == if (mlxsw_sp_fib6_rt_can_mp(rt) ==
mlxsw_sp_fib6_rt_can_mp(nrt)) mlxsw_sp_fib6_rt_can_mp(nrt))
return fib6_entry; return fib6_entry;
if (mlxsw_sp_fib6_rt_can_mp(nrt)) if (mlxsw_sp_fib6_rt_can_mp(nrt))
fallback = fallback ?: fib6_entry; fallback = fallback ?: fib6_entry;
} }
if (rt->rt6i_metric > nrt->rt6i_metric) if (rt->fib6_metric > nrt->fib6_metric)
return fallback ?: fib6_entry; return fallback ?: fib6_entry;
} }
...@@ -5215,7 +5215,7 @@ mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry, ...@@ -5215,7 +5215,7 @@ mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry,
list_for_each_entry(last, &fib_node->entry_list, common.list) { list_for_each_entry(last, &fib_node->entry_list, common.list) {
struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(last); struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(last);
if (nrt->rt6i_table->tb6_id > rt->rt6i_table->tb6_id) if (nrt->fib6_table->tb6_id > rt->fib6_table->tb6_id)
break; break;
fib6_entry = last; fib6_entry = last;
} }
...@@ -5275,22 +5275,22 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp, ...@@ -5275,22 +5275,22 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib *fib; struct mlxsw_sp_fib *fib;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
vr = mlxsw_sp_vr_find(mlxsw_sp, rt->rt6i_table->tb6_id); vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id);
if (!vr) if (!vr)
return NULL; return NULL;
fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV6); fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV6);
fib_node = mlxsw_sp_fib_node_lookup(fib, &rt->rt6i_dst.addr, fib_node = mlxsw_sp_fib_node_lookup(fib, &rt->fib6_dst.addr,
sizeof(rt->rt6i_dst.addr), sizeof(rt->fib6_dst.addr),
rt->rt6i_dst.plen); rt->fib6_dst.plen);
if (!fib_node) if (!fib_node)
return NULL; return NULL;
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
struct fib6_info *iter_rt = mlxsw_sp_fib6_entry_rt(fib6_entry); struct fib6_info *iter_rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
if (rt->rt6i_table->tb6_id == iter_rt->rt6i_table->tb6_id && if (rt->fib6_table->tb6_id == iter_rt->fib6_table->tb6_id &&
rt->rt6i_metric == iter_rt->rt6i_metric && rt->fib6_metric == iter_rt->fib6_metric &&
mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt)) mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt))
return fib6_entry; return fib6_entry;
} }
...@@ -5325,16 +5325,16 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5325,16 +5325,16 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
if (mlxsw_sp->router->aborted) if (mlxsw_sp->router->aborted)
return 0; return 0;
if (rt->rt6i_src.plen) if (rt->fib6_src.plen)
return -EINVAL; return -EINVAL;
if (mlxsw_sp_fib6_rt_should_ignore(rt)) if (mlxsw_sp_fib6_rt_should_ignore(rt))
return 0; return 0;
fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->rt6i_table->tb6_id, fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
&rt->rt6i_dst.addr, &rt->fib6_dst.addr,
sizeof(rt->rt6i_dst.addr), sizeof(rt->fib6_dst.addr),
rt->rt6i_dst.plen, rt->fib6_dst.plen,
MLXSW_SP_L3_PROTO_IPV6); MLXSW_SP_L3_PROTO_IPV6);
if (IS_ERR(fib_node)) if (IS_ERR(fib_node))
return PTR_ERR(fib_node); return PTR_ERR(fib_node);
......
...@@ -143,7 +143,6 @@ struct ipv6_ac_socklist { ...@@ -143,7 +143,6 @@ struct ipv6_ac_socklist {
struct ifacaddr6 { struct ifacaddr6 {
struct in6_addr aca_addr; struct in6_addr aca_addr;
struct inet6_dev *aca_idev;
struct fib6_info *aca_rt; struct fib6_info *aca_rt;
struct ifacaddr6 *aca_next; struct ifacaddr6 *aca_next;
int aca_users; int aca_users;
......
...@@ -134,34 +134,33 @@ struct fib6_nh { ...@@ -134,34 +134,33 @@ struct fib6_nh {
}; };
struct fib6_info { struct fib6_info {
struct fib6_table *rt6i_table; struct fib6_table *fib6_table;
struct fib6_info __rcu *rt6_next; struct fib6_info __rcu *rt6_next;
struct fib6_node __rcu *rt6i_node; struct fib6_node __rcu *fib6_node;
/* Multipath routes: /* Multipath routes:
* siblings is a list of fib6_info that have the the same metric/weight, * siblings is a list of fib6_info that have the the same metric/weight,
* destination, but not the same gateway. nsiblings is just a cache * destination, but not the same gateway. nsiblings is just a cache
* to speed up lookup. * to speed up lookup.
*/ */
struct list_head rt6i_siblings; struct list_head fib6_siblings;
unsigned int rt6i_nsiblings; unsigned int fib6_nsiblings;
atomic_t rt6i_ref; atomic_t fib6_ref;
struct inet6_dev *rt6i_idev;
unsigned long expires; unsigned long expires;
struct dst_metrics *fib6_metrics; struct dst_metrics *fib6_metrics;
#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] #define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]
struct rt6key rt6i_dst; struct rt6key fib6_dst;
u32 rt6i_flags; u32 fib6_flags;
struct rt6key rt6i_src; struct rt6key fib6_src;
struct rt6key rt6i_prefsrc; struct rt6key fib6_prefsrc;
struct rt6_info * __percpu *rt6i_pcpu; struct rt6_info * __percpu *rt6i_pcpu;
struct rt6_exception_bucket __rcu *rt6i_exception_bucket; struct rt6_exception_bucket __rcu *rt6i_exception_bucket;
u32 rt6i_metric; u32 fib6_metric;
u8 rt6i_protocol; u8 fib6_protocol;
u8 fib6_type; u8 fib6_type;
u8 exception_bucket_flushed:1, u8 exception_bucket_flushed:1,
should_flush:1, should_flush:1,
...@@ -206,7 +205,7 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) ...@@ -206,7 +205,7 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
static inline void fib6_clean_expires(struct fib6_info *f6i) static inline void fib6_clean_expires(struct fib6_info *f6i)
{ {
f6i->rt6i_flags &= ~RTF_EXPIRES; f6i->fib6_flags &= ~RTF_EXPIRES;
f6i->expires = 0; f6i->expires = 0;
} }
...@@ -214,12 +213,12 @@ static inline void fib6_set_expires(struct fib6_info *f6i, ...@@ -214,12 +213,12 @@ static inline void fib6_set_expires(struct fib6_info *f6i,
unsigned long expires) unsigned long expires)
{ {
f6i->expires = expires; f6i->expires = expires;
f6i->rt6i_flags |= RTF_EXPIRES; f6i->fib6_flags |= RTF_EXPIRES;
} }
static inline bool fib6_check_expired(const struct fib6_info *f6i) static inline bool fib6_check_expired(const struct fib6_info *f6i)
{ {
if (f6i->rt6i_flags & RTF_EXPIRES) if (f6i->fib6_flags & RTF_EXPIRES)
return time_after(jiffies, f6i->expires); return time_after(jiffies, f6i->expires);
return false; return false;
} }
...@@ -250,14 +249,14 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) ...@@ -250,14 +249,14 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout)
* Return true if we can get cookie safely * Return true if we can get cookie safely
* Return false if not * Return false if not
*/ */
static inline bool rt6_get_cookie_safe(const struct fib6_info *rt, static inline bool rt6_get_cookie_safe(const struct fib6_info *f6i,
u32 *cookie) u32 *cookie)
{ {
struct fib6_node *fn; struct fib6_node *fn;
bool status = false; bool status = false;
rcu_read_lock(); rcu_read_lock();
fn = rcu_dereference(rt->rt6i_node); fn = rcu_dereference(f6i->fib6_node);
if (fn) { if (fn) {
*cookie = fn->fn_sernum; *cookie = fn->fn_sernum;
...@@ -295,12 +294,12 @@ void fib6_info_destroy(struct fib6_info *f6i); ...@@ -295,12 +294,12 @@ void fib6_info_destroy(struct fib6_info *f6i);
static inline void fib6_info_hold(struct fib6_info *f6i) static inline void fib6_info_hold(struct fib6_info *f6i)
{ {
atomic_inc(&f6i->rt6i_ref); atomic_inc(&f6i->fib6_ref);
} }
static inline void fib6_info_release(struct fib6_info *f6i) static inline void fib6_info_release(struct fib6_info *f6i)
{ {
if (f6i && atomic_dec_and_test(&f6i->rt6i_ref)) if (f6i && atomic_dec_and_test(&f6i->fib6_ref))
fib6_info_destroy(f6i); fib6_info_destroy(f6i);
} }
...@@ -410,6 +409,11 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -410,6 +409,11 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
struct nl_info *info, struct netlink_ext_ack *extack); struct nl_info *info, struct netlink_ext_ack *extack);
int fib6_del(struct fib6_info *rt, struct nl_info *info); int fib6_del(struct fib6_info *rt, struct nl_info *info);
static inline struct net_device *fib6_info_nh_dev(const struct fib6_info *f6i)
{
return f6i->fib6_nh.nh_dev;
}
void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
unsigned int flags); unsigned int flags);
......
...@@ -66,9 +66,9 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr) ...@@ -66,9 +66,9 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr)
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
} }
static inline bool rt6_qualify_for_ecmp(const struct fib6_info *rt) static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i)
{ {
return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) == return (f6i->fib6_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) ==
RTF_GATEWAY; RTF_GATEWAY;
} }
...@@ -102,26 +102,27 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg); ...@@ -102,26 +102,27 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg);
int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags, int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int ip6_ins_rt(struct net *net, struct fib6_info *rt); int ip6_ins_rt(struct net *net, struct fib6_info *f6i);
int ip6_del_rt(struct net *net, struct fib6_info *rt); int ip6_del_rt(struct net *net, struct fib6_info *f6i);
void rt6_flush_exceptions(struct fib6_info *rt); void rt6_flush_exceptions(struct fib6_info *f6i);
void rt6_age_exceptions(struct fib6_info *rt, struct fib6_gc_args *gc_args, void rt6_age_exceptions(struct fib6_info *f6i, struct fib6_gc_args *gc_args,
unsigned long now); unsigned long now);
static inline int ip6_route_get_saddr(struct net *net, struct fib6_info *rt, static inline int ip6_route_get_saddr(struct net *net, struct fib6_info *f6i,
const struct in6_addr *daddr, const struct in6_addr *daddr,
unsigned int prefs, unsigned int prefs,
struct in6_addr *saddr) struct in6_addr *saddr)
{ {
struct inet6_dev *idev = rt ? rt->rt6i_idev : NULL;
int err = 0; int err = 0;
if (rt && rt->rt6i_prefsrc.plen) if (f6i && f6i->fib6_prefsrc.plen) {
*saddr = rt->rt6i_prefsrc.addr; *saddr = f6i->fib6_prefsrc.addr;
else } else {
err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, struct net_device *dev = f6i ? fib6_info_nh_dev(f6i) : NULL;
daddr, prefs, saddr);
err = ipv6_dev_get_saddr(net, dev, daddr, prefs, saddr);
}
return err; return err;
} }
...@@ -136,7 +137,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6); ...@@ -136,7 +137,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);
void fib6_force_start_gc(struct net *net); void fib6_force_start_gc(struct net *net);
struct fib6_info *addrconf_dst_alloc(struct net *net, struct inet6_dev *idev, struct fib6_info *addrconf_f6i_alloc(struct net *net, struct inet6_dev *idev,
const struct in6_addr *addr, bool anycast, const struct in6_addr *addr, bool anycast,
gfp_t gfp_flags); gfp_t gfp_flags);
...@@ -176,14 +177,14 @@ struct rt6_rtnl_dump_arg { ...@@ -176,14 +177,14 @@ struct rt6_rtnl_dump_arg {
struct net *net; struct net *net;
}; };
int rt6_dump_route(struct fib6_info *rt, void *p_arg); int rt6_dump_route(struct fib6_info *f6i, void *p_arg);
void rt6_mtu_change(struct net_device *dev, unsigned int mtu); void rt6_mtu_change(struct net_device *dev, unsigned int mtu);
void rt6_remove_prefsrc(struct inet6_ifaddr *ifp); void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
void rt6_clean_tohost(struct net *net, struct in6_addr *gateway); void rt6_clean_tohost(struct net *net, struct in6_addr *gateway);
void rt6_sync_up(struct net_device *dev, unsigned int nh_flags); void rt6_sync_up(struct net_device *dev, unsigned int nh_flags);
void rt6_disable_ip(struct net_device *dev, unsigned long event); void rt6_disable_ip(struct net_device *dev, unsigned long event);
void rt6_sync_down_dev(struct net_device *dev, unsigned long event); void rt6_sync_down_dev(struct net_device *dev, unsigned long event);
void rt6_multipath_rebalance(struct fib6_info *rt); void rt6_multipath_rebalance(struct fib6_info *f6i);
void rt6_uncached_list_add(struct rt6_info *rt); void rt6_uncached_list_add(struct rt6_info *rt);
void rt6_uncached_list_del(struct rt6_info *rt); void rt6_uncached_list_del(struct rt6_info *rt);
...@@ -274,7 +275,6 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, ...@@ -274,7 +275,6 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt,
static inline bool rt6_duplicate_nexthop(struct fib6_info *a, struct fib6_info *b) static inline bool rt6_duplicate_nexthop(struct fib6_info *a, struct fib6_info *b)
{ {
return a->fib6_nh.nh_dev == b->fib6_nh.nh_dev && return a->fib6_nh.nh_dev == b->fib6_nh.nh_dev &&
a->rt6i_idev == b->rt6i_idev &&
ipv6_addr_equal(&a->fib6_nh.nh_gw, &b->fib6_nh.nh_gw) && ipv6_addr_equal(&a->fib6_nh.nh_gw, &b->fib6_nh.nh_gw) &&
!lwtunnel_cmp_encap(a->fib6_nh.nh_lwtstate, b->fib6_nh.nh_lwtstate); !lwtunnel_cmp_encap(a->fib6_nh.nh_lwtstate, b->fib6_nh.nh_lwtstate);
} }
......
...@@ -994,7 +994,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ...@@ -994,7 +994,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
gfp_t gfp_flags = can_block ? GFP_KERNEL : GFP_ATOMIC; gfp_t gfp_flags = can_block ? GFP_KERNEL : GFP_ATOMIC;
struct net *net = dev_net(idev->dev); struct net *net = dev_net(idev->dev);
struct inet6_ifaddr *ifa = NULL; struct inet6_ifaddr *ifa = NULL;
struct fib6_info *rt = NULL; struct fib6_info *f6i = NULL;
int err = 0; int err = 0;
int addr_type = ipv6_addr_type(addr); int addr_type = ipv6_addr_type(addr);
...@@ -1036,16 +1036,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ...@@ -1036,16 +1036,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
goto out; goto out;
} }
rt = addrconf_dst_alloc(net, idev, addr, false, gfp_flags); f6i = addrconf_f6i_alloc(net, idev, addr, false, gfp_flags);
if (IS_ERR(rt)) { if (IS_ERR(f6i)) {
err = PTR_ERR(rt); err = PTR_ERR(f6i);
rt = NULL; f6i = NULL;
goto out; goto out;
} }
if (net->ipv6.devconf_all->disable_policy || if (net->ipv6.devconf_all->disable_policy ||
idev->cnf.disable_policy) idev->cnf.disable_policy)
rt->dst_nopolicy = true; f6i->dst_nopolicy = true;
neigh_parms_data_state_setall(idev->nd_parms); neigh_parms_data_state_setall(idev->nd_parms);
...@@ -1067,7 +1067,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ...@@ -1067,7 +1067,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
ifa->cstamp = ifa->tstamp = jiffies; ifa->cstamp = ifa->tstamp = jiffies;
ifa->tokenized = false; ifa->tokenized = false;
ifa->rt = rt; ifa->rt = f6i;
ifa->idev = idev; ifa->idev = idev;
in6_dev_hold(idev); in6_dev_hold(idev);
...@@ -1101,7 +1101,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ...@@ -1101,7 +1101,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
inet6addr_notifier_call_chain(NETDEV_UP, ifa); inet6addr_notifier_call_chain(NETDEV_UP, ifa);
out: out:
if (unlikely(err < 0)) { if (unlikely(err < 0)) {
fib6_info_release(rt); fib6_info_release(f6i);
if (ifa) { if (ifa) {
if (ifa->idev) if (ifa->idev)
...@@ -1178,19 +1178,19 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) ...@@ -1178,19 +1178,19 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
static void static void
cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt)
{ {
struct fib6_info *rt; struct fib6_info *f6i;
rt = addrconf_get_prefix_route(&ifp->addr, f6i = addrconf_get_prefix_route(&ifp->addr,
ifp->prefix_len, ifp->prefix_len,
ifp->idev->dev, ifp->idev->dev,
0, RTF_GATEWAY | RTF_DEFAULT); 0, RTF_GATEWAY | RTF_DEFAULT);
if (rt) { if (f6i) {
if (del_rt) if (del_rt)
ip6_del_rt(dev_net(ifp->idev->dev), rt); ip6_del_rt(dev_net(ifp->idev->dev), f6i);
else { else {
if (!(rt->rt6i_flags & RTF_EXPIRES)) if (!(f6i->fib6_flags & RTF_EXPIRES))
fib6_set_expires(rt, expires); fib6_set_expires(f6i, expires);
fib6_info_release(rt); fib6_info_release(f6i);
} }
} }
} }
...@@ -2370,9 +2370,9 @@ static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, ...@@ -2370,9 +2370,9 @@ static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
for_each_fib6_node_rt_rcu(fn) { for_each_fib6_node_rt_rcu(fn) {
if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex) if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex)
continue; continue;
if ((rt->rt6i_flags & flags) != flags) if ((rt->fib6_flags & flags) != flags)
continue; continue;
if ((rt->rt6i_flags & noflags) != 0) if ((rt->fib6_flags & noflags) != 0)
continue; continue;
fib6_info_hold(rt); fib6_info_hold(rt);
break; break;
...@@ -3245,7 +3245,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) ...@@ -3245,7 +3245,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
addrconf_add_linklocal(idev, &addr, 0); addrconf_add_linklocal(idev, &addr, 0);
else if (prefix_route) else if (prefix_route)
addrconf_prefix_route(&addr, 64, idev->dev, addrconf_prefix_route(&addr, 64, idev->dev,
0, 0, GFP_ATOMIC); 0, 0, GFP_KERNEL);
break; break;
case IN6_ADDR_GEN_MODE_NONE: case IN6_ADDR_GEN_MODE_NONE:
default: default:
...@@ -3341,22 +3341,22 @@ static int fixup_permanent_addr(struct net *net, ...@@ -3341,22 +3341,22 @@ static int fixup_permanent_addr(struct net *net,
struct inet6_dev *idev, struct inet6_dev *idev,
struct inet6_ifaddr *ifp) struct inet6_ifaddr *ifp)
{ {
/* !rt6i_node means the host route was removed from the /* !fib6_node means the host route was removed from the
* FIB, for example, if 'lo' device is taken down. In that * FIB, for example, if 'lo' device is taken down. In that
* case regenerate the host route. * case regenerate the host route.
*/ */
if (!ifp->rt || !ifp->rt->rt6i_node) { if (!ifp->rt || !ifp->rt->fib6_node) {
struct fib6_info *rt, *prev; struct fib6_info *f6i, *prev;
rt = addrconf_dst_alloc(net, idev, &ifp->addr, false, f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false,
GFP_ATOMIC); GFP_ATOMIC);
if (IS_ERR(rt)) if (IS_ERR(f6i))
return PTR_ERR(rt); return PTR_ERR(f6i);
/* ifp->rt can be accessed outside of rtnl */ /* ifp->rt can be accessed outside of rtnl */
spin_lock(&ifp->lock); spin_lock(&ifp->lock);
prev = ifp->rt; prev = ifp->rt;
ifp->rt = rt; ifp->rt = f6i;
spin_unlock(&ifp->lock); spin_unlock(&ifp->lock);
fib6_info_release(prev); fib6_info_release(prev);
...@@ -4817,9 +4817,10 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, ...@@ -4817,9 +4817,10 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
u32 portid, u32 seq, int event, unsigned int flags) u32 portid, u32 seq, int event, unsigned int flags)
{ {
struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt);
int ifindex = dev ? dev->ifindex : 1;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
u8 scope = RT_SCOPE_UNIVERSE; u8 scope = RT_SCOPE_UNIVERSE;
int ifindex = ifaca->aca_idev->dev->ifindex;
if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE)
scope = RT_SCOPE_SITE; scope = RT_SCOPE_SITE;
...@@ -5612,14 +5613,14 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) ...@@ -5612,14 +5613,14 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
* our DAD process, so we don't need * our DAD process, so we don't need
* to do it again * to do it again
*/ */
if (!rcu_access_pointer(ifp->rt->rt6i_node)) if (!rcu_access_pointer(ifp->rt->fib6_node))
ip6_ins_rt(net, ifp->rt); ip6_ins_rt(net, ifp->rt);
if (ifp->idev->cnf.forwarding) if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp); addrconf_join_anycast(ifp);
if (!ipv6_addr_any(&ifp->peer_addr)) if (!ipv6_addr_any(&ifp->peer_addr))
addrconf_prefix_route(&ifp->peer_addr, 128, addrconf_prefix_route(&ifp->peer_addr, 128,
ifp->idev->dev, 0, 0, ifp->idev->dev, 0, 0,
GFP_KERNEL); GFP_ATOMIC);
break; break;
case RTM_DELADDR: case RTM_DELADDR:
if (ifp->idev->cnf.forwarding) if (ifp->idev->cnf.forwarding)
......
...@@ -212,16 +212,14 @@ static void aca_get(struct ifacaddr6 *aca) ...@@ -212,16 +212,14 @@ static void aca_get(struct ifacaddr6 *aca)
static void aca_put(struct ifacaddr6 *ac) static void aca_put(struct ifacaddr6 *ac)
{ {
if (refcount_dec_and_test(&ac->aca_refcnt)) { if (refcount_dec_and_test(&ac->aca_refcnt)) {
in6_dev_put(ac->aca_idev);
fib6_info_release(ac->aca_rt); fib6_info_release(ac->aca_rt);
kfree(ac); kfree(ac);
} }
} }
static struct ifacaddr6 *aca_alloc(struct fib6_info *rt, static struct ifacaddr6 *aca_alloc(struct fib6_info *f6i,
const struct in6_addr *addr) const struct in6_addr *addr)
{ {
struct inet6_dev *idev = rt->rt6i_idev;
struct ifacaddr6 *aca; struct ifacaddr6 *aca;
aca = kzalloc(sizeof(*aca), GFP_ATOMIC); aca = kzalloc(sizeof(*aca), GFP_ATOMIC);
...@@ -229,10 +227,8 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *rt, ...@@ -229,10 +227,8 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *rt,
return NULL; return NULL;
aca->aca_addr = *addr; aca->aca_addr = *addr;
in6_dev_hold(idev); fib6_info_hold(f6i);
aca->aca_idev = idev; aca->aca_rt = f6i;
fib6_info_hold(rt);
aca->aca_rt = rt;
aca->aca_users = 1; aca->aca_users = 1;
/* aca_tstamp should be updated upon changes */ /* aca_tstamp should be updated upon changes */
aca->aca_cstamp = aca->aca_tstamp = jiffies; aca->aca_cstamp = aca->aca_tstamp = jiffies;
...@@ -247,7 +243,7 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *rt, ...@@ -247,7 +243,7 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *rt,
int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
{ {
struct ifacaddr6 *aca; struct ifacaddr6 *aca;
struct fib6_info *rt; struct fib6_info *f6i;
struct net *net; struct net *net;
int err; int err;
...@@ -268,14 +264,14 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) ...@@ -268,14 +264,14 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
} }
net = dev_net(idev->dev); net = dev_net(idev->dev);
rt = addrconf_dst_alloc(net, idev, addr, true, GFP_ATOMIC); f6i = addrconf_f6i_alloc(net, idev, addr, true, GFP_ATOMIC);
if (IS_ERR(rt)) { if (IS_ERR(f6i)) {
err = PTR_ERR(rt); err = PTR_ERR(f6i);
goto out; goto out;
} }
aca = aca_alloc(rt, addr); aca = aca_alloc(f6i, addr);
if (!aca) { if (!aca) {
fib6_info_release(rt); fib6_info_release(f6i);
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
...@@ -289,7 +285,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) ...@@ -289,7 +285,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
aca_get(aca); aca_get(aca);
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
ip6_ins_rt(net, rt); ip6_ins_rt(net, f6i);
addrconf_join_solict(idev->dev, &aca->aca_addr); addrconf_join_solict(idev->dev, &aca->aca_addr);
......
...@@ -105,12 +105,12 @@ enum { ...@@ -105,12 +105,12 @@ enum {
FIB6_NO_SERNUM_CHANGE = 0, FIB6_NO_SERNUM_CHANGE = 0,
}; };
void fib6_update_sernum(struct net *net, struct fib6_info *rt) void fib6_update_sernum(struct net *net, struct fib6_info *f6i)
{ {
struct fib6_node *fn; struct fib6_node *fn;
fn = rcu_dereference_protected(rt->rt6i_node, fn = rcu_dereference_protected(f6i->fib6_node,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&f6i->fib6_table->tb6_lock));
if (fn) if (fn)
fn->fn_sernum = fib6_new_sernum(net); fn->fn_sernum = fib6_new_sernum(net);
} }
...@@ -159,10 +159,10 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags) ...@@ -159,10 +159,10 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags)
return NULL; return NULL;
} }
INIT_LIST_HEAD(&f6i->rt6i_siblings); INIT_LIST_HEAD(&f6i->fib6_siblings);
f6i->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; f6i->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
atomic_inc(&f6i->rt6i_ref); atomic_inc(&f6i->fib6_ref);
return f6i; return f6i;
} }
...@@ -172,7 +172,7 @@ void fib6_info_destroy(struct fib6_info *f6i) ...@@ -172,7 +172,7 @@ void fib6_info_destroy(struct fib6_info *f6i)
struct rt6_exception_bucket *bucket; struct rt6_exception_bucket *bucket;
struct dst_metrics *m; struct dst_metrics *m;
WARN_ON(f6i->rt6i_node); WARN_ON(f6i->fib6_node);
bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket, 1); bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket, 1);
if (bucket) { if (bucket) {
...@@ -197,8 +197,6 @@ void fib6_info_destroy(struct fib6_info *f6i) ...@@ -197,8 +197,6 @@ void fib6_info_destroy(struct fib6_info *f6i)
} }
} }
if (f6i->rt6i_idev)
in6_dev_put(f6i->rt6i_idev);
if (f6i->fib6_nh.nh_dev) if (f6i->fib6_nh.nh_dev)
dev_put(f6i->fib6_nh.nh_dev); dev_put(f6i->fib6_nh.nh_dev);
...@@ -401,7 +399,7 @@ static int call_fib6_entry_notifiers(struct net *net, ...@@ -401,7 +399,7 @@ static int call_fib6_entry_notifiers(struct net *net,
.rt = rt, .rt = rt,
}; };
rt->rt6i_table->fib_seq++; rt->fib6_table->fib_seq++;
return call_fib6_notifiers(net, event_type, &info.info); return call_fib6_notifiers(net, event_type, &info.info);
} }
...@@ -483,10 +481,10 @@ static int fib6_dump_node(struct fib6_walker *w) ...@@ -483,10 +481,10 @@ static int fib6_dump_node(struct fib6_walker *w)
* last sibling of this route (no need to dump the * last sibling of this route (no need to dump the
* sibling routes again) * sibling routes again)
*/ */
if (rt->rt6i_nsiblings) if (rt->fib6_nsiblings)
rt = list_last_entry(&rt->rt6i_siblings, rt = list_last_entry(&rt->fib6_siblings,
struct fib6_info, struct fib6_info,
rt6i_siblings); fib6_siblings);
} }
w->leaf = NULL; w->leaf = NULL;
return 0; return 0;
...@@ -810,7 +808,7 @@ static struct fib6_node *fib6_add_1(struct net *net, ...@@ -810,7 +808,7 @@ static struct fib6_node *fib6_add_1(struct net *net,
RCU_INIT_POINTER(in->parent, pn); RCU_INIT_POINTER(in->parent, pn);
in->leaf = fn->leaf; in->leaf = fn->leaf;
atomic_inc(&rcu_dereference_protected(in->leaf, atomic_inc(&rcu_dereference_protected(in->leaf,
lockdep_is_held(&table->tb6_lock))->rt6i_ref); lockdep_is_held(&table->tb6_lock))->fib6_ref);
/* update parent pointer */ /* update parent pointer */
if (dir) if (dir)
...@@ -865,9 +863,9 @@ static struct fib6_node *fib6_add_1(struct net *net, ...@@ -865,9 +863,9 @@ static struct fib6_node *fib6_add_1(struct net *net,
static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
struct net *net) struct net *net)
{ {
struct fib6_table *table = rt->rt6i_table; struct fib6_table *table = rt->fib6_table;
if (atomic_read(&rt->rt6i_ref) != 1) { if (atomic_read(&rt->fib6_ref) != 1) {
/* This route is used as dummy address holder in some split /* This route is used as dummy address holder in some split
* nodes. It is not leaked, but it still holds other resources, * nodes. It is not leaked, but it still holds other resources,
* which must be released in time. So, scan ascendant nodes * which must be released in time. So, scan ascendant nodes
...@@ -880,7 +878,7 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, ...@@ -880,7 +878,7 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
struct fib6_info *new_leaf; struct fib6_info *new_leaf;
if (!(fn->fn_flags & RTN_RTINFO) && leaf == rt) { if (!(fn->fn_flags & RTN_RTINFO) && leaf == rt) {
new_leaf = fib6_find_prefix(net, table, fn); new_leaf = fib6_find_prefix(net, table, fn);
atomic_inc(&new_leaf->rt6i_ref); atomic_inc(&new_leaf->fib6_ref);
rcu_assign_pointer(fn->leaf, new_leaf); rcu_assign_pointer(fn->leaf, new_leaf);
fib6_info_release(rt); fib6_info_release(rt);
...@@ -919,7 +917,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -919,7 +917,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct fib6_info *leaf = rcu_dereference_protected(fn->leaf, struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
struct fib6_info *iter = NULL; struct fib6_info *iter = NULL;
struct fib6_info __rcu **ins; struct fib6_info __rcu **ins;
struct fib6_info __rcu **fallback_ins = NULL; struct fib6_info __rcu **fallback_ins = NULL;
...@@ -939,12 +937,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -939,12 +937,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
for (iter = leaf; iter; for (iter = leaf; iter;
iter = rcu_dereference_protected(iter->rt6_next, iter = rcu_dereference_protected(iter->rt6_next,
lockdep_is_held(&rt->rt6i_table->tb6_lock))) { lockdep_is_held(&rt->fib6_table->tb6_lock))) {
/* /*
* Search for duplicates * Search for duplicates
*/ */
if (iter->rt6i_metric == rt->rt6i_metric) { if (iter->fib6_metric == rt->fib6_metric) {
/* /*
* Same priority level * Same priority level
*/ */
...@@ -964,11 +962,11 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -964,11 +962,11 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
} }
if (rt6_duplicate_nexthop(iter, rt)) { if (rt6_duplicate_nexthop(iter, rt)) {
if (rt->rt6i_nsiblings) if (rt->fib6_nsiblings)
rt->rt6i_nsiblings = 0; rt->fib6_nsiblings = 0;
if (!(iter->rt6i_flags & RTF_EXPIRES)) if (!(iter->fib6_flags & RTF_EXPIRES))
return -EEXIST; return -EEXIST;
if (!(rt->rt6i_flags & RTF_EXPIRES)) if (!(rt->fib6_flags & RTF_EXPIRES))
fib6_clean_expires(iter); fib6_clean_expires(iter);
else else
fib6_set_expires(iter, rt->expires); fib6_set_expires(iter, rt->expires);
...@@ -988,10 +986,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -988,10 +986,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
*/ */
if (rt_can_ecmp && if (rt_can_ecmp &&
rt6_qualify_for_ecmp(iter)) rt6_qualify_for_ecmp(iter))
rt->rt6i_nsiblings++; rt->fib6_nsiblings++;
} }
if (iter->rt6i_metric > rt->rt6i_metric) if (iter->fib6_metric > rt->fib6_metric)
break; break;
next_iter: next_iter:
...@@ -1002,7 +1000,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1002,7 +1000,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
/* No ECMP-able route found, replace first non-ECMP one */ /* No ECMP-able route found, replace first non-ECMP one */
ins = fallback_ins; ins = fallback_ins;
iter = rcu_dereference_protected(*ins, iter = rcu_dereference_protected(*ins,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
found++; found++;
} }
...@@ -1011,34 +1009,34 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1011,34 +1009,34 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
fn->rr_ptr = NULL; fn->rr_ptr = NULL;
/* Link this route to others same route. */ /* Link this route to others same route. */
if (rt->rt6i_nsiblings) { if (rt->fib6_nsiblings) {
unsigned int rt6i_nsiblings; unsigned int fib6_nsiblings;
struct fib6_info *sibling, *temp_sibling; struct fib6_info *sibling, *temp_sibling;
/* Find the first route that have the same metric */ /* Find the first route that have the same metric */
sibling = leaf; sibling = leaf;
while (sibling) { while (sibling) {
if (sibling->rt6i_metric == rt->rt6i_metric && if (sibling->fib6_metric == rt->fib6_metric &&
rt6_qualify_for_ecmp(sibling)) { rt6_qualify_for_ecmp(sibling)) {
list_add_tail(&rt->rt6i_siblings, list_add_tail(&rt->fib6_siblings,
&sibling->rt6i_siblings); &sibling->fib6_siblings);
break; break;
} }
sibling = rcu_dereference_protected(sibling->rt6_next, sibling = rcu_dereference_protected(sibling->rt6_next,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
} }
/* For each sibling in the list, increment the counter of /* For each sibling in the list, increment the counter of
* siblings. BUG() if counters does not match, list of siblings * siblings. BUG() if counters does not match, list of siblings
* is broken! * is broken!
*/ */
rt6i_nsiblings = 0; fib6_nsiblings = 0;
list_for_each_entry_safe(sibling, temp_sibling, list_for_each_entry_safe(sibling, temp_sibling,
&rt->rt6i_siblings, rt6i_siblings) { &rt->fib6_siblings, fib6_siblings) {
sibling->rt6i_nsiblings++; sibling->fib6_nsiblings++;
BUG_ON(sibling->rt6i_nsiblings != rt->rt6i_nsiblings); BUG_ON(sibling->fib6_nsiblings != rt->fib6_nsiblings);
rt6i_nsiblings++; fib6_nsiblings++;
} }
BUG_ON(rt6i_nsiblings != rt->rt6i_nsiblings); BUG_ON(fib6_nsiblings != rt->fib6_nsiblings);
rt6_multipath_rebalance(temp_sibling); rt6_multipath_rebalance(temp_sibling);
} }
...@@ -1059,8 +1057,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1059,8 +1057,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
return err; return err;
rcu_assign_pointer(rt->rt6_next, iter); rcu_assign_pointer(rt->rt6_next, iter);
atomic_inc(&rt->rt6i_ref); atomic_inc(&rt->fib6_ref);
rcu_assign_pointer(rt->rt6i_node, fn); rcu_assign_pointer(rt->fib6_node, fn);
rcu_assign_pointer(*ins, rt); rcu_assign_pointer(*ins, rt);
if (!info->skip_notify) if (!info->skip_notify)
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
...@@ -1087,8 +1085,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1087,8 +1085,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
if (err) if (err)
return err; return err;
atomic_inc(&rt->rt6i_ref); atomic_inc(&rt->fib6_ref);
rcu_assign_pointer(rt->rt6i_node, fn); rcu_assign_pointer(rt->fib6_node, fn);
rt->rt6_next = iter->rt6_next; rt->rt6_next = iter->rt6_next;
rcu_assign_pointer(*ins, rt); rcu_assign_pointer(*ins, rt);
if (!info->skip_notify) if (!info->skip_notify)
...@@ -1097,8 +1095,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1097,8 +1095,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
info->nl_net->ipv6.rt6_stats->fib_route_nodes++; info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
fn->fn_flags |= RTN_RTINFO; fn->fn_flags |= RTN_RTINFO;
} }
nsiblings = iter->rt6i_nsiblings; nsiblings = iter->fib6_nsiblings;
iter->rt6i_node = NULL; iter->fib6_node = NULL;
fib6_purge_rt(iter, fn, info->nl_net); fib6_purge_rt(iter, fn, info->nl_net);
if (rcu_access_pointer(fn->rr_ptr) == iter) if (rcu_access_pointer(fn->rr_ptr) == iter)
fn->rr_ptr = NULL; fn->rr_ptr = NULL;
...@@ -1108,13 +1106,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1108,13 +1106,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
/* Replacing an ECMP route, remove all siblings */ /* Replacing an ECMP route, remove all siblings */
ins = &rt->rt6_next; ins = &rt->rt6_next;
iter = rcu_dereference_protected(*ins, iter = rcu_dereference_protected(*ins,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
while (iter) { while (iter) {
if (iter->rt6i_metric > rt->rt6i_metric) if (iter->fib6_metric > rt->fib6_metric)
break; break;
if (rt6_qualify_for_ecmp(iter)) { if (rt6_qualify_for_ecmp(iter)) {
*ins = iter->rt6_next; *ins = iter->rt6_next;
iter->rt6i_node = NULL; iter->fib6_node = NULL;
fib6_purge_rt(iter, fn, info->nl_net); fib6_purge_rt(iter, fn, info->nl_net);
if (rcu_access_pointer(fn->rr_ptr) == iter) if (rcu_access_pointer(fn->rr_ptr) == iter)
fn->rr_ptr = NULL; fn->rr_ptr = NULL;
...@@ -1125,7 +1123,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1125,7 +1123,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
ins = &iter->rt6_next; ins = &iter->rt6_next;
} }
iter = rcu_dereference_protected(*ins, iter = rcu_dereference_protected(*ins,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
} }
WARN_ON(nsiblings != 0); WARN_ON(nsiblings != 0);
} }
...@@ -1137,7 +1135,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1137,7 +1135,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
static void fib6_start_gc(struct net *net, struct fib6_info *rt) static void fib6_start_gc(struct net *net, struct fib6_info *rt)
{ {
if (!timer_pending(&net->ipv6.ip6_fib_timer) && if (!timer_pending(&net->ipv6.ip6_fib_timer) &&
(rt->rt6i_flags & RTF_EXPIRES)) (rt->fib6_flags & RTF_EXPIRES))
mod_timer(&net->ipv6.ip6_fib_timer, mod_timer(&net->ipv6.ip6_fib_timer,
jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
} }
...@@ -1152,15 +1150,15 @@ void fib6_force_start_gc(struct net *net) ...@@ -1152,15 +1150,15 @@ void fib6_force_start_gc(struct net *net)
static void __fib6_update_sernum_upto_root(struct fib6_info *rt, static void __fib6_update_sernum_upto_root(struct fib6_info *rt,
int sernum) int sernum)
{ {
struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node, struct fib6_node *fn = rcu_dereference_protected(rt->fib6_node,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
/* paired with smp_rmb() in rt6_get_cookie_safe() */ /* paired with smp_rmb() in rt6_get_cookie_safe() */
smp_wmb(); smp_wmb();
while (fn) { while (fn) {
fn->fn_sernum = sernum; fn->fn_sernum = sernum;
fn = rcu_dereference_protected(fn->parent, fn = rcu_dereference_protected(fn->parent,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
} }
} }
...@@ -1179,7 +1177,7 @@ void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt) ...@@ -1179,7 +1177,7 @@ void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt)
int fib6_add(struct fib6_node *root, struct fib6_info *rt, int fib6_add(struct fib6_node *root, struct fib6_info *rt,
struct nl_info *info, struct netlink_ext_ack *extack) struct nl_info *info, struct netlink_ext_ack *extack)
{ {
struct fib6_table *table = rt->rt6i_table; struct fib6_table *table = rt->fib6_table;
struct fib6_node *fn, *pn = NULL; struct fib6_node *fn, *pn = NULL;
int err = -ENOMEM; int err = -ENOMEM;
int allow_create = 1; int allow_create = 1;
...@@ -1196,8 +1194,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1196,8 +1194,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n"); pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
fn = fib6_add_1(info->nl_net, table, root, fn = fib6_add_1(info->nl_net, table, root,
&rt->rt6i_dst.addr, rt->rt6i_dst.plen, &rt->fib6_dst.addr, rt->fib6_dst.plen,
offsetof(struct fib6_info, rt6i_dst), allow_create, offsetof(struct fib6_info, fib6_dst), allow_create,
replace_required, extack); replace_required, extack);
if (IS_ERR(fn)) { if (IS_ERR(fn)) {
err = PTR_ERR(fn); err = PTR_ERR(fn);
...@@ -1208,7 +1206,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1208,7 +1206,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
pn = fn; pn = fn;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
if (rt->rt6i_src.plen) { if (rt->fib6_src.plen) {
struct fib6_node *sn; struct fib6_node *sn;
if (!rcu_access_pointer(fn->subtree)) { if (!rcu_access_pointer(fn->subtree)) {
...@@ -1229,7 +1227,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1229,7 +1227,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
if (!sfn) if (!sfn)
goto failure; goto failure;
atomic_inc(&info->nl_net->ipv6.fib6_null_entry->rt6i_ref); atomic_inc(&info->nl_net->ipv6.fib6_null_entry->fib6_ref);
rcu_assign_pointer(sfn->leaf, rcu_assign_pointer(sfn->leaf,
info->nl_net->ipv6.fib6_null_entry); info->nl_net->ipv6.fib6_null_entry);
sfn->fn_flags = RTN_ROOT; sfn->fn_flags = RTN_ROOT;
...@@ -1237,8 +1235,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1237,8 +1235,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
/* Now add the first leaf node to new subtree */ /* Now add the first leaf node to new subtree */
sn = fib6_add_1(info->nl_net, table, sfn, sn = fib6_add_1(info->nl_net, table, sfn,
&rt->rt6i_src.addr, rt->rt6i_src.plen, &rt->fib6_src.addr, rt->fib6_src.plen,
offsetof(struct fib6_info, rt6i_src), offsetof(struct fib6_info, fib6_src),
allow_create, replace_required, extack); allow_create, replace_required, extack);
if (IS_ERR(sn)) { if (IS_ERR(sn)) {
...@@ -1256,8 +1254,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1256,8 +1254,8 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
rcu_assign_pointer(fn->subtree, sfn); rcu_assign_pointer(fn->subtree, sfn);
} else { } else {
sn = fib6_add_1(info->nl_net, table, FIB6_SUBTREE(fn), sn = fib6_add_1(info->nl_net, table, FIB6_SUBTREE(fn),
&rt->rt6i_src.addr, rt->rt6i_src.plen, &rt->fib6_src.addr, rt->fib6_src.plen,
offsetof(struct fib6_info, rt6i_src), offsetof(struct fib6_info, fib6_src),
allow_create, replace_required, extack); allow_create, replace_required, extack);
if (IS_ERR(sn)) { if (IS_ERR(sn)) {
...@@ -1272,7 +1270,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, ...@@ -1272,7 +1270,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
rcu_assign_pointer(fn->leaf, rcu_assign_pointer(fn->leaf,
info->nl_net->ipv6.fib6_null_entry); info->nl_net->ipv6.fib6_null_entry);
} else { } else {
atomic_inc(&rt->rt6i_ref); atomic_inc(&rt->fib6_ref);
rcu_assign_pointer(fn->leaf, rt); rcu_assign_pointer(fn->leaf, rt);
} }
} }
...@@ -1421,12 +1419,12 @@ struct fib6_node *fib6_lookup(struct fib6_node *root, const struct in6_addr *dad ...@@ -1421,12 +1419,12 @@ struct fib6_node *fib6_lookup(struct fib6_node *root, const struct in6_addr *dad
struct fib6_node *fn; struct fib6_node *fn;
struct lookup_args args[] = { struct lookup_args args[] = {
{ {
.offset = offsetof(struct fib6_info, rt6i_dst), .offset = offsetof(struct fib6_info, fib6_dst),
.addr = daddr, .addr = daddr,
}, },
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
{ {
.offset = offsetof(struct fib6_info, rt6i_src), .offset = offsetof(struct fib6_info, fib6_src),
.addr = saddr, .addr = saddr,
}, },
#endif #endif
...@@ -1511,7 +1509,7 @@ struct fib6_node *fib6_locate(struct fib6_node *root, ...@@ -1511,7 +1509,7 @@ struct fib6_node *fib6_locate(struct fib6_node *root,
struct fib6_node *fn; struct fib6_node *fn;
fn = fib6_locate_1(root, daddr, dst_len, fn = fib6_locate_1(root, daddr, dst_len,
offsetof(struct fib6_info, rt6i_dst), offsetof(struct fib6_info, fib6_dst),
exact_match); exact_match);
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
...@@ -1522,7 +1520,7 @@ struct fib6_node *fib6_locate(struct fib6_node *root, ...@@ -1522,7 +1520,7 @@ struct fib6_node *fib6_locate(struct fib6_node *root,
if (subtree) { if (subtree) {
fn = fib6_locate_1(subtree, saddr, src_len, fn = fib6_locate_1(subtree, saddr, src_len,
offsetof(struct fib6_info, rt6i_src), offsetof(struct fib6_info, fib6_src),
exact_match); exact_match);
} }
} }
...@@ -1706,7 +1704,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn, ...@@ -1706,7 +1704,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
/* Unlink it */ /* Unlink it */
*rtp = rt->rt6_next; *rtp = rt->rt6_next;
rt->rt6i_node = NULL; rt->fib6_node = NULL;
net->ipv6.rt6_stats->fib_rt_entries--; net->ipv6.rt6_stats->fib_rt_entries--;
net->ipv6.rt6_stats->fib_discarded_routes++; net->ipv6.rt6_stats->fib_discarded_routes++;
...@@ -1718,14 +1716,14 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn, ...@@ -1718,14 +1716,14 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
fn->rr_ptr = NULL; fn->rr_ptr = NULL;
/* Remove this entry from other siblings */ /* Remove this entry from other siblings */
if (rt->rt6i_nsiblings) { if (rt->fib6_nsiblings) {
struct fib6_info *sibling, *next_sibling; struct fib6_info *sibling, *next_sibling;
list_for_each_entry_safe(sibling, next_sibling, list_for_each_entry_safe(sibling, next_sibling,
&rt->rt6i_siblings, rt6i_siblings) &rt->fib6_siblings, fib6_siblings)
sibling->rt6i_nsiblings--; sibling->fib6_nsiblings--;
rt->rt6i_nsiblings = 0; rt->fib6_nsiblings = 0;
list_del_init(&rt->rt6i_siblings); list_del_init(&rt->fib6_siblings);
rt6_multipath_rebalance(next_sibling); rt6_multipath_rebalance(next_sibling);
} }
...@@ -1765,9 +1763,9 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn, ...@@ -1765,9 +1763,9 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
/* Need to own table->tb6_lock */ /* Need to own table->tb6_lock */
int fib6_del(struct fib6_info *rt, struct nl_info *info) int fib6_del(struct fib6_info *rt, struct nl_info *info)
{ {
struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node, struct fib6_node *fn = rcu_dereference_protected(rt->fib6_node,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
struct fib6_table *table = rt->rt6i_table; struct fib6_table *table = rt->fib6_table;
struct net *net = info->nl_net; struct net *net = info->nl_net;
struct fib6_info __rcu **rtp; struct fib6_info __rcu **rtp;
struct fib6_info __rcu **rtp_next; struct fib6_info __rcu **rtp_next;
...@@ -1951,17 +1949,17 @@ static int fib6_clean_node(struct fib6_walker *w) ...@@ -1951,17 +1949,17 @@ static int fib6_clean_node(struct fib6_walker *w)
#if RT6_DEBUG >= 2 #if RT6_DEBUG >= 2
pr_debug("%s: del failed: rt=%p@%p err=%d\n", pr_debug("%s: del failed: rt=%p@%p err=%d\n",
__func__, rt, __func__, rt,
rcu_access_pointer(rt->rt6i_node), rcu_access_pointer(rt->fib6_node),
res); res);
#endif #endif
continue; continue;
} }
return 0; return 0;
} else if (res == -2) { } else if (res == -2) {
if (WARN_ON(!rt->rt6i_nsiblings)) if (WARN_ON(!rt->fib6_nsiblings))
continue; continue;
rt = list_last_entry(&rt->rt6i_siblings, rt = list_last_entry(&rt->fib6_siblings,
struct fib6_info, rt6i_siblings); struct fib6_info, fib6_siblings);
continue; continue;
} }
WARN_ON(res != 0); WARN_ON(res != 0);
...@@ -2045,7 +2043,7 @@ static int fib6_age(struct fib6_info *rt, void *arg) ...@@ -2045,7 +2043,7 @@ static int fib6_age(struct fib6_info *rt, void *arg)
* Routes are expired even if they are in use. * Routes are expired even if they are in use.
*/ */
if (rt->rt6i_flags & RTF_EXPIRES && rt->expires) { if (rt->fib6_flags & RTF_EXPIRES && rt->expires) {
if (time_after(now, rt->expires)) { if (time_after(now, rt->expires)) {
RT6_TRACE("expiring %p\n", rt); RT6_TRACE("expiring %p\n", rt);
return -1; return -1;
...@@ -2243,22 +2241,22 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v) ...@@ -2243,22 +2241,22 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
struct ipv6_route_iter *iter = seq->private; struct ipv6_route_iter *iter = seq->private;
const struct net_device *dev; const struct net_device *dev;
seq_printf(seq, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); seq_printf(seq, "%pi6 %02x ", &rt->fib6_dst.addr, rt->fib6_dst.plen);
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
seq_printf(seq, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen); seq_printf(seq, "%pi6 %02x ", &rt->fib6_src.addr, rt->fib6_src.plen);
#else #else
seq_puts(seq, "00000000000000000000000000000000 00 "); seq_puts(seq, "00000000000000000000000000000000 00 ");
#endif #endif
if (rt->rt6i_flags & RTF_GATEWAY) if (rt->fib6_flags & RTF_GATEWAY)
seq_printf(seq, "%pi6", &rt->fib6_nh.nh_gw); seq_printf(seq, "%pi6", &rt->fib6_nh.nh_gw);
else else
seq_puts(seq, "00000000000000000000000000000000"); seq_puts(seq, "00000000000000000000000000000000");
dev = rt->fib6_nh.nh_dev; dev = rt->fib6_nh.nh_dev;
seq_printf(seq, " %08x %08x %08x %08x %8s\n", seq_printf(seq, " %08x %08x %08x %08x %8s\n",
rt->rt6i_metric, atomic_read(&rt->rt6i_ref), 0, rt->fib6_metric, atomic_read(&rt->fib6_ref), 0,
rt->rt6i_flags, dev ? dev->name : ""); rt->fib6_flags, dev ? dev->name : "");
iter->w.leaf = NULL; iter->w.leaf = NULL;
return 0; return 0;
} }
......
...@@ -1318,7 +1318,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -1318,7 +1318,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
} }
neigh->flags |= NTF_ROUTER; neigh->flags |= NTF_ROUTER;
} else if (rt) { } else if (rt) {
rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); rt->fib6_flags = (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
} }
if (rt) if (rt)
......
...@@ -284,10 +284,10 @@ static const u32 ip6_template_metrics[RTAX_MAX] = { ...@@ -284,10 +284,10 @@ static const u32 ip6_template_metrics[RTAX_MAX] = {
}; };
static const struct fib6_info fib6_null_entry_template = { static const struct fib6_info fib6_null_entry_template = {
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL, .fib6_protocol = RTPROT_KERNEL,
.rt6i_metric = ~(u32)0, .fib6_metric = ~(u32)0,
.rt6i_ref = ATOMIC_INIT(1), .fib6_ref = ATOMIC_INIT(1),
.fib6_type = RTN_UNREACHABLE, .fib6_type = RTN_UNREACHABLE,
.fib6_metrics = (struct dst_metrics *)&dst_default_metrics, .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
}; };
...@@ -429,8 +429,8 @@ static struct fib6_info *rt6_multipath_select(const struct net *net, ...@@ -429,8 +429,8 @@ static struct fib6_info *rt6_multipath_select(const struct net *net,
if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound)) if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound))
return match; return match;
list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings, list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
rt6i_siblings) { fib6_siblings) {
int nh_upper_bound; int nh_upper_bound;
nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound); nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound);
...@@ -455,7 +455,6 @@ static inline struct fib6_info *rt6_device_match(struct net *net, ...@@ -455,7 +455,6 @@ static inline struct fib6_info *rt6_device_match(struct net *net,
int oif, int oif,
int flags) int flags)
{ {
struct fib6_info *local = NULL;
struct fib6_info *sprt; struct fib6_info *sprt;
if (!oif && ipv6_addr_any(saddr) && if (!oif && ipv6_addr_any(saddr) &&
...@@ -471,17 +470,6 @@ static inline struct fib6_info *rt6_device_match(struct net *net, ...@@ -471,17 +470,6 @@ static inline struct fib6_info *rt6_device_match(struct net *net,
if (oif) { if (oif) {
if (dev->ifindex == oif) if (dev->ifindex == oif)
return sprt; return sprt;
if (dev->flags & IFF_LOOPBACK) {
if (!sprt->rt6i_idev ||
sprt->rt6i_idev->dev->ifindex != oif) {
if (flags & RT6_LOOKUP_F_IFACE)
continue;
if (local &&
local->rt6i_idev->dev->ifindex == oif)
continue;
}
local = sprt;
}
} else { } else {
if (ipv6_chk_addr(net, saddr, dev, if (ipv6_chk_addr(net, saddr, dev,
flags & RT6_LOOKUP_F_IFACE)) flags & RT6_LOOKUP_F_IFACE))
...@@ -489,13 +477,8 @@ static inline struct fib6_info *rt6_device_match(struct net *net, ...@@ -489,13 +477,8 @@ static inline struct fib6_info *rt6_device_match(struct net *net,
} }
} }
if (oif) { if (oif && flags & RT6_LOOKUP_F_IFACE)
if (local) return net->ipv6.fib6_null_entry;
return local;
if (flags & RT6_LOOKUP_F_IFACE)
return net->ipv6.fib6_null_entry;
}
return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt; return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
} }
...@@ -534,7 +517,7 @@ static void rt6_probe(struct fib6_info *rt) ...@@ -534,7 +517,7 @@ static void rt6_probe(struct fib6_info *rt)
* Router Reachability Probe MUST be rate-limited * Router Reachability Probe MUST be rate-limited
* to no more than one per minute. * to no more than one per minute.
*/ */
if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
return; return;
nh_gw = &rt->fib6_nh.nh_gw; nh_gw = &rt->fib6_nh.nh_gw;
...@@ -542,15 +525,17 @@ static void rt6_probe(struct fib6_info *rt) ...@@ -542,15 +525,17 @@ static void rt6_probe(struct fib6_info *rt)
rcu_read_lock_bh(); rcu_read_lock_bh();
neigh = __ipv6_neigh_lookup_noref(dev, nh_gw); neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
if (neigh) { if (neigh) {
struct inet6_dev *idev;
if (neigh->nud_state & NUD_VALID) if (neigh->nud_state & NUD_VALID)
goto out; goto out;
idev = __in6_dev_get(dev);
work = NULL; work = NULL;
write_lock(&neigh->lock); write_lock(&neigh->lock);
if (!(neigh->nud_state & NUD_VALID) && if (!(neigh->nud_state & NUD_VALID) &&
time_after(jiffies, time_after(jiffies,
neigh->updated + neigh->updated + idev->cnf.rtr_probe_interval)) {
rt->rt6i_idev->cnf.rtr_probe_interval)) {
work = kmalloc(sizeof(*work), GFP_ATOMIC); work = kmalloc(sizeof(*work), GFP_ATOMIC);
if (work) if (work)
__neigh_set_probe_once(neigh); __neigh_set_probe_once(neigh);
...@@ -586,9 +571,6 @@ static inline int rt6_check_dev(struct fib6_info *rt, int oif) ...@@ -586,9 +571,6 @@ static inline int rt6_check_dev(struct fib6_info *rt, int oif)
if (!oif || dev->ifindex == oif) if (!oif || dev->ifindex == oif)
return 2; return 2;
if ((dev->flags & IFF_LOOPBACK) &&
rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
return 1;
return 0; return 0;
} }
...@@ -597,8 +579,8 @@ static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt) ...@@ -597,8 +579,8 @@ static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
enum rt6_nud_state ret = RT6_NUD_FAIL_HARD; enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
struct neighbour *neigh; struct neighbour *neigh;
if (rt->rt6i_flags & RTF_NONEXTHOP || if (rt->fib6_flags & RTF_NONEXTHOP ||
!(rt->rt6i_flags & RTF_GATEWAY)) !(rt->fib6_flags & RTF_GATEWAY))
return RT6_NUD_SUCCEED; return RT6_NUD_SUCCEED;
rcu_read_lock_bh(); rcu_read_lock_bh();
...@@ -632,7 +614,7 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict) ...@@ -632,7 +614,7 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
if (!m && (strict & RT6_LOOKUP_F_IFACE)) if (!m && (strict & RT6_LOOKUP_F_IFACE))
return RT6_NUD_FAIL_HARD; return RT6_NUD_FAIL_HARD;
#ifdef CONFIG_IPV6_ROUTER_PREF #ifdef CONFIG_IPV6_ROUTER_PREF
m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->fib6_flags)) << 2;
#endif #endif
if (strict & RT6_LOOKUP_F_REACHABLE) { if (strict & RT6_LOOKUP_F_REACHABLE) {
int n = rt6_check_neigh(rt); int n = rt6_check_neigh(rt);
...@@ -642,18 +624,32 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict) ...@@ -642,18 +624,32 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
return m; return m;
} }
/* called with rc_read_lock held */
static inline bool fib6_ignore_linkdown(const struct fib6_info *f6i)
{
const struct net_device *dev = fib6_info_nh_dev(f6i);
bool rc = false;
if (dev) {
const struct inet6_dev *idev = __in6_dev_get(dev);
rc = !!idev->cnf.ignore_routes_with_linkdown;
}
return rc;
}
static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict, static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict,
int *mpri, struct fib6_info *match, int *mpri, struct fib6_info *match,
bool *do_rr) bool *do_rr)
{ {
int m; int m;
bool match_do_rr = false; bool match_do_rr = false;
struct inet6_dev *idev = rt->rt6i_idev;
if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
goto out; goto out;
if (idev->cnf.ignore_routes_with_linkdown && if (fib6_ignore_linkdown(rt) &&
rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
!(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
goto out; goto out;
...@@ -694,7 +690,7 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn, ...@@ -694,7 +690,7 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
match = NULL; match = NULL;
cont = NULL; cont = NULL;
for (rt = rr_head; rt; rt = rcu_dereference(rt->rt6_next)) { for (rt = rr_head; rt; rt = rcu_dereference(rt->rt6_next)) {
if (rt->rt6i_metric != metric) { if (rt->fib6_metric != metric) {
cont = rt; cont = rt;
break; break;
} }
...@@ -704,7 +700,7 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn, ...@@ -704,7 +700,7 @@ static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
for (rt = leaf; rt && rt != rr_head; for (rt = leaf; rt && rt != rr_head;
rt = rcu_dereference(rt->rt6_next)) { rt = rcu_dereference(rt->rt6_next)) {
if (rt->rt6i_metric != metric) { if (rt->fib6_metric != metric) {
cont = rt; cont = rt;
break; break;
} }
...@@ -741,30 +737,30 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn, ...@@ -741,30 +737,30 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
* (This might happen if all routes under fn are deleted from * (This might happen if all routes under fn are deleted from
* the tree and fib6_repair_tree() is called on the node.) * the tree and fib6_repair_tree() is called on the node.)
*/ */
key_plen = rt0->rt6i_dst.plen; key_plen = rt0->fib6_dst.plen;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
if (rt0->rt6i_src.plen) if (rt0->fib6_src.plen)
key_plen = rt0->rt6i_src.plen; key_plen = rt0->fib6_src.plen;
#endif #endif
if (fn->fn_bit != key_plen) if (fn->fn_bit != key_plen)
return net->ipv6.fib6_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->fib6_metric, oif, strict,
&do_rr); &do_rr);
if (do_rr) { if (do_rr) {
struct fib6_info *next = rcu_dereference(rt0->rt6_next); struct fib6_info *next = rcu_dereference(rt0->rt6_next);
/* no entries matched; do round-robin */ /* no entries matched; do round-robin */
if (!next || next->rt6i_metric != rt0->rt6i_metric) if (!next || next->fib6_metric != rt0->fib6_metric)
next = leaf; next = leaf;
if (next != rt0) { if (next != rt0) {
spin_lock_bh(&leaf->rt6i_table->tb6_lock); spin_lock_bh(&leaf->fib6_table->tb6_lock);
/* make sure next is not being deleted from the tree */ /* make sure next is not being deleted from the tree */
if (next->rt6i_node) if (next->fib6_node)
rcu_assign_pointer(fn->rr_ptr, next); rcu_assign_pointer(fn->rr_ptr, next);
spin_unlock_bh(&leaf->rt6i_table->tb6_lock); spin_unlock_bh(&leaf->fib6_table->tb6_lock);
} }
} }
...@@ -773,7 +769,7 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn, ...@@ -773,7 +769,7 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt) static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
{ {
return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)); return (rt->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
} }
#ifdef CONFIG_IPV6_ROUTE_INFO #ifdef CONFIG_IPV6_ROUTE_INFO
...@@ -837,8 +833,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, ...@@ -837,8 +833,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
dev, pref); dev, pref);
else if (rt) else if (rt)
rt->rt6i_flags = RTF_ROUTEINFO | rt->fib6_flags = RTF_ROUTEINFO |
(rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
if (rt) { if (rt) {
if (!addrconf_finite_timeout(lifetime)) if (!addrconf_finite_timeout(lifetime))
...@@ -861,13 +857,13 @@ static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt) ...@@ -861,13 +857,13 @@ static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
{ {
struct net_device *dev = rt->fib6_nh.nh_dev; struct net_device *dev = rt->fib6_nh.nh_dev;
if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) { if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
/* for copies of local routes, dst->dev needs to be the /* for copies of local routes, dst->dev needs to be the
* device if it is a master device, the master device if * device if it is a master device, the master device if
* device is enslaved, and the loopback as the default * device is enslaved, and the loopback as the default
*/ */
if (netif_is_l3_slave(dev) && if (netif_is_l3_slave(dev) &&
!rt6_need_strict(&rt->rt6i_dst.addr)) !rt6_need_strict(&rt->fib6_dst.addr))
dev = l3mdev_master_dev_rcu(dev); dev = l3mdev_master_dev_rcu(dev);
else if (!netif_is_l3_master(dev)) else if (!netif_is_l3_master(dev))
dev = dev_net(dev)->loopback_dev; dev = dev_net(dev)->loopback_dev;
...@@ -939,7 +935,7 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort) ...@@ -939,7 +935,7 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
{ {
rt->dst.flags |= fib6_info_dst_flags(ort); rt->dst.flags |= fib6_info_dst_flags(ort);
if (ort->rt6i_flags & RTF_REJECT) { if (ort->fib6_flags & RTF_REJECT) {
ip6_rt_init_dst_reject(rt, ort); ip6_rt_init_dst_reject(rt, ort);
return; return;
} }
...@@ -949,7 +945,7 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort) ...@@ -949,7 +945,7 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
if (ort->fib6_type == RTN_LOCAL) { if (ort->fib6_type == RTN_LOCAL) {
rt->dst.input = ip6_input; rt->dst.input = ip6_input;
} else if (ipv6_addr_type(&ort->rt6i_dst.addr) & IPV6_ADDR_MULTICAST) { } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
rt->dst.input = ip6_mc_input; rt->dst.input = ip6_mc_input;
} else { } else {
rt->dst.input = ip6_forward; rt->dst.input = ip6_forward;
...@@ -977,19 +973,19 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from) ...@@ -977,19 +973,19 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort) static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
{ {
struct net_device *dev = fib6_info_nh_dev(ort);
ip6_rt_init_dst(rt, ort); ip6_rt_init_dst(rt, ort);
rt->rt6i_dst = ort->rt6i_dst; rt->rt6i_dst = ort->fib6_dst;
rt->rt6i_idev = ort->rt6i_idev; rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
if (rt->rt6i_idev)
in6_dev_hold(rt->rt6i_idev);
rt->rt6i_gateway = ort->fib6_nh.nh_gw; rt->rt6i_gateway = ort->fib6_nh.nh_gw;
rt->rt6i_flags = ort->rt6i_flags; rt->rt6i_flags = ort->fib6_flags;
rt6_set_from(rt, ort); rt6_set_from(rt, ort);
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
rt->rt6i_src = ort->rt6i_src; rt->rt6i_src = ort->fib6_src;
#endif #endif
rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_prefsrc = ort->fib6_prefsrc;
rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
} }
...@@ -1064,7 +1060,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, ...@@ -1064,7 +1060,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
} else { } else {
f6i = rt6_device_match(net, f6i, &fl6->saddr, f6i = rt6_device_match(net, f6i, &fl6->saddr,
fl6->flowi6_oif, flags); fl6->flowi6_oif, flags);
if (f6i->rt6i_nsiblings && fl6->flowi6_oif == 0) if (f6i->fib6_nsiblings && fl6->flowi6_oif == 0)
f6i = rt6_multipath_select(net, f6i, fl6, f6i = rt6_multipath_select(net, f6i, fl6,
fl6->flowi6_oif, skb, flags); fl6->flowi6_oif, skb, flags);
} }
...@@ -1142,7 +1138,7 @@ static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info, ...@@ -1142,7 +1138,7 @@ static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
int err; int err;
struct fib6_table *table; struct fib6_table *table;
table = rt->rt6i_table; table = rt->fib6_table;
spin_lock_bh(&table->tb6_lock); spin_lock_bh(&table->tb6_lock);
err = fib6_add(&table->tb6_root, rt, info, extack); err = fib6_add(&table->tb6_root, rt, info, extack);
spin_unlock_bh(&table->tb6_lock); spin_unlock_bh(&table->tb6_lock);
...@@ -1182,8 +1178,8 @@ static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort, ...@@ -1182,8 +1178,8 @@ static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
rt->rt6i_dst.plen = 128; rt->rt6i_dst.plen = 128;
if (!rt6_is_gw_or_nonexthop(ort)) { if (!rt6_is_gw_or_nonexthop(ort)) {
if (ort->rt6i_dst.plen != 128 && if (ort->fib6_dst.plen != 128 &&
ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
rt->rt6i_flags |= RTF_ANYCAST; rt->rt6i_flags |= RTF_ANYCAST;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
if (rt->rt6i_src.plen && saddr) { if (rt->rt6i_src.plen && saddr) {
...@@ -1375,7 +1371,18 @@ static unsigned int fib6_mtu(const struct fib6_info *rt) ...@@ -1375,7 +1371,18 @@ static unsigned int fib6_mtu(const struct fib6_info *rt)
{ {
unsigned int mtu; unsigned int mtu;
mtu = rt->fib6_pmtu ? : rt->rt6i_idev->cnf.mtu6; if (rt->fib6_pmtu) {
mtu = rt->fib6_pmtu;
} else {
struct net_device *dev = fib6_info_nh_dev(rt);
struct inet6_dev *idev;
rcu_read_lock();
idev = __in6_dev_get(dev);
mtu = idev->cnf.mtu6;
rcu_read_unlock();
}
mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu); return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
...@@ -1416,14 +1423,14 @@ static int rt6_insert_exception(struct rt6_info *nrt, ...@@ -1416,14 +1423,14 @@ static int rt6_insert_exception(struct rt6_info *nrt,
* Otherwise, the exception table is indexed by * Otherwise, the exception table is indexed by
* a hash of only rt6i_dst. * a hash of only rt6i_dst.
*/ */
if (ort->rt6i_src.plen) if (ort->fib6_src.plen)
src_key = &nrt->rt6i_src.addr; src_key = &nrt->rt6i_src.addr;
#endif #endif
/* Update rt6i_prefsrc as it could be changed /* Update rt6i_prefsrc as it could be changed
* in rt6_remove_prefsrc() * in rt6_remove_prefsrc()
*/ */
nrt->rt6i_prefsrc = ort->rt6i_prefsrc; nrt->rt6i_prefsrc = ort->fib6_prefsrc;
/* rt6_mtu_change() might lower mtu on ort. /* rt6_mtu_change() might lower mtu on ort.
* Only insert this exception route if its mtu * Only insert this exception route if its mtu
* is less than ort's mtu value. * is less than ort's mtu value.
...@@ -1457,9 +1464,9 @@ static int rt6_insert_exception(struct rt6_info *nrt, ...@@ -1457,9 +1464,9 @@ static int rt6_insert_exception(struct rt6_info *nrt,
/* Update fn->fn_sernum to invalidate all cached dst */ /* Update fn->fn_sernum to invalidate all cached dst */
if (!err) { if (!err) {
spin_lock_bh(&ort->rt6i_table->tb6_lock); spin_lock_bh(&ort->fib6_table->tb6_lock);
fib6_update_sernum(net, ort); fib6_update_sernum(net, ort);
spin_unlock_bh(&ort->rt6i_table->tb6_lock); spin_unlock_bh(&ort->fib6_table->tb6_lock);
fib6_force_start_gc(net); fib6_force_start_gc(net);
} }
...@@ -1514,7 +1521,7 @@ static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt, ...@@ -1514,7 +1521,7 @@ static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
* Otherwise, the exception table is indexed by * Otherwise, the exception table is indexed by
* a hash of only rt6i_dst. * a hash of only rt6i_dst.
*/ */
if (rt->rt6i_src.plen) if (rt->fib6_src.plen)
src_key = saddr; src_key = saddr;
#endif #endif
rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key); rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
...@@ -1551,7 +1558,7 @@ static int rt6_remove_exception_rt(struct rt6_info *rt) ...@@ -1551,7 +1558,7 @@ static int rt6_remove_exception_rt(struct rt6_info *rt)
* Otherwise, the exception table is indexed by * Otherwise, the exception table is indexed by
* a hash of only rt6i_dst. * a hash of only rt6i_dst.
*/ */
if (from->rt6i_src.plen) if (from->fib6_src.plen)
src_key = &rt->rt6i_src.addr; src_key = &rt->rt6i_src.addr;
#endif #endif
rt6_ex = __rt6_find_exception_spinlock(&bucket, rt6_ex = __rt6_find_exception_spinlock(&bucket,
...@@ -1592,7 +1599,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt) ...@@ -1592,7 +1599,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
* Otherwise, the exception table is indexed by * Otherwise, the exception table is indexed by
* a hash of only rt6i_dst. * a hash of only rt6i_dst.
*/ */
if (from->rt6i_src.plen) if (from->fib6_src.plen)
src_key = &rt->rt6i_src.addr; src_key = &rt->rt6i_src.addr;
#endif #endif
rt6_ex = __rt6_find_exception_rcu(&bucket, rt6_ex = __rt6_find_exception_rcu(&bucket,
...@@ -1810,7 +1817,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, ...@@ -1810,7 +1817,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
redo_rt6_select: redo_rt6_select:
f6i = rt6_select(net, fn, oif, strict); f6i = rt6_select(net, fn, oif, strict);
if (f6i->rt6i_nsiblings) if (f6i->fib6_nsiblings)
f6i = rt6_multipath_select(net, f6i, fl6, oif, skb, strict); f6i = rt6_multipath_select(net, f6i, fl6, oif, skb, strict);
if (f6i == net->ipv6.fib6_null_entry) { if (f6i == net->ipv6.fib6_null_entry) {
fn = fib6_backtrack(fn, &fl6->saddr); fn = fib6_backtrack(fn, &fl6->saddr);
...@@ -1842,7 +1849,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, ...@@ -1842,7 +1849,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
trace_fib6_table_lookup(net, rt, table, fl6); trace_fib6_table_lookup(net, rt, table, fl6);
return rt; return rt;
} else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) && } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
!(f6i->rt6i_flags & RTF_GATEWAY))) { !(f6i->fib6_flags & RTF_GATEWAY))) {
/* Create a RTF_CACHE clone which will not be /* Create a RTF_CACHE clone which will not be
* owned by the fib6 tree. It is for the special case where * owned by the fib6 tree. It is for the special case where
* the daddr in the skb during the neighbor look-up is different * the daddr in the skb during the neighbor look-up is different
...@@ -2206,7 +2213,7 @@ static void ip6_link_failure(struct sk_buff *skb) ...@@ -2206,7 +2213,7 @@ static void ip6_link_failure(struct sk_buff *skb)
struct fib6_node *fn; struct fib6_node *fn;
rcu_read_lock(); rcu_read_lock();
fn = rcu_dereference(rt->from->rt6i_node); fn = rcu_dereference(rt->from->fib6_node);
if (fn && (rt->rt6i_flags & RTF_DEFAULT)) if (fn && (rt->rt6i_flags & RTF_DEFAULT))
fn->fn_sernum = -1; fn->fn_sernum = -1;
rcu_read_unlock(); rcu_read_unlock();
...@@ -2372,9 +2379,9 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, ...@@ -2372,9 +2379,9 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
continue; continue;
if (fib6_check_expired(rt)) if (fib6_check_expired(rt))
continue; continue;
if (rt->rt6i_flags & RTF_REJECT) if (rt->fib6_flags & RTF_REJECT)
break; break;
if (!(rt->rt6i_flags & RTF_GATEWAY)) if (!(rt->fib6_flags & RTF_GATEWAY))
continue; continue;
if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex) if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
continue; continue;
...@@ -2400,7 +2407,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, ...@@ -2400,7 +2407,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
if (!rt) if (!rt)
rt = net->ipv6.fib6_null_entry; rt = net->ipv6.fib6_null_entry;
else if (rt->rt6i_flags & RTF_REJECT) { else if (rt->fib6_flags & RTF_REJECT) {
ret = net->ipv6.ip6_null_entry; ret = net->ipv6.ip6_null_entry;
goto out; goto out;
} }
...@@ -2907,7 +2914,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, ...@@ -2907,7 +2914,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
if (cfg->fc_protocol == RTPROT_UNSPEC) if (cfg->fc_protocol == RTPROT_UNSPEC)
cfg->fc_protocol = RTPROT_BOOT; cfg->fc_protocol = RTPROT_BOOT;
rt->rt6i_protocol = cfg->fc_protocol; rt->fib6_protocol = cfg->fc_protocol;
addr_type = ipv6_addr_type(&cfg->fc_dst); addr_type = ipv6_addr_type(&cfg->fc_dst);
...@@ -2922,17 +2929,17 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, ...@@ -2922,17 +2929,17 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate); rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
} }
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
rt->rt6i_dst.plen = cfg->fc_dst_len; rt->fib6_dst.plen = cfg->fc_dst_len;
if (rt->rt6i_dst.plen == 128) if (rt->fib6_dst.plen == 128)
rt->dst_host = true; rt->dst_host = true;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
rt->rt6i_src.plen = cfg->fc_src_len; rt->fib6_src.plen = cfg->fc_src_len;
#endif #endif
rt->rt6i_metric = cfg->fc_metric; rt->fib6_metric = cfg->fc_metric;
rt->fib6_nh.nh_weight = 1; rt->fib6_nh.nh_weight = 1;
rt->fib6_type = cfg->fc_type; rt->fib6_type = cfg->fc_type;
...@@ -2958,7 +2965,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, ...@@ -2958,7 +2965,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
goto out; goto out;
} }
} }
rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
goto install_route; goto install_route;
} }
...@@ -2992,24 +2999,26 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, ...@@ -2992,24 +2999,26 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
rt->rt6i_prefsrc.addr = cfg->fc_prefsrc; rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
rt->rt6i_prefsrc.plen = 128; rt->fib6_prefsrc.plen = 128;
} else } else
rt->rt6i_prefsrc.plen = 0; rt->fib6_prefsrc.plen = 0;
rt->rt6i_flags = cfg->fc_flags; rt->fib6_flags = cfg->fc_flags;
install_route: install_route:
if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
!netif_carrier_ok(dev)) !netif_carrier_ok(dev))
rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
rt->fib6_nh.nh_dev = dev; rt->fib6_nh.nh_dev = dev;
rt->rt6i_idev = idev; rt->fib6_table = table;
rt->rt6i_table = table;
cfg->fc_nlinfo.nl_net = dev_net(dev); cfg->fc_nlinfo.nl_net = dev_net(dev);
if (idev)
in6_dev_put(idev);
return rt; return rt;
out: out:
if (dev) if (dev)
...@@ -3048,7 +3057,7 @@ static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info) ...@@ -3048,7 +3057,7 @@ static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
goto out; goto out;
} }
table = rt->rt6i_table; table = rt->fib6_table;
spin_lock_bh(&table->tb6_lock); spin_lock_bh(&table->tb6_lock);
err = fib6_del(rt, info); err = fib6_del(rt, info);
spin_unlock_bh(&table->tb6_lock); spin_unlock_bh(&table->tb6_lock);
...@@ -3075,10 +3084,10 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) ...@@ -3075,10 +3084,10 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
if (rt == net->ipv6.fib6_null_entry) if (rt == net->ipv6.fib6_null_entry)
goto out_put; goto out_put;
table = rt->rt6i_table; table = rt->fib6_table;
spin_lock_bh(&table->tb6_lock); spin_lock_bh(&table->tb6_lock);
if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) { if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
struct fib6_info *sibling, *next_sibling; struct fib6_info *sibling, *next_sibling;
/* prefer to send a single notification with all hops */ /* prefer to send a single notification with all hops */
...@@ -3096,8 +3105,8 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) ...@@ -3096,8 +3105,8 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
} }
list_for_each_entry_safe(sibling, next_sibling, list_for_each_entry_safe(sibling, next_sibling,
&rt->rt6i_siblings, &rt->fib6_siblings,
rt6i_siblings) { fib6_siblings) {
err = fib6_del(sibling, info); err = fib6_del(sibling, info);
if (err) if (err)
goto out_unlock; goto out_unlock;
...@@ -3176,9 +3185,9 @@ static int ip6_route_del(struct fib6_config *cfg, ...@@ -3176,9 +3185,9 @@ static int ip6_route_del(struct fib6_config *cfg,
if (cfg->fc_flags & RTF_GATEWAY && if (cfg->fc_flags & RTF_GATEWAY &&
!ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw)) !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
continue; continue;
if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
continue; continue;
if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol) if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
continue; continue;
fib6_info_hold(rt); fib6_info_hold(rt);
rcu_read_unlock(); rcu_read_unlock();
...@@ -3336,7 +3345,7 @@ static struct fib6_info *rt6_get_route_info(struct net *net, ...@@ -3336,7 +3345,7 @@ static struct fib6_info *rt6_get_route_info(struct net *net,
for_each_fib6_node_rt_rcu(fn) { for_each_fib6_node_rt_rcu(fn) {
if (rt->fib6_nh.nh_dev->ifindex != ifindex) if (rt->fib6_nh.nh_dev->ifindex != ifindex)
continue; continue;
if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
continue; continue;
if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr)) if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
continue; continue;
...@@ -3396,7 +3405,7 @@ struct fib6_info *rt6_get_dflt_router(struct net *net, ...@@ -3396,7 +3405,7 @@ struct fib6_info *rt6_get_dflt_router(struct net *net,
rcu_read_lock(); rcu_read_lock();
for_each_fib6_node_rt_rcu(&table->tb6_root) { for_each_fib6_node_rt_rcu(&table->tb6_root) {
if (dev == rt->fib6_nh.nh_dev && if (dev == rt->fib6_nh.nh_dev &&
((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr)) ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
break; break;
} }
...@@ -3445,8 +3454,11 @@ static void __rt6_purge_dflt_routers(struct net *net, ...@@ -3445,8 +3454,11 @@ static void __rt6_purge_dflt_routers(struct net *net,
restart: restart:
rcu_read_lock(); rcu_read_lock();
for_each_fib6_node_rt_rcu(&table->tb6_root) { for_each_fib6_node_rt_rcu(&table->tb6_root) {
if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && struct net_device *dev = fib6_info_nh_dev(rt);
(!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
(!idev || idev->cnf.accept_ra != 2)) {
fib6_info_hold(rt); fib6_info_hold(rt);
rcu_read_unlock(); rcu_read_unlock();
ip6_del_rt(net, rt); ip6_del_rt(net, rt);
...@@ -3591,44 +3603,40 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff ...@@ -3591,44 +3603,40 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff
* Allocate a dst for local (unicast / anycast) address. * Allocate a dst for local (unicast / anycast) address.
*/ */
struct fib6_info *addrconf_dst_alloc(struct net *net, struct fib6_info *addrconf_f6i_alloc(struct net *net,
struct inet6_dev *idev, struct inet6_dev *idev,
const struct in6_addr *addr, const struct in6_addr *addr,
bool anycast, gfp_t gfp_flags) bool anycast, gfp_t gfp_flags)
{ {
u32 tb_id; u32 tb_id;
struct net_device *dev = idev->dev; struct net_device *dev = idev->dev;
struct fib6_info *rt; struct fib6_info *f6i;
rt = fib6_info_alloc(gfp_flags); f6i = fib6_info_alloc(gfp_flags);
if (!rt) if (!f6i)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
rt->dst_nocount = true; f6i->dst_nocount = true;
f6i->dst_host = true;
in6_dev_hold(idev); f6i->fib6_protocol = RTPROT_KERNEL;
rt->rt6i_idev = idev; f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
rt->dst_host = true;
rt->rt6i_protocol = RTPROT_KERNEL;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
if (anycast) { if (anycast) {
rt->fib6_type = RTN_ANYCAST; f6i->fib6_type = RTN_ANYCAST;
rt->rt6i_flags |= RTF_ANYCAST; f6i->fib6_flags |= RTF_ANYCAST;
} else { } else {
rt->fib6_type = RTN_LOCAL; f6i->fib6_type = RTN_LOCAL;
rt->rt6i_flags |= RTF_LOCAL; f6i->fib6_flags |= RTF_LOCAL;
} }
rt->fib6_nh.nh_gw = *addr; f6i->fib6_nh.nh_gw = *addr;
dev_hold(dev); dev_hold(dev);
rt->fib6_nh.nh_dev = dev; f6i->fib6_nh.nh_dev = dev;
rt->rt6i_dst.addr = *addr; f6i->fib6_dst.addr = *addr;
rt->rt6i_dst.plen = 128; f6i->fib6_dst.plen = 128;
tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL; tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
rt->rt6i_table = fib6_get_table(net, tb_id); f6i->fib6_table = fib6_get_table(net, tb_id);
return rt; return f6i;
} }
/* remove deleted ip from prefsrc entries */ /* remove deleted ip from prefsrc entries */
...@@ -3646,10 +3654,10 @@ static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg) ...@@ -3646,10 +3654,10 @@ static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
if (((void *)rt->fib6_nh.nh_dev == dev || !dev) && if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
rt != net->ipv6.fib6_null_entry && rt != net->ipv6.fib6_null_entry &&
ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
spin_lock_bh(&rt6_exception_lock); spin_lock_bh(&rt6_exception_lock);
/* remove prefsrc entry */ /* remove prefsrc entry */
rt->rt6i_prefsrc.plen = 0; rt->fib6_prefsrc.plen = 0;
/* need to update cache as well */ /* need to update cache as well */
rt6_exceptions_remove_prefsrc(rt); rt6_exceptions_remove_prefsrc(rt);
spin_unlock_bh(&rt6_exception_lock); spin_unlock_bh(&rt6_exception_lock);
...@@ -3675,7 +3683,7 @@ static int fib6_clean_tohost(struct fib6_info *rt, void *arg) ...@@ -3675,7 +3683,7 @@ static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
{ {
struct in6_addr *gateway = (struct in6_addr *)arg; struct in6_addr *gateway = (struct in6_addr *)arg;
if (((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) { ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
return -1; return -1;
} }
...@@ -3707,16 +3715,16 @@ static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt) ...@@ -3707,16 +3715,16 @@ static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
struct fib6_info *iter; struct fib6_info *iter;
struct fib6_node *fn; struct fib6_node *fn;
fn = rcu_dereference_protected(rt->rt6i_node, fn = rcu_dereference_protected(rt->fib6_node,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
iter = rcu_dereference_protected(fn->leaf, iter = rcu_dereference_protected(fn->leaf,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
while (iter) { while (iter) {
if (iter->rt6i_metric == rt->rt6i_metric && if (iter->fib6_metric == rt->fib6_metric &&
rt6_qualify_for_ecmp(iter)) rt6_qualify_for_ecmp(iter))
return iter; return iter;
iter = rcu_dereference_protected(iter->rt6_next, iter = rcu_dereference_protected(iter->rt6_next,
lockdep_is_held(&rt->rt6i_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
} }
return NULL; return NULL;
...@@ -3726,7 +3734,7 @@ static bool rt6_is_dead(const struct fib6_info *rt) ...@@ -3726,7 +3734,7 @@ static bool rt6_is_dead(const struct fib6_info *rt)
{ {
if (rt->fib6_nh.nh_flags & RTNH_F_DEAD || if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
(rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) fib6_ignore_linkdown(rt)))
return true; return true;
return false; return false;
...@@ -3740,7 +3748,7 @@ static int rt6_multipath_total_weight(const struct fib6_info *rt) ...@@ -3740,7 +3748,7 @@ static int rt6_multipath_total_weight(const struct fib6_info *rt)
if (!rt6_is_dead(rt)) if (!rt6_is_dead(rt))
total += rt->fib6_nh.nh_weight; total += rt->fib6_nh.nh_weight;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) { list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
if (!rt6_is_dead(iter)) if (!rt6_is_dead(iter))
total += iter->fib6_nh.nh_weight; total += iter->fib6_nh.nh_weight;
} }
...@@ -3767,7 +3775,7 @@ static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total) ...@@ -3767,7 +3775,7 @@ static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
rt6_upper_bound_set(rt, &weight, total); rt6_upper_bound_set(rt, &weight, total);
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
rt6_upper_bound_set(iter, &weight, total); rt6_upper_bound_set(iter, &weight, total);
} }
...@@ -3780,7 +3788,7 @@ void rt6_multipath_rebalance(struct fib6_info *rt) ...@@ -3780,7 +3788,7 @@ void rt6_multipath_rebalance(struct fib6_info *rt)
* then there is no need to rebalance upon the removal of every * then there is no need to rebalance upon the removal of every
* sibling route. * sibling route.
*/ */
if (!rt->rt6i_nsiblings || rt->should_flush) if (!rt->fib6_nsiblings || rt->should_flush)
return; return;
/* During lookup routes are evaluated in order, so we need to /* During lookup routes are evaluated in order, so we need to
...@@ -3831,7 +3839,7 @@ static bool rt6_multipath_uses_dev(const struct fib6_info *rt, ...@@ -3831,7 +3839,7 @@ static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
if (rt->fib6_nh.nh_dev == dev) if (rt->fib6_nh.nh_dev == dev)
return true; return true;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
if (iter->fib6_nh.nh_dev == dev) if (iter->fib6_nh.nh_dev == dev)
return true; return true;
...@@ -3843,7 +3851,7 @@ static void rt6_multipath_flush(struct fib6_info *rt) ...@@ -3843,7 +3851,7 @@ static void rt6_multipath_flush(struct fib6_info *rt)
struct fib6_info *iter; struct fib6_info *iter;
rt->should_flush = 1; rt->should_flush = 1;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
iter->should_flush = 1; iter->should_flush = 1;
} }
...@@ -3856,7 +3864,7 @@ static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt, ...@@ -3856,7 +3864,7 @@ static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
if (rt->fib6_nh.nh_dev == down_dev || if (rt->fib6_nh.nh_dev == down_dev ||
rt->fib6_nh.nh_flags & RTNH_F_DEAD) rt->fib6_nh.nh_flags & RTNH_F_DEAD)
dead++; dead++;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
if (iter->fib6_nh.nh_dev == down_dev || if (iter->fib6_nh.nh_dev == down_dev ||
iter->fib6_nh.nh_flags & RTNH_F_DEAD) iter->fib6_nh.nh_flags & RTNH_F_DEAD)
dead++; dead++;
...@@ -3872,7 +3880,7 @@ static void rt6_multipath_nh_flags_set(struct fib6_info *rt, ...@@ -3872,7 +3880,7 @@ static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
if (rt->fib6_nh.nh_dev == dev) if (rt->fib6_nh.nh_dev == dev)
rt->fib6_nh.nh_flags |= nh_flags; rt->fib6_nh.nh_flags |= nh_flags;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
if (iter->fib6_nh.nh_dev == dev) if (iter->fib6_nh.nh_dev == dev)
iter->fib6_nh.nh_flags |= nh_flags; iter->fib6_nh.nh_flags |= nh_flags;
} }
...@@ -3893,13 +3901,13 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg) ...@@ -3893,13 +3901,13 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
case NETDEV_DOWN: case NETDEV_DOWN:
if (rt->should_flush) if (rt->should_flush)
return -1; return -1;
if (!rt->rt6i_nsiblings) if (!rt->fib6_nsiblings)
return rt->fib6_nh.nh_dev == dev ? -1 : 0; return rt->fib6_nh.nh_dev == dev ? -1 : 0;
if (rt6_multipath_uses_dev(rt, dev)) { if (rt6_multipath_uses_dev(rt, dev)) {
unsigned int count; unsigned int count;
count = rt6_multipath_dead_count(rt, dev); count = rt6_multipath_dead_count(rt, dev);
if (rt->rt6i_nsiblings + 1 == count) { if (rt->fib6_nsiblings + 1 == count) {
rt6_multipath_flush(rt); rt6_multipath_flush(rt);
return -1; return -1;
} }
...@@ -3911,7 +3919,7 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg) ...@@ -3911,7 +3919,7 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
return -2; return -2;
case NETDEV_CHANGE: case NETDEV_CHANGE:
if (rt->fib6_nh.nh_dev != dev || if (rt->fib6_nh.nh_dev != dev ||
rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
break; break;
rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
rt6_multipath_rebalance(rt); rt6_multipath_rebalance(rt);
...@@ -4188,10 +4196,10 @@ static void ip6_route_mpath_notify(struct fib6_info *rt, ...@@ -4188,10 +4196,10 @@ static void ip6_route_mpath_notify(struct fib6_info *rt,
* nexthop. Since sibling routes are always added at the end of * nexthop. Since sibling routes are always added at the end of
* the list, find the first sibling of the last route appended * the list, find the first sibling of the last route appended
*/ */
if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) { if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
rt = list_first_entry(&rt_last->rt6i_siblings, rt = list_first_entry(&rt_last->fib6_siblings,
struct fib6_info, struct fib6_info,
rt6i_siblings); fib6_siblings);
} }
if (rt) if (rt)
...@@ -4410,13 +4418,13 @@ static size_t rt6_nlmsg_size(struct fib6_info *rt) ...@@ -4410,13 +4418,13 @@ static size_t rt6_nlmsg_size(struct fib6_info *rt)
{ {
int nexthop_len = 0; int nexthop_len = 0;
if (rt->rt6i_nsiblings) { if (rt->fib6_nsiblings) {
nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */ nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
+ NLA_ALIGN(sizeof(struct rtnexthop)) + NLA_ALIGN(sizeof(struct rtnexthop))
+ nla_total_size(16) /* RTA_GATEWAY */ + nla_total_size(16) /* RTA_GATEWAY */
+ lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate); + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
nexthop_len *= rt->rt6i_nsiblings; nexthop_len *= rt->fib6_nsiblings;
} }
return NLMSG_ALIGN(sizeof(struct rtmsg)) return NLMSG_ALIGN(sizeof(struct rtmsg))
...@@ -4444,11 +4452,14 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt, ...@@ -4444,11 +4452,14 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) { if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
*flags |= RTNH_F_LINKDOWN; *flags |= RTNH_F_LINKDOWN;
if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
rcu_read_lock();
if (fib6_ignore_linkdown(rt))
*flags |= RTNH_F_DEAD; *flags |= RTNH_F_DEAD;
rcu_read_unlock();
} }
if (rt->rt6i_flags & RTF_GATEWAY) { if (rt->fib6_flags & RTF_GATEWAY) {
if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0) if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -4518,11 +4529,11 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4518,11 +4529,11 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
rtm = nlmsg_data(nlh); rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET6; rtm->rtm_family = AF_INET6;
rtm->rtm_dst_len = rt->rt6i_dst.plen; rtm->rtm_dst_len = rt->fib6_dst.plen;
rtm->rtm_src_len = rt->rt6i_src.plen; rtm->rtm_src_len = rt->fib6_src.plen;
rtm->rtm_tos = 0; rtm->rtm_tos = 0;
if (rt->rt6i_table) if (rt->fib6_table)
table = rt->rt6i_table->tb6_id; table = rt->fib6_table->tb6_id;
else else
table = RT6_TABLE_UNSPEC; table = RT6_TABLE_UNSPEC;
rtm->rtm_table = table; rtm->rtm_table = table;
...@@ -4532,9 +4543,9 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4532,9 +4543,9 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
rtm->rtm_type = rt->fib6_type; rtm->rtm_type = rt->fib6_type;
rtm->rtm_flags = 0; rtm->rtm_flags = 0;
rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_protocol = rt->rt6i_protocol; rtm->rtm_protocol = rt->fib6_protocol;
if (rt->rt6i_flags & RTF_CACHE) if (rt->fib6_flags & RTF_CACHE)
rtm->rtm_flags |= RTM_F_CLONED; rtm->rtm_flags |= RTM_F_CLONED;
if (dest) { if (dest) {
...@@ -4542,7 +4553,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4542,7 +4553,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_dst_len = 128; rtm->rtm_dst_len = 128;
} else if (rtm->rtm_dst_len) } else if (rtm->rtm_dst_len)
if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr)) if (nla_put_in6_addr(skb, RTA_DST, &rt->fib6_dst.addr))
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
if (src) { if (src) {
...@@ -4550,12 +4561,12 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4550,12 +4561,12 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_src_len = 128; rtm->rtm_src_len = 128;
} else if (rtm->rtm_src_len && } else if (rtm->rtm_src_len &&
nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr)) nla_put_in6_addr(skb, RTA_SRC, &rt->fib6_src.addr))
goto nla_put_failure; goto nla_put_failure;
#endif #endif
if (iif) { if (iif) {
#ifdef CONFIG_IPV6_MROUTE #ifdef CONFIG_IPV6_MROUTE
if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { if (ipv6_addr_is_multicast(&rt->fib6_dst.addr)) {
int err = ip6mr_get_route(net, skb, rtm, portid); int err = ip6mr_get_route(net, skb, rtm, portid);
if (err == 0) if (err == 0)
...@@ -4573,9 +4584,9 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4573,9 +4584,9 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
} }
if (rt->rt6i_prefsrc.plen) { if (rt->fib6_prefsrc.plen) {
struct in6_addr saddr_buf; struct in6_addr saddr_buf;
saddr_buf = rt->rt6i_prefsrc.addr; saddr_buf = rt->fib6_prefsrc.addr;
if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf)) if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -4584,13 +4595,13 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4584,13 +4595,13 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
if (rtnetlink_put_metrics(skb, pmetrics) < 0) if (rtnetlink_put_metrics(skb, pmetrics) < 0)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric)) if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
goto nla_put_failure; goto nla_put_failure;
/* For multipath routes, walk the siblings list and add /* For multipath routes, walk the siblings list and add
* each as a nexthop within RTA_MULTIPATH. * each as a nexthop within RTA_MULTIPATH.
*/ */
if (rt->rt6i_nsiblings) { if (rt->fib6_nsiblings) {
struct fib6_info *sibling, *next_sibling; struct fib6_info *sibling, *next_sibling;
struct nlattr *mp; struct nlattr *mp;
...@@ -4602,7 +4613,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4602,7 +4613,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
list_for_each_entry_safe(sibling, next_sibling, list_for_each_entry_safe(sibling, next_sibling,
&rt->rt6i_siblings, rt6i_siblings) { &rt->fib6_siblings, fib6_siblings) {
if (rt6_add_nexthop(skb, sibling) < 0) if (rt6_add_nexthop(skb, sibling) < 0)
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -4613,7 +4624,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4613,7 +4624,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
} }
if (rt->rt6i_flags & RTF_EXPIRES) { if (rt->fib6_flags & RTF_EXPIRES) {
expires = dst ? dst->expires : rt->expires; expires = dst ? dst->expires : rt->expires;
expires -= jiffies; expires -= jiffies;
} }
...@@ -4621,7 +4632,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4621,7 +4632,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0) if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->fib6_flags)))
goto nla_put_failure; goto nla_put_failure;
...@@ -4646,7 +4657,7 @@ int rt6_dump_route(struct fib6_info *rt, void *p_arg) ...@@ -4646,7 +4657,7 @@ int rt6_dump_route(struct fib6_info *rt, void *p_arg)
/* user wants prefix routes only */ /* user wants prefix routes only */
if (rtm->rtm_flags & RTM_F_PREFIX && if (rtm->rtm_flags & RTM_F_PREFIX &&
!(rt->rt6i_flags & RTF_PREFIX_RT)) { !(rt->fib6_flags & RTF_PREFIX_RT)) {
/* success since this is not a prefix route */ /* success since this is not a prefix route */
return 1; return 1;
} }
...@@ -4820,7 +4831,6 @@ static int ip6_route_dev_notify(struct notifier_block *this, ...@@ -4820,7 +4831,6 @@ static int ip6_route_dev_notify(struct notifier_block *this,
if (event == NETDEV_REGISTER) { if (event == NETDEV_REGISTER) {
net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev; 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
...@@ -4834,7 +4844,6 @@ static int ip6_route_dev_notify(struct notifier_block *this, ...@@ -4834,7 +4844,6 @@ 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);
...@@ -5157,7 +5166,6 @@ void __init ip6_route_init_special_entries(void) ...@@ -5157,7 +5166,6 @@ void __init ip6_route_init_special_entries(void)
* 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->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