Commit f6310b61 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-Add-route-offload-indication'

Ido Schimmel says:

====================
net: Add route offload indication

This patch set adds offload indication to IPv4 and IPv6 routes. So far
offload indication was only available for the nexthop via
'RTNH_F_OFFLOAD', which is problematic as a nexthop is usually shared
between multiple routes.

Based on feedback from Roopa and David on the RFC [1], the indication is
split to 'offload' and 'trap'. This is done because not all the routes
present in hardware actually offload traffic from the kernel. For
example, host routes merely trap packets to the kernel. The two flags
are dumped to user space via the 'rtm_flags' field in the ancillary
header of the rtnetlink message.

In addition, the patch set uses the new flags in order to test the FIB
offload API by adding a dummy FIB offload implementation to netdevsim.
The new tests are added to a shared library and can be therefore shared
between different drivers.

Patches #1-#3 add offload indication to IPv4 routes.
Patches #4 adds offload indication to IPv6 routes.
Patches #5-#6 add support for the offload indication in mlxsw.
Patch #7 adds dummy FIB offload implementation in netdevsim.
Patches #8-#10 add selftests.

v2 (feedback from David Ahern):
* Patch #2: Name last argument of fib_dump_info()
* Patch #2: Move 'struct fib_rt_info' to include/net/ip_fib.h so that it
  could later be passed to fib_alias_hw_flags_set()
* Patch #3: Make use of 'struct fib_rt_info' in fib_alias_hw_flags_set()
* Patch #6: Convert to new fib_alias_hw_flags_set() interface
* Patch #7: Convert to new fib_alias_hw_flags_set() interface

[1] https://patchwork.ozlabs.org/cover/1170530/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0fadc0a2 212a37c2
...@@ -549,6 +549,7 @@ source "drivers/net/hyperv/Kconfig" ...@@ -549,6 +549,7 @@ source "drivers/net/hyperv/Kconfig"
config NETDEVSIM config NETDEVSIM
tristate "Simulated networking device" tristate "Simulated networking device"
depends on DEBUG_FS depends on DEBUG_FS
depends on IPV6 || IPV6=n
select NET_DEVLINK select NET_DEVLINK
help help
This driver is a developer testing tool and software model that can This driver is a developer testing tool and software model that can
......
This diff is collapsed.
...@@ -192,7 +192,9 @@ struct fib6_info { ...@@ -192,7 +192,9 @@ struct fib6_info {
dst_nopolicy:1, dst_nopolicy:1,
dst_host:1, dst_host:1,
fib6_destroying:1, fib6_destroying:1,
unused:3; offload:1,
trap:1,
unused:1;
struct rcu_head rcu; struct rcu_head rcu;
struct nexthop *nh; struct nexthop *nh;
...@@ -329,6 +331,13 @@ static inline void fib6_info_release(struct fib6_info *f6i) ...@@ -329,6 +331,13 @@ static inline void fib6_info_release(struct fib6_info *f6i)
call_rcu(&f6i->rcu, fib6_info_destroy_rcu); call_rcu(&f6i->rcu, fib6_info_destroy_rcu);
} }
static inline void fib6_info_hw_flags_set(struct fib6_info *f6i, bool offload,
bool trap)
{
f6i->offload = offload;
f6i->trap = trap;
}
enum fib6_walk_state { enum fib6_walk_state {
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
FWS_S, FWS_S,
......
...@@ -204,6 +204,18 @@ __be32 fib_result_prefsrc(struct net *net, struct fib_result *res); ...@@ -204,6 +204,18 @@ __be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
#define FIB_RES_DEV(res) (FIB_RES_NHC(res)->nhc_dev) #define FIB_RES_DEV(res) (FIB_RES_NHC(res)->nhc_dev)
#define FIB_RES_OIF(res) (FIB_RES_NHC(res)->nhc_oif) #define FIB_RES_OIF(res) (FIB_RES_NHC(res)->nhc_oif)
struct fib_rt_info {
struct fib_info *fi;
u32 tb_id;
__be32 dst;
int dst_len;
u8 tos;
u8 type;
u8 offload:1,
trap:1,
unused:6;
};
struct fib_entry_notifier_info { struct fib_entry_notifier_info {
struct fib_notifier_info info; /* must be first */ struct fib_notifier_info info; /* must be first */
u32 dst; u32 dst;
...@@ -464,6 +476,7 @@ int fib_nh_common_init(struct fib_nh_common *nhc, struct nlattr *fc_encap, ...@@ -464,6 +476,7 @@ int fib_nh_common_init(struct fib_nh_common *nhc, struct nlattr *fc_encap,
void fib_nh_common_release(struct fib_nh_common *nhc); void fib_nh_common_release(struct fib_nh_common *nhc);
/* Exported by fib_trie.c */ /* Exported by fib_trie.c */
void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri);
void fib_trie_init(void); void fib_trie_init(void);
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias); struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
......
...@@ -309,6 +309,8 @@ enum rt_scope_t { ...@@ -309,6 +309,8 @@ enum rt_scope_t {
#define RTM_F_PREFIX 0x800 /* Prefix addresses */ #define RTM_F_PREFIX 0x800 /* Prefix addresses */
#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */ #define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */
#define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */ #define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */
#define RTM_F_OFFLOAD 0x4000 /* route is offloaded */
#define RTM_F_TRAP 0x8000 /* route is trapping packets */
/* Reserved table identifiers */ /* Reserved table identifiers */
......
...@@ -16,6 +16,9 @@ struct fib_alias { ...@@ -16,6 +16,9 @@ struct fib_alias {
u8 fa_slen; u8 fa_slen;
u32 tb_id; u32 tb_id;
s16 fa_default; s16 fa_default;
u8 offload:1,
trap:1,
unused:6;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -35,9 +38,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg, ...@@ -35,9 +38,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
int fib_nh_match(struct fib_config *cfg, struct fib_info *fi, int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi); bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi);
int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
u8 type, __be32 dst, int dst_len, u8 tos, struct fib_info *fi, struct fib_rt_info *fri, unsigned int flags);
unsigned int);
void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len,
u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); u32 tb_id, const struct nl_info *info, unsigned int nlm_flags);
......
...@@ -504,6 +504,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, ...@@ -504,6 +504,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
int dst_len, u32 tb_id, const struct nl_info *info, int dst_len, u32 tb_id, const struct nl_info *info,
unsigned int nlm_flags) unsigned int nlm_flags)
{ {
struct fib_rt_info fri;
struct sk_buff *skb; struct sk_buff *skb;
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
int err = -ENOBUFS; int err = -ENOBUFS;
...@@ -512,9 +513,15 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, ...@@ -512,9 +513,15 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
if (!skb) if (!skb)
goto errout; goto errout;
err = fib_dump_info(skb, info->portid, seq, event, tb_id, fri.fi = fa->fa_info;
fa->fa_type, key, dst_len, fri.tb_id = tb_id;
fa->fa_tos, fa->fa_info, nlm_flags); fri.dst = key;
fri.dst_len = dst_len;
fri.tos = fa->fa_tos;
fri.type = fa->fa_type;
fri.offload = fa->offload;
fri.trap = fa->trap;
err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags);
if (err < 0) { if (err < 0) {
/* -EMSGSIZE implies BUG in fib_nlmsg_size() */ /* -EMSGSIZE implies BUG in fib_nlmsg_size() */
WARN_ON(err == -EMSGSIZE); WARN_ON(err == -EMSGSIZE);
...@@ -1725,10 +1732,11 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi) ...@@ -1725,10 +1732,11 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi)
#endif #endif
int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, struct fib_rt_info *fri, unsigned int flags)
struct fib_info *fi, unsigned int flags)
{ {
unsigned int nhs = fib_info_num_path(fi); unsigned int nhs = fib_info_num_path(fri->fi);
struct fib_info *fi = fri->fi;
u32 tb_id = fri->tb_id;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct rtmsg *rtm; struct rtmsg *rtm;
...@@ -1738,22 +1746,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -1738,22 +1746,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
rtm = nlmsg_data(nlh); rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET; rtm->rtm_family = AF_INET;
rtm->rtm_dst_len = dst_len; rtm->rtm_dst_len = fri->dst_len;
rtm->rtm_src_len = 0; rtm->rtm_src_len = 0;
rtm->rtm_tos = tos; rtm->rtm_tos = fri->tos;
if (tb_id < 256) if (tb_id < 256)
rtm->rtm_table = tb_id; rtm->rtm_table = tb_id;
else else
rtm->rtm_table = RT_TABLE_COMPAT; rtm->rtm_table = RT_TABLE_COMPAT;
if (nla_put_u32(skb, RTA_TABLE, tb_id)) if (nla_put_u32(skb, RTA_TABLE, tb_id))
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_type = type; rtm->rtm_type = fri->type;
rtm->rtm_flags = fi->fib_flags; rtm->rtm_flags = fi->fib_flags;
rtm->rtm_scope = fi->fib_scope; rtm->rtm_scope = fi->fib_scope;
rtm->rtm_protocol = fi->fib_protocol; rtm->rtm_protocol = fi->fib_protocol;
if (rtm->rtm_dst_len && if (rtm->rtm_dst_len &&
nla_put_in_addr(skb, RTA_DST, dst)) nla_put_in_addr(skb, RTA_DST, fri->dst))
goto nla_put_failure; goto nla_put_failure;
if (fi->fib_priority && if (fi->fib_priority &&
nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority))
...@@ -1795,6 +1803,11 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -1795,6 +1803,11 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
goto nla_put_failure; goto nla_put_failure;
} }
if (fri->offload)
rtm->rtm_flags |= RTM_F_OFFLOAD;
if (fri->trap)
rtm->rtm_flags |= RTM_F_TRAP;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
return 0; return 0;
......
...@@ -1012,6 +1012,52 @@ static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen, ...@@ -1012,6 +1012,52 @@ static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen,
return NULL; return NULL;
} }
static struct fib_alias *
fib_find_matching_alias(struct net *net, const struct fib_rt_info *fri)
{
u8 slen = KEYLENGTH - fri->dst_len;
struct key_vector *l, *tp;
struct fib_table *tb;
struct fib_alias *fa;
struct trie *t;
tb = fib_get_table(net, fri->tb_id);
if (!tb)
return NULL;
t = (struct trie *)tb->tb_data;
l = fib_find_node(t, &tp, be32_to_cpu(fri->dst));
if (!l)
return NULL;
hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
if (fa->fa_slen == slen && fa->tb_id == fri->tb_id &&
fa->fa_tos == fri->tos && fa->fa_info == fri->fi &&
fa->fa_type == fri->type)
return fa;
}
return NULL;
}
void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri)
{
struct fib_alias *fa_match;
rcu_read_lock();
fa_match = fib_find_matching_alias(net, fri);
if (!fa_match)
goto out;
fa_match->offload = fri->offload;
fa_match->trap = fri->trap;
out:
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(fib_alias_hw_flags_set);
static void trie_rebalance(struct trie *t, struct key_vector *tn) static void trie_rebalance(struct trie *t, struct key_vector *tn)
{ {
while (!IS_TRIE(tn)) while (!IS_TRIE(tn))
...@@ -1220,24 +1266,29 @@ int fib_table_insert(struct net *net, struct fib_table *tb, ...@@ -1220,24 +1266,29 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
new_fa->fa_slen = fa->fa_slen; new_fa->fa_slen = fa->fa_slen;
new_fa->tb_id = tb->tb_id; new_fa->tb_id = tb->tb_id;
new_fa->fa_default = -1; new_fa->fa_default = -1;
new_fa->offload = 0;
new_fa->trap = 0;
hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list);
if (fib_find_alias(&l->leaf, fa->fa_slen, 0, 0, if (fib_find_alias(&l->leaf, fa->fa_slen, 0, 0,
tb->tb_id, true) == fa) { tb->tb_id, true) == new_fa) {
enum fib_event_type fib_event; enum fib_event_type fib_event;
fib_event = FIB_EVENT_ENTRY_REPLACE; fib_event = FIB_EVENT_ENTRY_REPLACE;
err = call_fib_entry_notifiers(net, fib_event, err = call_fib_entry_notifiers(net, fib_event,
key, plen, key, plen,
new_fa, extack); new_fa, extack);
if (err) if (err) {
hlist_replace_rcu(&new_fa->fa_list,
&fa->fa_list);
goto out_free_new_fa; goto out_free_new_fa;
}
} }
rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
tb->tb_id, &cfg->fc_nlinfo, nlflags); tb->tb_id, &cfg->fc_nlinfo, nlflags);
hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list);
alias_free_mem_rcu(fa); alias_free_mem_rcu(fa);
fib_release_info(fi_drop); fib_release_info(fi_drop);
...@@ -1275,6 +1326,8 @@ int fib_table_insert(struct net *net, struct fib_table *tb, ...@@ -1275,6 +1326,8 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
new_fa->fa_slen = slen; new_fa->fa_slen = slen;
new_fa->tb_id = tb->tb_id; new_fa->tb_id = tb->tb_id;
new_fa->fa_default = -1; new_fa->fa_default = -1;
new_fa->offload = 0;
new_fa->trap = 0;
/* Insert new entry to the list. */ /* Insert new entry to the list. */
err = fib_insert_alias(t, tp, l, new_fa, fa, key); err = fib_insert_alias(t, tp, l, new_fa, fa, key);
...@@ -2191,14 +2244,20 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, ...@@ -2191,14 +2244,20 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
if (filter->dump_routes) { if (filter->dump_routes) {
if (!s_fa) { if (!s_fa) {
struct fib_rt_info fri;
fri.fi = fi;
fri.tb_id = tb->tb_id;
fri.dst = xkey;
fri.dst_len = KEYLENGTH - fa->fa_slen;
fri.tos = fa->fa_tos;
fri.type = fa->fa_type;
fri.offload = fa->offload;
fri.trap = fa->trap;
err = fib_dump_info(skb, err = fib_dump_info(skb,
NETLINK_CB(cb->skb).portid, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
RTM_NEWROUTE, RTM_NEWROUTE, &fri, flags);
tb->tb_id, fa->fa_type,
xkey,
KEYLENGTH - fa->fa_slen,
fa->fa_tos, fi, flags);
if (err < 0) if (err < 0)
goto stop; goto stop;
} }
......
...@@ -3223,16 +3223,41 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -3223,16 +3223,41 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
if (rtm->rtm_flags & RTM_F_FIB_MATCH) { if (rtm->rtm_flags & RTM_F_FIB_MATCH) {
struct fib_rt_info fri;
if (!res.fi) { if (!res.fi) {
err = fib_props[res.type].error; err = fib_props[res.type].error;
if (!err) if (!err)
err = -EHOSTUNREACH; err = -EHOSTUNREACH;
goto errout_rcu; goto errout_rcu;
} }
fri.fi = res.fi;
fri.tb_id = table_id;
fri.dst = res.prefix;
fri.dst_len = res.prefixlen;
fri.tos = fl4.flowi4_tos;
fri.type = rt->rt_type;
fri.offload = 0;
fri.trap = 0;
if (res.fa_head) {
struct fib_alias *fa;
hlist_for_each_entry_rcu(fa, res.fa_head, fa_list) {
u8 slen = 32 - fri.dst_len;
if (fa->fa_slen == slen &&
fa->tb_id == fri.tb_id &&
fa->fa_tos == fri.tos &&
fa->fa_info == res.fi &&
fa->fa_type == fri.type) {
fri.offload = fa->offload;
fri.trap = fa->trap;
break;
}
}
}
err = fib_dump_info(skb, NETLINK_CB(in_skb).portid, err = fib_dump_info(skb, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, RTM_NEWROUTE, table_id, nlh->nlmsg_seq, RTM_NEWROUTE, &fri, 0);
rt->rt_type, res.prefix, res.prefixlen,
fl4.flowi4_tos, res.fi, 0);
} else { } else {
err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb, err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb,
NETLINK_CB(in_skb).portid, NETLINK_CB(in_skb).portid,
......
...@@ -5576,6 +5576,13 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -5576,6 +5576,13 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
expires -= jiffies; expires -= jiffies;
} }
if (!dst) {
if (rt->offload)
rtm->rtm_flags |= RTM_F_OFFLOAD;
if (rt->trap)
rtm->rtm_flags |= RTM_F_TRAP;
}
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;
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# This test is for checking the FIB offload API on top of mlxsw.
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="
ipv4_identical_routes
ipv4_tos
ipv4_metric
ipv4_replace
ipv4_delete
ipv4_plen
ipv4_replay
ipv4_flush
ipv6_add
ipv6_metric
ipv6_append_single
ipv6_replace_single
ipv6_metric_multipath
ipv6_append_multipath
ipv6_replace_multipath
ipv6_append_multipath_to_single
ipv6_delete_single
ipv6_delete_multipath
ipv6_replay_single
ipv6_replay_multipath
"
NUM_NETIFS=0
source $lib_dir/lib.sh
source $lib_dir/devlink_lib.sh
source $lib_dir/fib_offload_lib.sh
ipv4_identical_routes()
{
fib_ipv4_identical_routes_test "testns1"
}
ipv4_tos()
{
fib_ipv4_tos_test "testns1"
}
ipv4_metric()
{
fib_ipv4_metric_test "testns1"
}
ipv4_replace()
{
fib_ipv4_replace_test "testns1"
}
ipv4_delete()
{
fib_ipv4_delete_test "testns1"
}
ipv4_plen()
{
fib_ipv4_plen_test "testns1"
}
ipv4_replay_metric()
{
fib_ipv4_replay_metric_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay_tos()
{
fib_ipv4_replay_tos_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay_plen()
{
fib_ipv4_replay_plen_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay()
{
ipv4_replay_metric
ipv4_replay_tos
ipv4_replay_plen
}
ipv4_flush()
{
fib_ipv4_flush_test "testns1"
}
ipv6_add()
{
fib_ipv6_add_test "testns1"
}
ipv6_metric()
{
fib_ipv6_metric_test "testns1"
}
ipv6_append_single()
{
fib_ipv6_append_single_test "testns1"
}
ipv6_replace_single()
{
fib_ipv6_replace_single_test "testns1"
}
ipv6_metric_multipath()
{
fib_ipv6_metric_multipath_test "testns1"
}
ipv6_append_multipath()
{
fib_ipv6_append_multipath_test "testns1"
}
ipv6_replace_multipath()
{
fib_ipv6_replace_multipath_test "testns1"
}
ipv6_append_multipath_to_single()
{
fib_ipv6_append_multipath_to_single_test "testns1"
}
ipv6_delete_single()
{
fib_ipv6_delete_single_test "testns1"
}
ipv6_delete_multipath()
{
fib_ipv6_delete_multipath_test "testns1"
}
ipv6_replay_single()
{
fib_ipv6_replay_single_test "testns1" "$DEVLINK_DEV"
}
ipv6_replay_multipath()
{
fib_ipv6_replay_multipath_test "testns1" "$DEVLINK_DEV"
}
setup_prepare()
{
ip netns add testns1
if [ $? -ne 0 ]; then
echo "Failed to add netns \"testns1\""
exit 1
fi
devlink dev reload $DEVLINK_DEV netns testns1
if [ $? -ne 0 ]; then
echo "Failed to reload into netns \"testns1\""
exit 1
fi
}
cleanup()
{
pre_cleanup
devlink -N testns1 dev reload $DEVLINK_DEV netns $$
ip netns del testns1
}
trap cleanup EXIT
setup_prepare
tests_run
exit $EXIT_STATUS
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# This test is for checking the FIB offload API. It makes use of netdevsim
# which registers a listener to the FIB notification chain.
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="
ipv4_identical_routes
ipv4_tos
ipv4_metric
ipv4_replace
ipv4_delete
ipv4_plen
ipv4_replay
ipv4_flush
ipv4_error_path
ipv6_add
ipv6_metric
ipv6_append_single
ipv6_replace_single
ipv6_metric_multipath
ipv6_append_multipath
ipv6_replace_multipath
ipv6_append_multipath_to_single
ipv6_delete_single
ipv6_delete_multipath
ipv6_replay_single
ipv6_replay_multipath
ipv6_error_path
"
NETDEVSIM_PATH=/sys/bus/netdevsim/
DEV_ADDR=1337
DEV=netdevsim${DEV_ADDR}
DEVLINK_DEV=netdevsim/${DEV}
SYSFS_NET_DIR=/sys/bus/netdevsim/devices/$DEV/net/
NUM_NETIFS=0
source $lib_dir/lib.sh
source $lib_dir/devlink_lib.sh
source $lib_dir/fib_offload_lib.sh
ipv4_identical_routes()
{
fib_ipv4_identical_routes_test "testns1"
}
ipv4_tos()
{
fib_ipv4_tos_test "testns1"
}
ipv4_metric()
{
fib_ipv4_metric_test "testns1"
}
ipv4_replace()
{
fib_ipv4_replace_test "testns1"
}
ipv4_delete()
{
fib_ipv4_delete_test "testns1"
}
ipv4_plen()
{
fib_ipv4_plen_test "testns1"
}
ipv4_replay_metric()
{
fib_ipv4_replay_metric_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay_tos()
{
fib_ipv4_replay_tos_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay_plen()
{
fib_ipv4_replay_plen_test "testns1" "$DEVLINK_DEV"
}
ipv4_replay()
{
ipv4_replay_metric
ipv4_replay_tos
ipv4_replay_plen
}
ipv4_flush()
{
fib_ipv4_flush_test "testns1"
}
ipv4_error_path_add()
{
local lsb
RET=0
ip -n testns1 link add name dummy1 type dummy
ip -n testns1 link set dev dummy1 up
devlink -N testns1 resource set $DEVLINK_DEV path IPv4/fib size 10
devlink -N testns1 dev reload $DEVLINK_DEV
for lsb in $(seq 1 20); do
ip -n testns1 route add 192.0.2.${lsb}/32 dev dummy1 \
&> /dev/null
done
log_test "IPv4 error path - add"
ip -n testns1 link del dev dummy1
}
ipv4_error_path_replay()
{
local lsb
RET=0
ip -n testns1 link add name dummy1 type dummy
ip -n testns1 link set dev dummy1 up
devlink -N testns1 resource set $DEVLINK_DEV path IPv4/fib size 100
devlink -N testns1 dev reload $DEVLINK_DEV
for lsb in $(seq 1 20); do
ip -n testns1 route add 192.0.2.${lsb}/32 dev dummy1
done
devlink -N testns1 resource set $DEVLINK_DEV path IPv4/fib size 10
devlink -N testns1 dev reload $DEVLINK_DEV &> /dev/null
log_test "IPv4 error path - replay"
ip -n testns1 link del dev dummy1
# Successfully reload after deleting all the routes.
devlink -N testns1 resource set $DEVLINK_DEV path IPv4/fib size 100
devlink -N testns1 dev reload $DEVLINK_DEV
}
ipv4_error_path()
{
# Test the different error paths of the notifiers by limiting the size
# of the "IPv4/fib" resource.
ipv4_error_path_add
ipv4_error_path_replay
}
ipv6_add()
{
fib_ipv6_add_test "testns1"
}
ipv6_metric()
{
fib_ipv6_metric_test "testns1"
}
ipv6_append_single()
{
fib_ipv6_append_single_test "testns1"
}
ipv6_replace_single()
{
fib_ipv6_replace_single_test "testns1"
}
ipv6_metric_multipath()
{
fib_ipv6_metric_multipath_test "testns1"
}
ipv6_append_multipath()
{
fib_ipv6_append_multipath_test "testns1"
}
ipv6_replace_multipath()
{
fib_ipv6_replace_multipath_test "testns1"
}
ipv6_append_multipath_to_single()
{
fib_ipv6_append_multipath_to_single_test "testns1"
}
ipv6_delete_single()
{
fib_ipv6_delete_single_test "testns1"
}
ipv6_delete_multipath()
{
fib_ipv6_delete_multipath_test "testns1"
}
ipv6_replay_single()
{
fib_ipv6_replay_single_test "testns1" "$DEVLINK_DEV"
}
ipv6_replay_multipath()
{
fib_ipv6_replay_multipath_test "testns1" "$DEVLINK_DEV"
}
ipv6_error_path_add_single()
{
local lsb
RET=0
ip -n testns1 link add name dummy1 type dummy
ip -n testns1 link set dev dummy1 up
devlink -N testns1 resource set $DEVLINK_DEV path IPv6/fib size 10
devlink -N testns1 dev reload $DEVLINK_DEV
for lsb in $(seq 1 20); do
ip -n testns1 route add 2001:db8:1::${lsb}/128 dev dummy1 \
&> /dev/null
done
log_test "IPv6 error path - add single"
ip -n testns1 link del dev dummy1
}
ipv6_error_path_add_multipath()
{
local lsb
RET=0
for i in $(seq 1 2); do
ip -n testns1 link add name dummy$i type dummy
ip -n testns1 link set dev dummy$i up
ip -n testns1 address add 2001:db8:$i::1/64 dev dummy$i
done
devlink -N testns1 resource set $DEVLINK_DEV path IPv6/fib size 10
devlink -N testns1 dev reload $DEVLINK_DEV
for lsb in $(seq 1 20); do
ip -n testns1 route add 2001:db8:10::${lsb}/128 \
nexthop via 2001:db8:1::2 dev dummy1 \
nexthop via 2001:db8:2::2 dev dummy2 &> /dev/null
done
log_test "IPv6 error path - add multipath"
for i in $(seq 1 2); do
ip -n testns1 link del dev dummy$i
done
}
ipv6_error_path_replay()
{
local lsb
RET=0
ip -n testns1 link add name dummy1 type dummy
ip -n testns1 link set dev dummy1 up
devlink -N testns1 resource set $DEVLINK_DEV path IPv6/fib size 100
devlink -N testns1 dev reload $DEVLINK_DEV
for lsb in $(seq 1 20); do
ip -n testns1 route add 2001:db8:1::${lsb}/128 dev dummy1
done
devlink -N testns1 resource set $DEVLINK_DEV path IPv6/fib size 10
devlink -N testns1 dev reload $DEVLINK_DEV &> /dev/null
log_test "IPv6 error path - replay"
ip -n testns1 link del dev dummy1
# Successfully reload after deleting all the routes.
devlink -N testns1 resource set $DEVLINK_DEV path IPv6/fib size 100
devlink -N testns1 dev reload $DEVLINK_DEV
}
ipv6_error_path()
{
# Test the different error paths of the notifiers by limiting the size
# of the "IPv6/fib" resource.
ipv6_error_path_add_single
ipv6_error_path_add_multipath
ipv6_error_path_replay
}
setup_prepare()
{
local netdev
modprobe netdevsim &> /dev/null
echo "$DEV_ADDR 1" > ${NETDEVSIM_PATH}/new_device
while [ ! -d $SYSFS_NET_DIR ] ; do :; done
ip netns add testns1
if [ $? -ne 0 ]; then
echo "Failed to add netns \"testns1\""
exit 1
fi
devlink dev reload $DEVLINK_DEV netns testns1
if [ $? -ne 0 ]; then
echo "Failed to reload into netns \"testns1\""
exit 1
fi
}
cleanup()
{
pre_cleanup
ip netns del testns1
echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device
modprobe -r netdevsim &> /dev/null
}
trap cleanup EXIT
setup_prepare
tests_run
exit $EXIT_STATUS
This diff is collapsed.
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