Commit 4001f1f0 authored by David S. Miller's avatar David S. Miller

Merge branch 'Support-for-fdb-ECMP-nexthop-groups'

Roopa Prabhu says:

====================
Support for fdb ECMP nexthop groups

This series introduces ecmp nexthops and nexthop groups
for mac fdb entries. In subsequent patches this is used
by the vxlan driver fdb entries. The use case is
E-VPN multihoming [1,2,3] which requires bridged vxlan traffic
to be load balanced to remote switches (vteps) belonging to
the same multi-homed ethernet segment (This is analogous to
a multi-homed LAG but over vxlan).

Changes include new nexthop flag NHA_FDB for nexthops
referenced by fdb entries. These nexthops only have ip.
The patches make sure that routes dont reference such nexthops.

example:
$ip nexthop add id 12 via 172.16.1.2 fdb
$ip nexthop add id 13 via 172.16.1.3 fdb
$ip nexthop add id 102 group 12/13 fdb

$bridge fdb add 02:02:00:00:00:13 dev vxlan1000 nhid 101 self

[1] E-VPN https://tools.ietf.org/html/rfc7432
[2] E-VPN VxLAN: https://tools.ietf.org/html/rfc8365
[3] LPC talk with mention of nexthop groups for L2 ecmp
http://vger.kernel.org/lpc_net2018_talks/scaling_bridge_fdb_database_slidesV3.pdf

v4 -
    - fix error path free_skb in vxlan_xmit_nh
    - fix atomic notifier initialization issue
      (Reported-by: kernel test robot <rong.a.chen@intel.com>)
      The reported error was easy to locate and fix, but i was not
      able to re-test with the robot reproducer script due to some
      other issues with running the script on my test system.

v3 - fix wording in selftest print as pointed out by davidA

v2 -
	- dropped nikolays fixes for nexthop multipath null pointer deref
	  (he will send those separately)
	- added negative tests for route add with fdb nexthop + a few more
	- Fixes for a few  fdb replace conditions found during more testing
	- Moved to rcu_dereference_rtnl in vxlan_fdb_info and consolidate rcu
	  dereferences
	- Fixes to build failures Reported-by: kbuild test robot <lkp@intel.com>
	- DavidA, I am going to send a separate patch for the neighbor code validation
	  for NDA_NH_ID if thats ok.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7b1b843a 0534c548
This diff is collapsed.
......@@ -65,6 +65,7 @@ struct fib6_config {
struct nl_info fc_nlinfo;
struct nlattr *fc_encap;
u16 fc_encap_type;
bool fc_is_fdb;
};
struct fib6_node {
......
......@@ -14,5 +14,6 @@ struct netns_nexthop {
unsigned int seq; /* protected by rtnl_mutex */
u32 last_id_allocated;
struct atomic_notifier_head notifier_chain;
};
#endif
......@@ -10,6 +10,7 @@
#define __LINUX_NEXTHOP_H
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <linux/route.h>
#include <linux/types.h>
#include <net/ip_fib.h>
......@@ -26,6 +27,7 @@ struct nh_config {
u8 nh_family;
u8 nh_protocol;
u8 nh_blackhole;
u8 nh_fdb;
u32 nh_flags;
int nh_ifindex;
......@@ -52,6 +54,7 @@ struct nh_info {
u8 family;
bool reject_nh;
bool fdb_nh;
union {
struct fib_nh_common fib_nhc;
......@@ -80,6 +83,7 @@ struct nexthop {
struct rb_node rb_node; /* entry on netns rbtree */
struct list_head fi_list; /* v4 entries using nh */
struct list_head f6i_list; /* v6 entries using nh */
struct list_head fdb_list; /* fdb entries using this nh */
struct list_head grp_list; /* nh group entries using this nh */
struct net *net;
......@@ -88,6 +92,7 @@ struct nexthop {
u8 protocol; /* app managing this nh */
u8 nh_flags;
bool is_group;
bool is_fdb_nh;
refcount_t refcnt;
struct rcu_head rcu;
......@@ -98,6 +103,17 @@ struct nexthop {
};
};
enum nexthop_event_type {
NEXTHOP_EVENT_ADD,
NEXTHOP_EVENT_DEL
};
int call_nexthop_notifier(struct notifier_block *nb, struct net *net,
enum nexthop_event_type event_type,
struct nexthop *nh);
int register_nexthop_notifier(struct net *net, struct notifier_block *nb);
int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
/* caller is holding rcu or rtnl; no reference taken to nexthop */
struct nexthop *nexthop_find_by_id(struct net *net, u32 id);
void nexthop_free_rcu(struct rcu_head *head);
......@@ -304,4 +320,32 @@ static inline void nexthop_path_fib6_result(struct fib6_result *res, int hash)
int nexthop_for_each_fib6_nh(struct nexthop *nh,
int (*cb)(struct fib6_nh *nh, void *arg),
void *arg);
static inline int nexthop_get_family(struct nexthop *nh)
{
struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
return nhi->family;
}
static inline
struct fib_nh_common *nexthop_fdb_nhc(struct nexthop *nh)
{
struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
return &nhi->fib_nhc;
}
static inline struct fib_nh_common *nexthop_path_fdb_result(struct nexthop *nh,
int hash)
{
struct nh_info *nhi;
struct nexthop *nhp;
nhp = nexthop_select_path(nh, hash);
if (unlikely(!nhp))
return NULL;
nhi = rcu_dereference(nhp->nh_info);
return &nhi->fib_nhc;
}
#endif
......@@ -7,6 +7,7 @@
#include <net/dst_metadata.h>
#include <net/rtnetlink.h>
#include <net/switchdev.h>
#include <net/nexthop.h>
#define IANA_VXLAN_UDP_PORT 4789
......@@ -487,4 +488,28 @@ static inline void vxlan_flag_attr_error(int attrtype,
#undef VXLAN_FLAG
}
static inline bool vxlan_fdb_nh_path_select(struct nexthop *nh,
int hash,
struct vxlan_rdst *rdst)
{
struct fib_nh_common *nhc;
nhc = nexthop_path_fdb_result(nh, hash);
if (unlikely(!nhc))
return false;
switch (nhc->nhc_gw_family) {
case AF_INET:
rdst->remote_ip.sin.sin_addr.s_addr = nhc->nhc_gw.ipv4;
rdst->remote_ip.sa.sa_family = AF_INET;
break;
case AF_INET6:
rdst->remote_ip.sin6.sin6_addr = nhc->nhc_gw.ipv6;
rdst->remote_ip.sa.sa_family = AF_INET6;
break;
}
return true;
}
#endif
......@@ -29,6 +29,7 @@ enum {
NDA_LINK_NETNSID,
NDA_SRC_VNI,
NDA_PROTOCOL, /* Originator of entry */
NDA_NH_ID,
__NDA_MAX
};
......
......@@ -49,6 +49,9 @@ enum {
NHA_GROUPS, /* flag; only return nexthop groups in dump */
NHA_MASTER, /* u32; only return nexthops with given master dev */
NHA_FDB, /* flag; nexthop belongs to a bridge fdb */
/* if NHA_FDB is added, OIF, BLACKHOLE, ENCAP cannot be set */
__NHA_MAX,
};
......
......@@ -1771,6 +1771,7 @@ static struct neigh_table *neigh_find_table(int family)
}
const struct nla_policy nda_policy[NDA_MAX+1] = {
[NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID },
[NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
......@@ -1781,6 +1782,7 @@ const struct nla_policy nda_policy[NDA_MAX+1] = {
[NDA_IFINDEX] = { .type = NLA_U32 },
[NDA_MASTER] = { .type = NLA_U32 },
[NDA_PROTOCOL] = { .type = NLA_U8 },
[NDA_NH_ID] = { .type = NLA_U32 },
};
static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
......
......@@ -33,8 +33,20 @@ static const struct nla_policy rtm_nh_policy[NHA_MAX + 1] = {
[NHA_ENCAP] = { .type = NLA_NESTED },
[NHA_GROUPS] = { .type = NLA_FLAG },
[NHA_MASTER] = { .type = NLA_U32 },
[NHA_FDB] = { .type = NLA_FLAG },
};
static int call_nexthop_notifiers(struct net *net,
enum fib_event_type event_type,
struct nexthop *nh)
{
int err;
err = atomic_notifier_call_chain(&net->nexthop.notifier_chain,
event_type, nh);
return notifier_to_errno(err);
}
static unsigned int nh_dev_hashfn(unsigned int val)
{
unsigned int mask = NH_DEV_HASHSIZE - 1;
......@@ -107,6 +119,7 @@ static struct nexthop *nexthop_alloc(void)
INIT_LIST_HEAD(&nh->fi_list);
INIT_LIST_HEAD(&nh->f6i_list);
INIT_LIST_HEAD(&nh->grp_list);
INIT_LIST_HEAD(&nh->fdb_list);
}
return nh;
}
......@@ -227,6 +240,9 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
if (nla_put_u32(skb, NHA_ID, nh->id))
goto nla_put_failure;
if (nh->is_fdb_nh && nla_put_flag(skb, NHA_FDB))
goto nla_put_failure;
if (nh->is_group) {
struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
......@@ -241,7 +257,7 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
if (nla_put_flag(skb, NHA_BLACKHOLE))
goto nla_put_failure;
goto out;
} else {
} else if (!nh->is_fdb_nh) {
const struct net_device *dev;
dev = nhi->fib_nhc.nhc_dev;
......@@ -387,12 +403,35 @@ static bool valid_group_nh(struct nexthop *nh, unsigned int npaths,
return true;
}
static int nh_check_attr_fdb_group(struct nexthop *nh, u8 *nh_family,
struct netlink_ext_ack *extack)
{
struct nh_info *nhi;
if (!nh->is_fdb_nh) {
NL_SET_ERR_MSG(extack, "FDB nexthop group can only have fdb nexthops");
return -EINVAL;
}
nhi = rtnl_dereference(nh->nh_info);
if (*nh_family == AF_UNSPEC) {
*nh_family = nhi->family;
} else if (*nh_family != nhi->family) {
NL_SET_ERR_MSG(extack, "FDB nexthop group cannot have mixed family nexthops");
return -EINVAL;
}
return 0;
}
static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
struct netlink_ext_ack *extack)
{
unsigned int len = nla_len(tb[NHA_GROUP]);
u8 nh_family = AF_UNSPEC;
struct nexthop_grp *nhg;
unsigned int i, j;
u8 nhg_fdb = 0;
if (len & (sizeof(struct nexthop_grp) - 1)) {
NL_SET_ERR_MSG(extack,
......@@ -421,6 +460,8 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
}
}
if (tb[NHA_FDB])
nhg_fdb = 1;
nhg = nla_data(tb[NHA_GROUP]);
for (i = 0; i < len; ++i) {
struct nexthop *nh;
......@@ -432,11 +473,20 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
}
if (!valid_group_nh(nh, len, extack))
return -EINVAL;
if (nhg_fdb && nh_check_attr_fdb_group(nh, &nh_family, extack))
return -EINVAL;
if (!nhg_fdb && nh->is_fdb_nh) {
NL_SET_ERR_MSG(extack, "Non FDB nexthop group cannot have fdb nexthops");
return -EINVAL;
}
}
for (i = NHA_GROUP + 1; i < __NHA_MAX; ++i) {
if (!tb[i])
continue;
if (tb[NHA_FDB])
continue;
NL_SET_ERR_MSG(extack,
"No other attributes can be set in nexthop groups");
return -EINVAL;
......@@ -495,6 +545,9 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
if (hash > atomic_read(&nhge->upper_bound))
continue;
if (nhge->nh->is_fdb_nh)
return nhge->nh;
/* nexthops always check if it is good and does
* not rely on a sysctl for this behavior
*/
......@@ -564,6 +617,11 @@ int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
{
struct nh_info *nhi;
if (nh->is_fdb_nh) {
NL_SET_ERR_MSG(extack, "Route cannot point to a fdb nexthop");
return -EINVAL;
}
/* fib6_src is unique to a fib6_info and limits the ability to cache
* routes in fib6_nh within a nexthop that is potentially shared
* across multiple fib entries. If the config wants to use source
......@@ -640,6 +698,12 @@ int fib_check_nexthop(struct nexthop *nh, u8 scope,
{
int err = 0;
if (nh->is_fdb_nh) {
NL_SET_ERR_MSG(extack, "Route cannot point to a fdb nexthop");
err = -EINVAL;
goto out;
}
if (nh->is_group) {
struct nh_group *nhg;
......@@ -773,6 +837,8 @@ static void __remove_nexthop_fib(struct net *net, struct nexthop *nh)
bool do_flush = false;
struct fib_info *fi;
call_nexthop_notifiers(net, NEXTHOP_EVENT_DEL, nh);
list_for_each_entry(fi, &nh->fi_list, nh_list) {
fi->fib_flags |= RTNH_F_DEAD;
do_flush = true;
......@@ -1125,6 +1191,9 @@ static struct nexthop *nexthop_create_group(struct net *net,
nh_group_rebalance(nhg);
}
if (cfg->nh_fdb)
nh->is_fdb_nh = 1;
rcu_assign_pointer(nh->nh_grp, nhg);
return nh;
......@@ -1152,7 +1221,7 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
.fc_encap = cfg->nh_encap,
.fc_encap_type = cfg->nh_encap_type,
};
u32 tb_id = l3mdev_fib_table(cfg->dev);
u32 tb_id = (cfg->dev ? l3mdev_fib_table(cfg->dev) : RT_TABLE_MAIN);
int err;
err = fib_nh_init(net, fib_nh, &fib_cfg, 1, extack);
......@@ -1161,6 +1230,9 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
goto out;
}
if (nh->is_fdb_nh)
goto out;
/* sets nh_dev if successful */
err = fib_check_nh(net, fib_nh, tb_id, 0, extack);
if (!err) {
......@@ -1186,6 +1258,7 @@ static int nh_create_ipv6(struct net *net, struct nexthop *nh,
.fc_flags = cfg->nh_flags,
.fc_encap = cfg->nh_encap,
.fc_encap_type = cfg->nh_encap_type,
.fc_is_fdb = cfg->nh_fdb,
};
int err;
......@@ -1227,6 +1300,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
nhi->family = cfg->nh_family;
nhi->fib_nhc.nhc_scope = RT_SCOPE_LINK;
if (cfg->nh_fdb)
nh->is_fdb_nh = 1;
if (cfg->nh_blackhole) {
nhi->reject_nh = 1;
cfg->nh_ifindex = net->loopback_dev->ifindex;
......@@ -1248,6 +1324,7 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
}
/* add the entry to the device based hash */
if (!nh->is_fdb_nh)
nexthop_devhash_add(net, nhi);
rcu_assign_pointer(nh->nh_info, nhi);
......@@ -1352,6 +1429,19 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
if (tb[NHA_ID])
cfg->nh_id = nla_get_u32(tb[NHA_ID]);
if (tb[NHA_FDB]) {
if (tb[NHA_OIF] || tb[NHA_BLACKHOLE] ||
tb[NHA_ENCAP] || tb[NHA_ENCAP_TYPE]) {
NL_SET_ERR_MSG(extack, "Fdb attribute can not be used with encap, oif or blackhole");
goto out;
}
if (nhm->nh_flags) {
NL_SET_ERR_MSG(extack, "Unsupported nexthop flags in ancillary header");
goto out;
}
cfg->nh_fdb = nla_get_flag(tb[NHA_FDB]);
}
if (tb[NHA_GROUP]) {
if (nhm->nh_family != AF_UNSPEC) {
NL_SET_ERR_MSG(extack, "Invalid family for group");
......@@ -1375,8 +1465,8 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
if (tb[NHA_BLACKHOLE]) {
if (tb[NHA_GATEWAY] || tb[NHA_OIF] ||
tb[NHA_ENCAP] || tb[NHA_ENCAP_TYPE]) {
NL_SET_ERR_MSG(extack, "Blackhole attribute can not be used with gateway or oif");
tb[NHA_ENCAP] || tb[NHA_ENCAP_TYPE] || tb[NHA_FDB]) {
NL_SET_ERR_MSG(extack, "Blackhole attribute can not be used with gateway, oif, encap or fdb");
goto out;
}
......@@ -1385,11 +1475,12 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
goto out;
}
if (!tb[NHA_OIF]) {
NL_SET_ERR_MSG(extack, "Device attribute required for non-blackhole nexthops");
if (!cfg->nh_fdb && !tb[NHA_OIF]) {
NL_SET_ERR_MSG(extack, "Device attribute required for non-blackhole and non-fdb nexthops");
goto out;
}
if (!cfg->nh_fdb && tb[NHA_OIF]) {
cfg->nh_ifindex = nla_get_u32(tb[NHA_OIF]);
if (cfg->nh_ifindex)
cfg->dev = __dev_get_by_index(net, cfg->nh_ifindex);
......@@ -1406,6 +1497,7 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
err = -ENETDOWN;
goto out;
}
}
err = -EINVAL;
if (tb[NHA_GATEWAY]) {
......@@ -1633,7 +1725,7 @@ static bool nh_dump_filtered(struct nexthop *nh, int dev_idx, int master_idx,
static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
int *master_idx, bool *group_filter,
struct netlink_callback *cb)
bool *fdb_filter, struct netlink_callback *cb)
{
struct netlink_ext_ack *extack = cb->extack;
struct nlattr *tb[NHA_MAX + 1];
......@@ -1670,6 +1762,9 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
case NHA_GROUPS:
*group_filter = true;
break;
case NHA_FDB:
*fdb_filter = true;
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported attribute in dump request");
return -EINVAL;
......@@ -1688,17 +1783,17 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh, int *dev_idx,
/* rtnl */
static int rtm_dump_nexthop(struct sk_buff *skb, struct netlink_callback *cb)
{
bool group_filter = false, fdb_filter = false;
struct nhmsg *nhm = nlmsg_data(cb->nlh);
int dev_filter_idx = 0, master_idx = 0;
struct net *net = sock_net(skb->sk);
struct rb_root *root = &net->nexthop.rb_root;
bool group_filter = false;
struct rb_node *node;
int idx = 0, s_idx;
int err;
err = nh_valid_dump_req(cb->nlh, &dev_filter_idx, &master_idx,
&group_filter, cb);
&group_filter, &fdb_filter, cb);
if (err < 0)
return err;
......@@ -1783,6 +1878,19 @@ static struct notifier_block nh_netdev_notifier = {
.notifier_call = nh_netdev_event,
};
int register_nexthop_notifier(struct net *net, struct notifier_block *nb)
{
return atomic_notifier_chain_register(&net->nexthop.notifier_chain, nb);
}
EXPORT_SYMBOL(register_nexthop_notifier);
int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&net->nexthop.notifier_chain,
nb);
}
EXPORT_SYMBOL(unregister_nexthop_notifier);
static void __net_exit nexthop_net_exit(struct net *net)
{
rtnl_lock();
......@@ -1799,6 +1907,7 @@ static int __net_init nexthop_net_init(struct net *net)
net->nexthop.devhash = kzalloc(sz, GFP_KERNEL);
if (!net->nexthop.devhash)
return -ENOMEM;
ATOMIC_INIT_NOTIFIER_HEAD(&net->nexthop.notifier_chain);
return 0;
}
......
......@@ -3421,6 +3421,11 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
#ifdef CONFIG_IPV6_ROUTER_PREF
fib6_nh->last_probe = jiffies;
#endif
if (cfg->fc_is_fdb) {
fib6_nh->fib_nh_gw6 = cfg->fc_gateway;
fib6_nh->fib_nh_gw_family = AF_INET6;
return 0;
}
err = -ENODEV;
if (cfg->fc_ifindex) {
......
......@@ -19,8 +19,8 @@ ret=0
ksft_skip=4
# all tests in this script. Can be overridden with -t option
IPV4_TESTS="ipv4_fcnal ipv4_grp_fcnal ipv4_withv6_fcnal ipv4_fcnal_runtime ipv4_compat_mode"
IPV6_TESTS="ipv6_fcnal ipv6_grp_fcnal ipv6_fcnal_runtime ipv6_compat_mode"
IPV4_TESTS="ipv4_fcnal ipv4_grp_fcnal ipv4_withv6_fcnal ipv4_fcnal_runtime ipv4_compat_mode ipv4_fdb_grp_fcnal"
IPV6_TESTS="ipv6_fcnal ipv6_grp_fcnal ipv6_fcnal_runtime ipv6_compat_mode ipv6_fdb_grp_fcnal"
ALL_TESTS="basic ${IPV4_TESTS} ${IPV6_TESTS}"
TESTS="${ALL_TESTS}"
......@@ -146,6 +146,7 @@ setup()
create_ns remote
IP="ip -netns me"
BRIDGE="bridge -netns me"
set -e
$IP li add veth1 type veth peer name veth2
$IP li set veth1 up
......@@ -280,6 +281,161 @@ stop_ip_monitor()
return $rc
}
check_nexthop_fdb_support()
{
$IP nexthop help 2>&1 | grep -q fdb
if [ $? -ne 0 ]; then
echo "SKIP: iproute2 too old, missing fdb nexthop support"
return $ksft_skip
fi
}
ipv6_fdb_grp_fcnal()
{
local rc
echo
echo "IPv6 fdb groups functional"
echo "--------------------------"
check_nexthop_fdb_support
if [ $? -eq $ksft_skip ]; then
return $ksft_skip
fi
# create group with multiple nexthops
run_cmd "$IP nexthop add id 61 via 2001:db8:91::2 fdb"
run_cmd "$IP nexthop add id 62 via 2001:db8:91::3 fdb"
run_cmd "$IP nexthop add id 102 group 61/62 fdb"
check_nexthop "id 102" "id 102 group 61/62 fdb"
log_test $? 0 "Fdb Nexthop group with multiple nexthops"
## get nexthop group
run_cmd "$IP nexthop get id 102"
check_nexthop "id 102" "id 102 group 61/62 fdb"
log_test $? 0 "Get Fdb nexthop group by id"
# fdb nexthop group can only contain fdb nexthops
run_cmd "$IP nexthop add id 63 via 2001:db8:91::4"
run_cmd "$IP nexthop add id 64 via 2001:db8:91::5"
run_cmd "$IP nexthop add id 103 group 63/64 fdb"
log_test $? 2 "Fdb Nexthop group with non-fdb nexthops"
# Non fdb nexthop group can not contain fdb nexthops
run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 fdb"
run_cmd "$IP nexthop add id 66 via 2001:db8:91::6 fdb"
run_cmd "$IP nexthop add id 104 group 65/66"
log_test $? 2 "Non-Fdb Nexthop group with fdb nexthops"
# fdb nexthop cannot have blackhole
run_cmd "$IP nexthop add id 67 blackhole fdb"
log_test $? 2 "Fdb Nexthop with blackhole"
# fdb nexthop with oif
run_cmd "$IP nexthop add id 68 via 2001:db8:91::7 dev veth1 fdb"
log_test $? 2 "Fdb Nexthop with oif"
# fdb nexthop with onlink
run_cmd "$IP nexthop add id 68 via 2001:db8:91::7 onlink fdb"
log_test $? 2 "Fdb Nexthop with onlink"
# fdb nexthop with encap
run_cmd "$IP nexthop add id 69 encap mpls 101 via 2001:db8:91::8 dev veth1 fdb"
log_test $? 2 "Fdb Nexthop with encap"
run_cmd "$IP link add name vx10 type vxlan id 1010 local 2001:db8:91::9 remote 2001:db8:91::10 dstport 4789 nolearning noudpcsum tos inherit ttl 100"
run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self"
log_test $? 0 "Fdb mac add with nexthop group"
## fdb nexthops can only reference nexthop groups and not nexthops
run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 61 self"
log_test $? 255 "Fdb mac add with nexthop"
run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 66"
log_test $? 2 "Route add with fdb nexthop"
run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 103"
log_test $? 2 "Route add with fdb nexthop group"
run_cmd "$IP nexthop del id 102"
log_test $? 0 "Fdb nexthop delete"
$IP link del dev vx10
}
ipv4_fdb_grp_fcnal()
{
local rc
echo
echo "IPv4 fdb groups functional"
echo "--------------------------"
check_nexthop_fdb_support
if [ $? -eq $ksft_skip ]; then
return $ksft_skip
fi
# create group with multiple nexthops
run_cmd "$IP nexthop add id 12 via 172.16.1.2 fdb"
run_cmd "$IP nexthop add id 13 via 172.16.1.3 fdb"
run_cmd "$IP nexthop add id 102 group 12/13 fdb"
check_nexthop "id 102" "id 102 group 12/13 fdb"
log_test $? 0 "Fdb Nexthop group with multiple nexthops"
# get nexthop group
run_cmd "$IP nexthop get id 102"
check_nexthop "id 102" "id 102 group 12/13 fdb"
log_test $? 0 "Get Fdb nexthop group by id"
# fdb nexthop group can only contain fdb nexthops
run_cmd "$IP nexthop add id 14 via 172.16.1.2"
run_cmd "$IP nexthop add id 15 via 172.16.1.3"
run_cmd "$IP nexthop add id 103 group 14/15 fdb"
log_test $? 2 "Fdb Nexthop group with non-fdb nexthops"
# Non fdb nexthop group can not contain fdb nexthops
run_cmd "$IP nexthop add id 16 via 172.16.1.2 fdb"
run_cmd "$IP nexthop add id 17 via 172.16.1.3 fdb"
run_cmd "$IP nexthop add id 104 group 14/15"
log_test $? 2 "Non-Fdb Nexthop group with fdb nexthops"
# fdb nexthop cannot have blackhole
run_cmd "$IP nexthop add id 18 blackhole fdb"
log_test $? 2 "Fdb Nexthop with blackhole"
# fdb nexthop with oif
run_cmd "$IP nexthop add id 16 via 172.16.1.2 dev veth1 fdb"
log_test $? 2 "Fdb Nexthop with oif"
# fdb nexthop with onlink
run_cmd "$IP nexthop add id 16 via 172.16.1.2 onlink fdb"
log_test $? 2 "Fdb Nexthop with onlink"
# fdb nexthop with encap
run_cmd "$IP nexthop add id 17 encap mpls 101 via 172.16.1.2 dev veth1 fdb"
log_test $? 2 "Fdb Nexthop with encap"
run_cmd "$IP link add name vx10 type vxlan id 1010 local 10.0.0.1 remote 10.0.0.2 dstport 4789 nolearning noudpcsum tos inherit ttl 100"
run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self"
log_test $? 0 "Fdb mac add with nexthop group"
# fdb nexthops can only reference nexthop groups and not nexthops
run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 12 self"
log_test $? 255 "Fdb mac add with nexthop"
run_cmd "$IP ro add 172.16.0.0/22 nhid 15"
log_test $? 2 "Route add with fdb nexthop"
run_cmd "$IP ro add 172.16.0.0/22 nhid 103"
log_test $? 2 "Route add with fdb nexthop group"
run_cmd "$IP nexthop del id 102"
log_test $? 0 "Fdb nexthop delete"
$IP link del dev vx10
}
################################################################################
# basic operations (add, delete, replace) on nexthops and nexthop groups
#
......
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