forked from Minki/linux
IPv6: Add "offload failed" indication to routes
After installing a route to the kernel, user space receives an acknowledgment, which means the route was installed in the kernel, but not necessarily in hardware. The asynchronous nature of route installation in hardware can lead to a routing daemon advertising a route before it was actually installed in hardware. This can result in packet loss or mis-routed packets until the route is installed in hardware. To avoid such cases, previous patch set added the ability to emit RTM_NEWROUTE notifications whenever RTM_F_OFFLOAD/RTM_F_TRAP flags are changed, this behavior is controlled by sysctl. With the above mentioned behavior, it is possible to know from user-space if the route was offloaded, but if the offload fails there is no indication to user-space. Following a failure, a routing daemon will wait indefinitely for a notification that will never come. This patch adds an "offload_failed" indication to IPv6 routes, so that users will have better visibility into the offload process. 'struct fib6_info' is extended with new field that indicates if route offload failed. Note that the new field is added using unused bit and therefore there is no need to increase struct size. Signed-off-by: Amit Cohen <amcohen@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
648106c30a
commit
0c5fcf9e24
@ -5008,7 +5008,7 @@ mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
|
|||||||
common);
|
common);
|
||||||
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
|
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
|
||||||
fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
|
fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
|
||||||
should_offload, !should_offload);
|
should_offload, !should_offload, false);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void
|
static void
|
||||||
@ -5030,7 +5030,7 @@ mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
|
|||||||
common);
|
common);
|
||||||
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
|
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
|
||||||
fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
|
fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
|
||||||
false, false);
|
false, false, false);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void
|
static void
|
||||||
|
@ -595,7 +595,7 @@ static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data,
|
|||||||
struct nsim_fib6_rt_nh *fib6_rt_nh;
|
struct nsim_fib6_rt_nh *fib6_rt_nh;
|
||||||
|
|
||||||
list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list)
|
list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list)
|
||||||
fib6_info_hw_flags_set(net, fib6_rt_nh->rt, false, trap);
|
fib6_info_hw_flags_set(net, fib6_rt_nh->rt, false, trap, false);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data,
|
static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data,
|
||||||
|
@ -195,7 +195,8 @@ struct fib6_info {
|
|||||||
fib6_destroying:1,
|
fib6_destroying:1,
|
||||||
offload:1,
|
offload:1,
|
||||||
trap:1,
|
trap:1,
|
||||||
unused:2;
|
offload_failed:1,
|
||||||
|
unused:1;
|
||||||
|
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
struct nexthop *nh;
|
struct nexthop *nh;
|
||||||
@ -539,7 +540,7 @@ static inline bool fib6_metric_locked(struct fib6_info *f6i, int metric)
|
|||||||
return !!(f6i->fib6_metrics->metrics[RTAX_LOCK - 1] & (1 << metric));
|
return !!(f6i->fib6_metrics->metrics[RTAX_LOCK - 1] & (1 << metric));
|
||||||
}
|
}
|
||||||
void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
|
void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
|
||||||
bool offload, bool trap);
|
bool offload, bool trap, bool offload_failed);
|
||||||
|
|
||||||
#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL)
|
#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL)
|
||||||
struct bpf_iter__ipv6_route {
|
struct bpf_iter__ipv6_route {
|
||||||
|
@ -5619,6 +5619,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
|
|||||||
rtm->rtm_flags |= RTM_F_OFFLOAD;
|
rtm->rtm_flags |= RTM_F_OFFLOAD;
|
||||||
if (rt->trap)
|
if (rt->trap)
|
||||||
rtm->rtm_flags |= RTM_F_TRAP;
|
rtm->rtm_flags |= RTM_F_TRAP;
|
||||||
|
if (rt->offload_failed)
|
||||||
|
rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -6070,16 +6072,18 @@ errout:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
|
void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
|
||||||
bool offload, bool trap)
|
bool offload, bool trap, bool offload_failed)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (f6i->offload == offload && f6i->trap == trap)
|
if (f6i->offload == offload && f6i->trap == trap &&
|
||||||
|
f6i->offload_failed == offload_failed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f6i->offload = offload;
|
f6i->offload = offload;
|
||||||
f6i->trap = trap;
|
f6i->trap = trap;
|
||||||
|
f6i->offload_failed = offload_failed;
|
||||||
|
|
||||||
if (!rcu_access_pointer(f6i->fib6_node))
|
if (!rcu_access_pointer(f6i->fib6_node))
|
||||||
/* The route was removed from the tree, do not send
|
/* The route was removed from the tree, do not send
|
||||||
|
Loading…
Reference in New Issue
Block a user