Skip to content

Commit

Permalink
IPv4: Add "offload failed" indication to routes
Browse files Browse the repository at this point in the history
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 IPv4 routes, so that
users will have better visibility into the offload process.

'struct fib_alias', and 'struct fib_rt_info' are 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 structs 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>
  • Loading branch information
Amit Cohen authored and David S. Miller committed Feb 9, 2021
1 parent 49fc251 commit 36c5100
Show file tree
Hide file tree
Showing 7 changed files with 17 additions and 3 deletions.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
Original file line number Diff line number Diff line change
Expand Up @@ -4963,6 +4963,7 @@ mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
fri.type = fib4_entry->type;
fri.offload = should_offload;
fri.trap = !should_offload;
fri.offload_failed = false;
fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
}

Expand All @@ -4985,6 +4986,7 @@ mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
fri.type = fib4_entry->type;
fri.offload = false;
fri.trap = false;
fri.offload_failed = false;
fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/net/netdevsim/fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ static void nsim_fib4_rt_hw_flags_set(struct net *net,
fri.type = fib4_rt->type;
fri.offload = false;
fri.trap = trap;
fri.offload_failed = false;
fib_alias_hw_flags_set(net, &fri);
}

Expand Down
3 changes: 2 additions & 1 deletion include/net/ip_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ struct fib_rt_info {
u8 type;
u8 offload:1,
trap:1,
unused:6;
offload_failed:1,
unused:5;
};

struct fib_entry_notifier_info {
Expand Down
3 changes: 2 additions & 1 deletion net/ipv4/fib_lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct fib_alias {
s16 fa_default;
u8 offload:1,
trap:1,
unused:6;
offload_failed:1,
unused:5;
struct rcu_head rcu;
};

Expand Down
3 changes: 3 additions & 0 deletions net/ipv4/fib_semantics.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
fri.type = fa->fa_type;
fri.offload = fa->offload;
fri.trap = fa->trap;
fri.offload_failed = fa->offload_failed;
err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags);
if (err < 0) {
/* -EMSGSIZE implies BUG in fib_nlmsg_size() */
Expand Down Expand Up @@ -1811,6 +1812,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
rtm->rtm_flags |= RTM_F_OFFLOAD;
if (fri->trap)
rtm->rtm_flags |= RTM_F_TRAP;
if (fri->offload_failed)
rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED;

nlmsg_end(skb, nlh);
return 0;
Expand Down
7 changes: 6 additions & 1 deletion net/ipv4/fib_trie.c
Original file line number Diff line number Diff line change
Expand Up @@ -1047,11 +1047,13 @@ void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri)
if (!fa_match)
goto out;

if (fa_match->offload == fri->offload && fa_match->trap == fri->trap)
if (fa_match->offload == fri->offload && fa_match->trap == fri->trap &&
fa_match->offload_failed == fri->offload_failed)
goto out;

fa_match->offload = fri->offload;
fa_match->trap = fri->trap;
fa_match->offload_failed = fri->offload_failed;

if (!net->ipv4.sysctl_fib_notify_on_flag_change)
goto out;
Expand Down Expand Up @@ -1290,6 +1292,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
new_fa->fa_default = -1;
new_fa->offload = 0;
new_fa->trap = 0;
new_fa->offload_failed = 0;

hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list);

Expand Down Expand Up @@ -1350,6 +1353,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
new_fa->fa_default = -1;
new_fa->offload = 0;
new_fa->trap = 0;
new_fa->offload_failed = 0;

/* Insert new entry to the list. */
err = fib_insert_alias(t, tp, l, new_fa, fa, key);
Expand Down Expand Up @@ -2289,6 +2293,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
fri.type = fa->fa_type;
fri.offload = fa->offload;
fri.trap = fa->trap;
fri.offload_failed = fa->offload_failed;
err = fib_dump_info(skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -3304,6 +3304,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
fri.type = rt->rt_type;
fri.offload = 0;
fri.trap = 0;
fri.offload_failed = 0;
if (res.fa_head) {
struct fib_alias *fa;

Expand Down

0 comments on commit 36c5100

Please sign in to comment.