mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
ipv6: Move gateway checks to a fib6_nh setting
The gateway setting is not per fib6_info entry but per-fib6_nh. Add a new fib_nh_has_gw flag to fib6_nh and convert references to RTF_GATEWAY to the new flag. For IPv6 address the flag is cheaper than checking that nh_gw is non-0 like IPv4 does. While this increases fib6_nh by 8-bytes, the effective allocation size of a fib6_info is unchanged. The 8 bytes is recovered later with a fib_nh_common change. Signed-off-by: David Ahern <dsahern@gmail.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dac7d0f270
commit
2b2450ca4a
7 changed files with 41 additions and 30 deletions
|
@ -4913,7 +4913,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->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
|
return !(rt->fib6_flags & RTF_ADDRCONF) && rt->fib6_nh.fib_nh_has_gw;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fib6_info *
|
static struct fib6_info *
|
||||||
|
@ -5053,7 +5053,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->fib6_flags & RTF_GATEWAY ||
|
return rt->fib6_nh.fib_nh_has_gw ||
|
||||||
mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
|
mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,7 @@ struct rt6_exception {
|
||||||
|
|
||||||
struct fib6_nh {
|
struct fib6_nh {
|
||||||
struct in6_addr nh_gw;
|
struct in6_addr nh_gw;
|
||||||
|
bool fib_nh_has_gw;
|
||||||
struct net_device *nh_dev;
|
struct net_device *nh_dev;
|
||||||
struct lwtunnel_state *nh_lwtstate;
|
struct lwtunnel_state *nh_lwtstate;
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,8 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr)
|
||||||
|
|
||||||
static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i)
|
static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i)
|
||||||
{
|
{
|
||||||
return (f6i->fib6_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) ==
|
return !(f6i->fib6_flags & (RTF_ADDRCONF|RTF_DYNAMIC)) &&
|
||||||
RTF_GATEWAY;
|
f6i->fib6_nh.fib_nh_has_gw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ip6_route_input(struct sk_buff *skb);
|
void ip6_route_input(struct sk_buff *skb);
|
||||||
|
|
|
@ -4751,7 +4751,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
||||||
if (f6i->fib6_nh.nh_lwtstate)
|
if (f6i->fib6_nh.nh_lwtstate)
|
||||||
return BPF_FIB_LKUP_RET_UNSUPP_LWT;
|
return BPF_FIB_LKUP_RET_UNSUPP_LWT;
|
||||||
|
|
||||||
if (f6i->fib6_flags & RTF_GATEWAY)
|
if (f6i->fib6_nh.fib_nh_has_gw)
|
||||||
*dst = f6i->fib6_nh.nh_gw;
|
*dst = f6i->fib6_nh.nh_gw;
|
||||||
|
|
||||||
dev = f6i->fib6_nh.nh_dev;
|
dev = f6i->fib6_nh.nh_dev;
|
||||||
|
|
|
@ -173,7 +173,8 @@ static int addrconf_ifdown(struct net_device *dev, int how);
|
||||||
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
|
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
|
||||||
int plen,
|
int plen,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
u32 flags, u32 noflags);
|
u32 flags, u32 noflags,
|
||||||
|
bool no_gw);
|
||||||
|
|
||||||
static void addrconf_dad_start(struct inet6_ifaddr *ifp);
|
static void addrconf_dad_start(struct inet6_ifaddr *ifp);
|
||||||
static void addrconf_dad_work(struct work_struct *w);
|
static void addrconf_dad_work(struct work_struct *w);
|
||||||
|
@ -1230,10 +1231,8 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_r
|
||||||
{
|
{
|
||||||
struct fib6_info *f6i;
|
struct fib6_info *f6i;
|
||||||
|
|
||||||
f6i = addrconf_get_prefix_route(&ifp->addr,
|
f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
|
||||||
ifp->prefix_len,
|
ifp->idev->dev, 0, RTF_DEFAULT, true);
|
||||||
ifp->idev->dev,
|
|
||||||
0, RTF_GATEWAY | RTF_DEFAULT);
|
|
||||||
if (f6i) {
|
if (f6i) {
|
||||||
if (del_rt)
|
if (del_rt)
|
||||||
ip6_del_rt(dev_net(ifp->idev->dev), f6i);
|
ip6_del_rt(dev_net(ifp->idev->dev), f6i);
|
||||||
|
@ -2402,7 +2401,8 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, u32 metric,
|
||||||
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
|
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
|
||||||
int plen,
|
int plen,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
u32 flags, u32 noflags)
|
u32 flags, u32 noflags,
|
||||||
|
bool no_gw)
|
||||||
{
|
{
|
||||||
struct fib6_node *fn;
|
struct fib6_node *fn;
|
||||||
struct fib6_info *rt = NULL;
|
struct fib6_info *rt = NULL;
|
||||||
|
@ -2421,6 +2421,8 @@ 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 (no_gw && rt->fib6_nh.fib_nh_has_gw)
|
||||||
|
continue;
|
||||||
if ((rt->fib6_flags & flags) != flags)
|
if ((rt->fib6_flags & flags) != flags)
|
||||||
continue;
|
continue;
|
||||||
if ((rt->fib6_flags & noflags) != 0)
|
if ((rt->fib6_flags & noflags) != 0)
|
||||||
|
@ -2717,7 +2719,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
|
||||||
pinfo->prefix_len,
|
pinfo->prefix_len,
|
||||||
dev,
|
dev,
|
||||||
RTF_ADDRCONF | RTF_PREFIX_RT,
|
RTF_ADDRCONF | RTF_PREFIX_RT,
|
||||||
RTF_GATEWAY | RTF_DEFAULT);
|
RTF_DEFAULT, true);
|
||||||
|
|
||||||
if (rt) {
|
if (rt) {
|
||||||
/* Autoconf prefix route */
|
/* Autoconf prefix route */
|
||||||
|
@ -4588,10 +4590,8 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp,
|
||||||
struct fib6_info *f6i;
|
struct fib6_info *f6i;
|
||||||
u32 prio;
|
u32 prio;
|
||||||
|
|
||||||
f6i = addrconf_get_prefix_route(&ifp->addr,
|
f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
|
||||||
ifp->prefix_len,
|
ifp->idev->dev, 0, RTF_DEFAULT, true);
|
||||||
ifp->idev->dev,
|
|
||||||
0, RTF_GATEWAY | RTF_DEFAULT);
|
|
||||||
if (!f6i)
|
if (!f6i)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
@ -5972,7 +5972,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
||||||
struct fib6_info *rt;
|
struct fib6_info *rt;
|
||||||
|
|
||||||
rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
|
rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
|
||||||
ifp->idev->dev, 0, 0);
|
ifp->idev->dev, 0, 0,
|
||||||
|
false);
|
||||||
if (rt)
|
if (rt)
|
||||||
ip6_del_rt(net, rt);
|
ip6_del_rt(net, rt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2294,6 +2294,7 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
|
||||||
{
|
{
|
||||||
struct fib6_info *rt = v;
|
struct fib6_info *rt = v;
|
||||||
struct ipv6_route_iter *iter = seq->private;
|
struct ipv6_route_iter *iter = seq->private;
|
||||||
|
unsigned int flags = rt->fib6_flags;
|
||||||
const struct net_device *dev;
|
const struct net_device *dev;
|
||||||
|
|
||||||
seq_printf(seq, "%pi6 %02x ", &rt->fib6_dst.addr, rt->fib6_dst.plen);
|
seq_printf(seq, "%pi6 %02x ", &rt->fib6_dst.addr, rt->fib6_dst.plen);
|
||||||
|
@ -2303,15 +2304,17 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
|
||||||
#else
|
#else
|
||||||
seq_puts(seq, "00000000000000000000000000000000 00 ");
|
seq_puts(seq, "00000000000000000000000000000000 00 ");
|
||||||
#endif
|
#endif
|
||||||
if (rt->fib6_flags & RTF_GATEWAY)
|
if (rt->fib6_nh.fib_nh_has_gw) {
|
||||||
|
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->fib6_metric, atomic_read(&rt->fib6_ref), 0,
|
rt->fib6_metric, atomic_read(&rt->fib6_ref), 0,
|
||||||
rt->fib6_flags, dev ? dev->name : "");
|
flags, dev ? dev->name : "");
|
||||||
iter->w.leaf = NULL;
|
iter->w.leaf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,7 +533,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->fib6_flags & RTF_GATEWAY))
|
if (!rt || !rt->fib6_nh.fib_nh_has_gw)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nh_gw = &rt->fib6_nh.nh_gw;
|
nh_gw = &rt->fib6_nh.nh_gw;
|
||||||
|
@ -595,7 +595,7 @@ static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
|
||||||
struct neighbour *neigh;
|
struct neighbour *neigh;
|
||||||
|
|
||||||
if (rt->fib6_flags & RTF_NONEXTHOP ||
|
if (rt->fib6_flags & RTF_NONEXTHOP ||
|
||||||
!(rt->fib6_flags & RTF_GATEWAY))
|
!rt->fib6_nh.fib_nh_has_gw)
|
||||||
return RT6_NUD_SUCCEED;
|
return RT6_NUD_SUCCEED;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock_bh();
|
||||||
|
@ -784,7 +784,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->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
|
return (rt->fib6_flags & RTF_NONEXTHOP) || rt->fib6_nh.fib_nh_has_gw;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_ROUTE_INFO
|
#ifdef CONFIG_IPV6_ROUTE_INFO
|
||||||
|
@ -989,8 +989,11 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
|
||||||
|
|
||||||
rt->rt6i_dst = ort->fib6_dst;
|
rt->rt6i_dst = ort->fib6_dst;
|
||||||
rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
|
rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
|
||||||
rt->rt6i_gateway = ort->fib6_nh.nh_gw;
|
|
||||||
rt->rt6i_flags = ort->fib6_flags;
|
rt->rt6i_flags = ort->fib6_flags;
|
||||||
|
if (ort->fib6_nh.fib_nh_has_gw) {
|
||||||
|
rt->rt6i_gateway = ort->fib6_nh.nh_gw;
|
||||||
|
rt->rt6i_flags |= RTF_GATEWAY;
|
||||||
|
}
|
||||||
rt6_set_from(rt, ort);
|
rt6_set_from(rt, ort);
|
||||||
#ifdef CONFIG_IPV6_SUBTREES
|
#ifdef CONFIG_IPV6_SUBTREES
|
||||||
rt->rt6i_src = ort->fib6_src;
|
rt->rt6i_src = ort->fib6_src;
|
||||||
|
@ -1872,7 +1875,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
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->fib6_flags & RTF_GATEWAY))) {
|
!f6i->fib6_nh.fib_nh_has_gw)) {
|
||||||
/* 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
|
||||||
|
@ -2442,7 +2445,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
|
||||||
continue;
|
continue;
|
||||||
if (rt->fib6_flags & RTF_REJECT)
|
if (rt->fib6_flags & RTF_REJECT)
|
||||||
break;
|
break;
|
||||||
if (!(rt->fib6_flags & RTF_GATEWAY))
|
if (!rt->fib6_nh.fib_nh_has_gw)
|
||||||
continue;
|
continue;
|
||||||
if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
|
if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
|
||||||
continue;
|
continue;
|
||||||
|
@ -2986,6 +2989,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
fib6_nh->nh_gw = cfg->fc_gateway;
|
fib6_nh->nh_gw = cfg->fc_gateway;
|
||||||
|
fib6_nh->fib_nh_has_gw = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
|
@ -3121,7 +3125,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
||||||
rt->fib6_table = table;
|
rt->fib6_table = table;
|
||||||
rt->fib6_metric = cfg->fc_metric;
|
rt->fib6_metric = cfg->fc_metric;
|
||||||
rt->fib6_type = cfg->fc_type;
|
rt->fib6_type = cfg->fc_type;
|
||||||
rt->fib6_flags = cfg->fc_flags;
|
rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY;
|
||||||
|
|
||||||
ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
|
ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
|
||||||
rt->fib6_dst.plen = cfg->fc_dst_len;
|
rt->fib6_dst.plen = cfg->fc_dst_len;
|
||||||
|
@ -3490,7 +3494,8 @@ 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->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
|
if (!(rt->fib6_flags & RTF_ROUTEINFO) ||
|
||||||
|
!rt->fib6_nh.fib_nh_has_gw)
|
||||||
continue;
|
continue;
|
||||||
if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
|
if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
|
||||||
continue;
|
continue;
|
||||||
|
@ -3811,7 +3816,7 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
|
||||||
fib6_clean_all(net, fib6_remove_prefsrc, &adni);
|
fib6_clean_all(net, fib6_remove_prefsrc, &adni);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
|
#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT)
|
||||||
|
|
||||||
/* Remove routers and update dst entries when gateway turn into host. */
|
/* Remove routers and update dst entries when gateway turn into host. */
|
||||||
static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
|
static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
|
||||||
|
@ -3819,6 +3824,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->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
|
if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
|
||||||
|
rt->fib6_nh.fib_nh_has_gw &&
|
||||||
ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
|
ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -4607,7 +4613,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rt->fib6_flags & RTF_GATEWAY) {
|
if (rt->fib6_nh.fib_nh_has_gw) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue