static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
{
/* 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 bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
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);
}
struct fib6_nh {
struct in6_addr nh_gw;
+ bool fib_nh_has_gw;
struct net_device *nh_dev;
struct lwtunnel_state *nh_lwtstate;
static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i)
{
- return (f6i->fib6_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) ==
- RTF_GATEWAY;
+ return !(f6i->fib6_flags & (RTF_ADDRCONF|RTF_DYNAMIC)) &&
+ f6i->fib6_nh.fib_nh_has_gw;
}
void ip6_route_input(struct sk_buff *skb);
if (f6i->fib6_nh.nh_lwtstate)
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;
dev = f6i->fib6_nh.nh_dev;
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
int plen,
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_work(struct work_struct *w);
{
struct fib6_info *f6i;
- f6i = addrconf_get_prefix_route(&ifp->addr,
- ifp->prefix_len,
- ifp->idev->dev,
- 0, RTF_GATEWAY | RTF_DEFAULT);
+ f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
+ ifp->idev->dev, 0, RTF_DEFAULT, true);
if (f6i) {
if (del_rt)
ip6_del_rt(dev_net(ifp->idev->dev), f6i);
static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
int plen,
const struct net_device *dev,
- u32 flags, u32 noflags)
+ u32 flags, u32 noflags,
+ bool no_gw)
{
struct fib6_node *fn;
struct fib6_info *rt = NULL;
for_each_fib6_node_rt_rcu(fn) {
if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex)
continue;
+ if (no_gw && rt->fib6_nh.fib_nh_has_gw)
+ continue;
if ((rt->fib6_flags & flags) != flags)
continue;
if ((rt->fib6_flags & noflags) != 0)
pinfo->prefix_len,
dev,
RTF_ADDRCONF | RTF_PREFIX_RT,
- RTF_GATEWAY | RTF_DEFAULT);
+ RTF_DEFAULT, true);
if (rt) {
/* Autoconf prefix route */
struct fib6_info *f6i;
u32 prio;
- f6i = addrconf_get_prefix_route(&ifp->addr,
- ifp->prefix_len,
- ifp->idev->dev,
- 0, RTF_GATEWAY | RTF_DEFAULT);
+ f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
+ ifp->idev->dev, 0, RTF_DEFAULT, true);
if (!f6i)
return -ENOENT;
struct fib6_info *rt;
rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
- ifp->idev->dev, 0, 0);
+ ifp->idev->dev, 0, 0,
+ false);
if (rt)
ip6_del_rt(net, rt);
}
{
struct fib6_info *rt = v;
struct ipv6_route_iter *iter = seq->private;
+ unsigned int flags = rt->fib6_flags;
const struct net_device *dev;
seq_printf(seq, "%pi6 %02x ", &rt->fib6_dst.addr, rt->fib6_dst.plen);
#else
seq_puts(seq, "00000000000000000000000000000000 00 ");
#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);
- else
+ } else {
seq_puts(seq, "00000000000000000000000000000000");
+ }
dev = rt->fib6_nh.nh_dev;
seq_printf(seq, " %08x %08x %08x %08x %8s\n",
rt->fib6_metric, atomic_read(&rt->fib6_ref), 0,
- rt->fib6_flags, dev ? dev->name : "");
+ flags, dev ? dev->name : "");
iter->w.leaf = NULL;
return 0;
}
* Router Reachability Probe MUST be rate-limited
* to no more than one per minute.
*/
- if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
+ if (!rt || !rt->fib6_nh.fib_nh_has_gw)
return;
nh_gw = &rt->fib6_nh.nh_gw;
struct neighbour *neigh;
if (rt->fib6_flags & RTF_NONEXTHOP ||
- !(rt->fib6_flags & RTF_GATEWAY))
+ !rt->fib6_nh.fib_nh_has_gw)
return RT6_NUD_SUCCEED;
rcu_read_lock_bh();
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
rt->rt6i_dst = ort->fib6_dst;
rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
- rt->rt6i_gateway = ort->fib6_nh.nh_gw;
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);
#ifdef CONFIG_IPV6_SUBTREES
rt->rt6i_src = ort->fib6_src;
rcu_read_unlock();
return rt;
} 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
* owned by the fib6 tree. It is for the special case where
* the daddr in the skb during the neighbor look-up is different
continue;
if (rt->fib6_flags & RTF_REJECT)
break;
- if (!(rt->fib6_flags & RTF_GATEWAY))
+ if (!rt->fib6_nh.fib_nh_has_gw)
continue;
if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
continue;
goto out;
fib6_nh->nh_gw = cfg->fc_gateway;
+ fib6_nh->fib_nh_has_gw = 1;
}
err = -ENODEV;
rt->fib6_table = table;
rt->fib6_metric = cfg->fc_metric;
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);
rt->fib6_dst.plen = cfg->fc_dst_len;
for_each_fib6_node_rt_rcu(fn) {
if (rt->fib6_nh.nh_dev->ifindex != ifindex)
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;
if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
continue;
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. */
static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
struct in6_addr *gateway = (struct in6_addr *)arg;
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)) {
return -1;
}
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)
goto nla_put_failure;
}