The merge commit 92716869375b ("Merge branch 'br-flush-filtering'") added support for FDB flushing in bridge driver. Extend VXLAN driver to support FDB flushing also. Add support for filtering by fields which are relevant for VXLAN FDBs: * Source VNI * Nexthop ID * 'router' flag * Destination VNI * Destination Port * Destination IP
Without this set, flush for VXLAN device fails: $ bridge fdb flush dev vx10 RTNETLINK answers: Operation not supported
With this set, such flush works with the relevant arguments, for example: $ bridge fdb flush dev vx10 vni 5000 dst 193.2.2.1 < flush all vx10 entries with VNI 5000 and destination IP 193.2.2.1>
Some preparations are required, handle them before adding flushing support in VXLAN driver. See more details in commit messages.
Patch set overview: Patch #1 prepares flush policy to be used by VXLAN driver Patches #2-#3 are preparations in VXLAN driver Patch #4 adds an initial support for flushing in VXLAN driver Patches #5-#9 add support for filtering by several attributes Patch #10 adds a test for FDB flush with VXLAN Patch #11 extends the test to check FDB flush with bridge
Amit Cohen (11): net: Handle bulk delete policy in bridge driver vxlan: vxlan_core: Make vxlan_flush() more generic for future use vxlan: vxlan_core: Do not skip default entry in vxlan_flush() by default vxlan: vxlan_core: Add support for FDB flush vxlan: vxlan_core: Support FDB flushing by source VNI vxlan: vxlan_core: Support FDB flushing by nexthop ID vxlan: vxlan_core: Support FDB flushing by destination VNI vxlan: vxlan_core: Support FDB flushing by destination port vxlan: vxlan_core: Support FDB flushing by destination IP selftests: Add test cases for FDB flush with VXLAN device selftests: fdb_flush: Add test cases for FDB flush with bridge device
drivers/net/vxlan/vxlan_core.c | 207 +++++- include/linux/netdevice.h | 8 +- net/bridge/br_fdb.c | 29 +- net/bridge/br_private.h | 3 +- net/core/rtnetlink.c | 27 +- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/fdb_flush.sh | 812 +++++++++++++++++++++++ 7 files changed, 1049 insertions(+), 38 deletions(-) create mode 100755 tools/testing/selftests/net/fdb_flush.sh
The merge commit 92716869375b ("Merge branch 'br-flush-filtering'") added support for FDB flushing in bridge driver. The following patches will extend VXLAN driver to support FDB flushing as well. The netlink message for bulk delete is shared between the drivers. With the existing implementation, there is no way to prevent user from flushing with attributes that are not supported per driver. For example, when VNI will be added, user will not get an error for flush FDB entries in bridge with VNI, although this attribute is not relevant for bridge.
As preparation for support of FDB flush in VXLAN driver, move the policy to be handled in bridge driver, later a new policy for VXLAN will be added in VXLAN driver. Do not pass 'vid' as part of ndo_fdb_del_bulk(), as this field is relevant only for bridge.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- include/linux/netdevice.h | 8 ++------ net/bridge/br_fdb.c | 29 ++++++++++++++++++++++++----- net/bridge/br_private.h | 3 +-- net/core/rtnetlink.c | 27 ++++++++++----------------- 4 files changed, 37 insertions(+), 30 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e070a4540fba..17b3c0e86bb4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1290,9 +1290,7 @@ struct netdev_net_notifier { * struct net_device *dev, * const unsigned char *addr, u16 vid) * Deletes the FDB entry from dev coresponding to addr. - * int (*ndo_fdb_del_bulk)(struct ndmsg *ndm, struct nlattr *tb[], - * struct net_device *dev, - * u16 vid, + * int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh, struct net_device *dev, * struct netlink_ext_ack *extack); * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, * struct net_device *dev, struct net_device *filter_dev, @@ -1567,10 +1565,8 @@ struct net_device_ops { struct net_device *dev, const unsigned char *addr, u16 vid, struct netlink_ext_ack *extack); - int (*ndo_fdb_del_bulk)(struct ndmsg *ndm, - struct nlattr *tb[], + int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh, struct net_device *dev, - u16 vid, struct netlink_ext_ack *extack); int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index e69a872bfc1d..a98ad763b368 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -661,14 +661,30 @@ static int __fdb_flush_validate_ifindex(const struct net_bridge *br, return 0; }
-int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, u16 vid, +static const struct nla_policy br_fdb_del_bulk_policy[NDA_MAX + 1] = { + [NDA_VLAN] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2), + [NDA_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 1), + [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, + [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, +}; + +int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, struct netlink_ext_ack *extack) { - u8 ndm_flags = ndm->ndm_flags & ~FDB_FLUSH_IGNORED_NDM_FLAGS; - struct net_bridge_fdb_flush_desc desc = { .vlan_id = vid }; + struct net_bridge_fdb_flush_desc desc = {}; + struct ndmsg *ndm = nlmsg_data(nlh); struct net_bridge_port *p = NULL; + struct nlattr *tb[NDA_MAX + 1]; struct net_bridge *br; + u8 ndm_flags; + int err; + + ndm_flags = ndm->ndm_flags & ~FDB_FLUSH_IGNORED_NDM_FLAGS; + + err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, + br_fdb_del_bulk_policy, extack); + if (err) + return err;
if (netif_is_bridge_master(dev)) { br = netdev_priv(dev); @@ -681,6 +697,9 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], br = p->br; }
+ if (tb[NDA_VLAN]) + desc.vlan_id = nla_get_u16(tb[NDA_VLAN]); + if (ndm_flags & ~FDB_FLUSH_ALLOWED_NDM_FLAGS) { NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm flag bits set"); return -EINVAL; @@ -703,7 +722,7 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], desc.flags_mask |= __ndm_flags_to_fdb_flags(ndm_flags_mask); } if (tb[NDA_IFINDEX]) { - int err, ifidx = nla_get_s32(tb[NDA_IFINDEX]); + int ifidx = nla_get_s32(tb[NDA_IFINDEX]);
err = __fdb_flush_validate_ifindex(br, ifidx, extack); if (err) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index a1f4acfa6994..cbbe35278459 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -847,8 +847,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, struct netlink_ext_ack *extack); -int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, u16 vid, +int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, struct netlink_ext_ack *extack); int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, u16 nlh_flags, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7452a6d190c5..eef7f7788996 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -4367,13 +4367,6 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm, } EXPORT_SYMBOL(ndo_dflt_fdb_del);
-static const struct nla_policy fdb_del_bulk_policy[NDA_MAX + 1] = { - [NDA_VLAN] = { .type = NLA_U16 }, - [NDA_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 1), - [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, - [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, -}; - static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { @@ -4394,8 +4387,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack); } else { - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, - fdb_del_bulk_policy, extack); + /* For bulk delete, the drivers will parse the message with + * policy. + */ + err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack); } if (err < 0) return err; @@ -4418,6 +4413,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, return -EINVAL; } addr = nla_data(tb[NDA_LLADDR]); + + err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack); + if (err) + return err; }
if (dev->type != ARPHRD_ETHER) { @@ -4425,10 +4424,6 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, return -EINVAL; }
- err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack); - if (err) - return err; - err = -EOPNOTSUPP;
/* Support fdb on master device the net/bridge default case */ @@ -4442,8 +4437,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid, extack); } else { if (ops->ndo_fdb_del_bulk) - err = ops->ndo_fdb_del_bulk(ndm, tb, dev, vid, - extack); + err = ops->ndo_fdb_del_bulk(nlh, dev, extack); }
if (err) @@ -4464,8 +4458,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, /* in case err was cleared by NTF_MASTER call */ err = -EOPNOTSUPP; if (ops->ndo_fdb_del_bulk) - err = ops->ndo_fdb_del_bulk(ndm, tb, dev, vid, - extack); + err = ops->ndo_fdb_del_bulk(nlh, dev, extack); }
if (!err) {
The function vxlan_flush() gets a boolean called 'do_all' and in case that it is false, it does not flush entries with state 'NUD_PERMANENT' or 'NUD_NOARP'. The following patches will add support for FDB flush with parameters from user space. Make the function more generic, so it can be used later.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 5b5597073b00..1c58fddb7df4 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3022,8 +3022,23 @@ static int vxlan_open(struct net_device *dev) return ret; }
+struct vxlan_fdb_flush_desc { + unsigned long state; + unsigned long state_mask; +}; + +static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, + const struct vxlan_fdb_flush_desc *desc) +{ + if (desc->state_mask && (f->state & desc->state_mask) != desc->state) + return false; + + return true; +} + /* Purge the forwarding table */ -static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) +static void vxlan_flush(struct vxlan_dev *vxlan, + const struct vxlan_fdb_flush_desc *desc) { unsigned int h;
@@ -3034,8 +3049,10 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) { struct vxlan_fdb *f = container_of(p, struct vxlan_fdb, hlist); - if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP))) + + if (!vxlan_fdb_flush_matches(f, desc)) continue; + /* the all_zeros_mac entry is deleted at vxlan_uninit */ if (is_zero_ether_addr(f->eth_addr) && f->vni == vxlan->cfg.vni) @@ -3050,12 +3067,16 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) static int vxlan_stop(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_fdb_flush_desc desc = { + .state = 0, + .state_mask = NUD_PERMANENT | NUD_NOARP, + };
vxlan_multicast_leave(vxlan);
del_timer_sync(&vxlan->age_timer);
- vxlan_flush(vxlan, false); + vxlan_flush(vxlan, &desc); vxlan_sock_release(vxlan);
return 0; @@ -4294,8 +4315,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], static void vxlan_dellink(struct net_device *dev, struct list_head *head) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_fdb_flush_desc desc = {};
- vxlan_flush(vxlan, true); + vxlan_flush(vxlan, &desc);
list_del(&vxlan->next); unregister_netdevice_queue(dev, head);
Currently, the function vxlan_flush() does not flush the default FDB entry (an entry with all_zeros_mac and default VNI), as it is deleted at vxlan_uninit(). When this function will be used for flushing FDB entries from user space, it will have to flush also the default entry in case that other parameters match (e.g., VNI, flags).
Extend 'struct vxlan_fdb_flush_desc' to include an indication whether the default entry should be flushed or not. The default value (false) indicates to flush it, adjust all the existing callers to set '.ignore_default_entry' to true, so the current behavior will not be changed.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 1c58fddb7df4..958960fdc011 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3023,16 +3023,27 @@ static int vxlan_open(struct net_device *dev) }
struct vxlan_fdb_flush_desc { + bool ignore_default_entry; unsigned long state; unsigned long state_mask; };
+static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, + const struct vxlan_dev *vxlan) +{ + return is_zero_ether_addr(f->eth_addr) && f->vni == vxlan->cfg.vni; +} + static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, + const struct vxlan_dev *vxlan, const struct vxlan_fdb_flush_desc *desc) { if (desc->state_mask && (f->state & desc->state_mask) != desc->state) return false;
+ if (desc->ignore_default_entry && vxlan_fdb_is_default_entry(f, vxlan)) + return false; + return true; }
@@ -3050,13 +3061,9 @@ static void vxlan_flush(struct vxlan_dev *vxlan, struct vxlan_fdb *f = container_of(p, struct vxlan_fdb, hlist);
- if (!vxlan_fdb_flush_matches(f, desc)) + if (!vxlan_fdb_flush_matches(f, vxlan, desc)) continue;
- /* the all_zeros_mac entry is deleted at vxlan_uninit */ - if (is_zero_ether_addr(f->eth_addr) && - f->vni == vxlan->cfg.vni) - continue; vxlan_fdb_destroy(vxlan, f, true, true); } spin_unlock_bh(&vxlan->hash_lock[h]); @@ -3068,6 +3075,8 @@ static int vxlan_stop(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_fdb_flush_desc desc = { + /* Default entry is deleted at vxlan_uninit. */ + .ignore_default_entry = true, .state = 0, .state_mask = NUD_PERMANENT | NUD_NOARP, }; @@ -4315,7 +4324,10 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], static void vxlan_dellink(struct net_device *dev, struct list_head *head) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_fdb_flush_desc desc = {}; + struct vxlan_fdb_flush_desc desc = { + /* Default entry is deleted at vxlan_uninit. */ + .ignore_default_entry = true, + };
vxlan_flush(vxlan, &desc);
The merge commit 92716869375b ("Merge branch 'br-flush-filtering'") added support for FDB flushing in bridge driver only, the VXLAN driver does not support such flushing. Extend VXLAN driver to support FDB flushing. In this commit, add support for flushing with state and flags, which are the fields that supported in the bridge driver.
Note that bridge driver supports 'NTF_USE' flag, but there is no point to support this flag for flushing as it is ignored when flags are stored. 'NTF_STICKY' is not relevant for VXLAN driver.
'NTF_ROUTER' is not supported in bridge driver for flush as it is not relevant for bridge, add it for VXLAN.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 958960fdc011..0aeb973e3da7 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3026,6 +3026,8 @@ struct vxlan_fdb_flush_desc { bool ignore_default_entry; unsigned long state; unsigned long state_mask; + unsigned long flags; + unsigned long flags_mask; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3041,6 +3043,9 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, if (desc->state_mask && (f->state & desc->state_mask) != desc->state) return false;
+ if (desc->flags_mask && (f->flags & desc->flags_mask) != desc->flags) + return false; + if (desc->ignore_default_entry && vxlan_fdb_is_default_entry(f, vxlan)) return false;
@@ -3070,6 +3075,56 @@ static void vxlan_flush(struct vxlan_dev *vxlan, } }
+static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { + [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, + [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, +}; + +#define VXLAN_FDB_FLUSH_IGNORED_NDM_FLAGS (NTF_MASTER | NTF_SELF) +#define VXLAN_FDB_FLUSH_ALLOWED_NDM_STATES (NUD_PERMANENT | NUD_NOARP) +#define VXLAN_FDB_FLUSH_ALLOWED_NDM_FLAGS (NTF_EXT_LEARNED | NTF_OFFLOADED | \ + NTF_ROUTER) + +static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, + struct netlink_ext_ack *extack) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_fdb_flush_desc desc = {}; + struct ndmsg *ndm = nlmsg_data(nlh); + struct nlattr *tb[NDA_MAX + 1]; + u8 ndm_flags; + int err; + + ndm_flags = ndm->ndm_flags & ~VXLAN_FDB_FLUSH_IGNORED_NDM_FLAGS; + + err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, vxlan_del_bulk_policy, + extack); + if (err) + return err; + + if (ndm_flags & ~VXLAN_FDB_FLUSH_ALLOWED_NDM_FLAGS) { + NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm flag bits set"); + return -EINVAL; + } + if (ndm->ndm_state & ~VXLAN_FDB_FLUSH_ALLOWED_NDM_STATES) { + NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm state bits set"); + return -EINVAL; + } + + desc.state = ndm->ndm_state; + desc.flags = ndm_flags; + + if (tb[NDA_NDM_STATE_MASK]) + desc.state_mask = nla_get_u16(tb[NDA_NDM_STATE_MASK]); + + if (tb[NDA_NDM_FLAGS_MASK]) + desc.flags_mask = nla_get_u8(tb[NDA_NDM_FLAGS_MASK]); + + vxlan_flush(vxlan, &desc); + + return 0; +} + /* Cleanup timer and forwarding table on shutdown */ static int vxlan_stop(struct net_device *dev) { @@ -3172,6 +3227,7 @@ static const struct net_device_ops vxlan_netdev_ether_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_fdb_add = vxlan_fdb_add, .ndo_fdb_del = vxlan_fdb_delete, + .ndo_fdb_del_bulk = vxlan_fdb_delete_bulk, .ndo_fdb_dump = vxlan_fdb_dump, .ndo_fdb_get = vxlan_fdb_get, .ndo_mdb_add = vxlan_mdb_add,
Add support for flush VXLAN FDB entries by source VNI.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 0aeb973e3da7..8214db56989d 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3028,6 +3028,7 @@ struct vxlan_fdb_flush_desc { unsigned long state_mask; unsigned long flags; unsigned long flags_mask; + __be32 src_vni; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3049,6 +3050,9 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, if (desc->ignore_default_entry && vxlan_fdb_is_default_entry(f, vxlan)) return false;
+ if (desc->src_vni && f->vni != desc->src_vni) + return false; + return true; }
@@ -3076,6 +3080,7 @@ static void vxlan_flush(struct vxlan_dev *vxlan, }
static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { + [NDA_SRC_VNI] = { .type = NLA_U32 }, [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, }; @@ -3120,6 +3125,9 @@ static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, if (tb[NDA_NDM_FLAGS_MASK]) desc.flags_mask = nla_get_u8(tb[NDA_NDM_FLAGS_MASK]);
+ if (tb[NDA_SRC_VNI]) + desc.src_vni = cpu_to_be32(nla_get_u32(tb[NDA_SRC_VNI])); + vxlan_flush(vxlan, &desc);
return 0;
Add support for flush VXLAN FDB entries by nexthop ID.
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 8214db56989d..ec7147409d99 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3029,6 +3029,7 @@ struct vxlan_fdb_flush_desc { unsigned long flags; unsigned long flags_mask; __be32 src_vni; + u32 nhid; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3037,6 +3038,13 @@ static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, return is_zero_ether_addr(f->eth_addr) && f->vni == vxlan->cfg.vni; }
+static bool vxlan_fdb_nhid_matches(const struct vxlan_fdb *f, u32 nhid) +{ + struct nexthop *nh = rtnl_dereference(f->nh); + + return nh && nh->id == nhid; +} + static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, const struct vxlan_dev *vxlan, const struct vxlan_fdb_flush_desc *desc) @@ -3053,6 +3061,9 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, if (desc->src_vni && f->vni != desc->src_vni) return false;
+ if (desc->nhid && !vxlan_fdb_nhid_matches(f, desc->nhid)) + return false; + return true; }
@@ -3081,6 +3092,7 @@ static void vxlan_flush(struct vxlan_dev *vxlan,
static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { [NDA_SRC_VNI] = { .type = NLA_U32 }, + [NDA_NH_ID] = { .type = NLA_U32 }, [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, }; @@ -3128,6 +3140,9 @@ static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, if (tb[NDA_SRC_VNI]) desc.src_vni = cpu_to_be32(nla_get_u32(tb[NDA_SRC_VNI]));
+ if (tb[NDA_NH_ID]) + desc.nhid = nla_get_u32(tb[NDA_NH_ID]); + vxlan_flush(vxlan, &desc);
return 0;
Add support for flush VXLAN FDB entries by destination VNI. FDB entry is stored as {MAC, SRC_VNI} + remote. The destination VNI is an attribute of the remote. For multicast entries, the VXLAN driver stores a linked list of remotes for a given key.
In user space, each remote is represented as a separate entry, so when flush is sent with filter of 'destination VNI', flush only the match remotes. In case that there are no additional remotes, destroy the entry.
For example, the following are stored as one entry with several remotes: $ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.1 vni 3000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 4000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 2000 self permanent 00:00:00:00:00:00 dst 192.1.1.2 vni 2000 self permanent
When user flush by VNI x, only the relevant remotes will be flushed: $ bridge fdb flush dev vx10 vni 2000
$ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.1 vni 3000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 4000 self permanent
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Petr Machata petrm@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index ec7147409d99..f16328a0f9fe 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3030,6 +3030,7 @@ struct vxlan_fdb_flush_desc { unsigned long flags_mask; __be32 src_vni; u32 nhid; + __be32 vni; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3067,10 +3068,46 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, return true; }
+static bool +vxlan_fdb_flush_should_match_remotes(const struct vxlan_fdb_flush_desc *desc) +{ + return !!desc->vni; +} + +static bool +vxlan_fdb_flush_remote_matches(const struct vxlan_fdb_flush_desc *desc, + const struct vxlan_rdst *rd) +{ + if (desc->vni && rd->remote_vni != desc->vni) + return false; + + return true; +} + +static void +vxlan_fdb_flush_match_remotes(struct vxlan_fdb *f, struct vxlan_dev *vxlan, + const struct vxlan_fdb_flush_desc *desc, + bool *p_destroy_fdb) +{ + bool remotes_flushed = false; + struct vxlan_rdst *rd, *tmp; + + list_for_each_entry_safe(rd, tmp, &f->remotes, list) { + if (!vxlan_fdb_flush_remote_matches(desc, rd)) + continue; + + vxlan_fdb_dst_destroy(vxlan, f, rd, true); + remotes_flushed = true; + } + + *p_destroy_fdb = remotes_flushed && list_empty(&f->remotes); +} + /* Purge the forwarding table */ static void vxlan_flush(struct vxlan_dev *vxlan, const struct vxlan_fdb_flush_desc *desc) { + bool match_remotes = vxlan_fdb_flush_should_match_remotes(desc); unsigned int h;
for (h = 0; h < FDB_HASH_SIZE; ++h) { @@ -3084,6 +3121,16 @@ static void vxlan_flush(struct vxlan_dev *vxlan, if (!vxlan_fdb_flush_matches(f, vxlan, desc)) continue;
+ if (match_remotes) { + bool destroy_fdb = false; + + vxlan_fdb_flush_match_remotes(f, vxlan, desc, + &destroy_fdb); + + if (!destroy_fdb) + continue; + } + vxlan_fdb_destroy(vxlan, f, true, true); } spin_unlock_bh(&vxlan->hash_lock[h]); @@ -3093,6 +3140,7 @@ static void vxlan_flush(struct vxlan_dev *vxlan, static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { [NDA_SRC_VNI] = { .type = NLA_U32 }, [NDA_NH_ID] = { .type = NLA_U32 }, + [NDA_VNI] = { .type = NLA_U32 }, [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, }; @@ -3143,6 +3191,9 @@ static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, if (tb[NDA_NH_ID]) desc.nhid = nla_get_u32(tb[NDA_NH_ID]);
+ if (tb[NDA_VNI]) + desc.vni = cpu_to_be32(nla_get_u32(tb[NDA_VNI])); + vxlan_flush(vxlan, &desc);
return 0;
Add support for flush VXLAN FDB entries by destination port. FDB entry is stored as {MAC, SRC_VNI} + remote. The destination port is an attribute of the remote. For multicast entries, the VXLAN driver stores a linked list of remotes for a given key.
In user space, each remote is represented as a separate entry, so when flush is sent with filter of 'destination port', flush only the match remotes. In case that there are no additional remotes, destroy the entry.
For example, the following are stored as one entry with several remotes: $ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.1 port 1111 vni 2000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 port 1111 vni 3000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 port 2222 vni 2000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 3000 self permanent
When user flush by port x, only the relevant remotes will be flushed: $ bridge fdb flush dev vx10 port 1111
$ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.1 port 2222 vni 2000 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 3000 self permanent
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index f16328a0f9fe..1d6efca4ec4a 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3031,6 +3031,7 @@ struct vxlan_fdb_flush_desc { __be32 src_vni; u32 nhid; __be32 vni; + __be16 port; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3071,7 +3072,7 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, static bool vxlan_fdb_flush_should_match_remotes(const struct vxlan_fdb_flush_desc *desc) { - return !!desc->vni; + return desc->vni || desc->port; }
static bool @@ -3081,6 +3082,9 @@ vxlan_fdb_flush_remote_matches(const struct vxlan_fdb_flush_desc *desc, if (desc->vni && rd->remote_vni != desc->vni) return false;
+ if (desc->port && rd->remote_port != desc->port) + return false; + return true; }
@@ -3141,6 +3145,7 @@ static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { [NDA_SRC_VNI] = { .type = NLA_U32 }, [NDA_NH_ID] = { .type = NLA_U32 }, [NDA_VNI] = { .type = NLA_U32 }, + [NDA_PORT] = { .type = NLA_U16 }, [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, }; @@ -3194,6 +3199,9 @@ static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, if (tb[NDA_VNI]) desc.vni = cpu_to_be32(nla_get_u32(tb[NDA_VNI]));
+ if (tb[NDA_PORT]) + desc.port = nla_get_be16(tb[NDA_PORT]); + vxlan_flush(vxlan, &desc);
return 0;
Add support for flush VXLAN FDB entries by destination IP. FDB entry is stored as {MAC, SRC_VNI} + remote. The destination IP is an attribute of the remote. For multicast entries, the VXLAN driver stores a linked list of remotes for a given key.
In user space, each remote is represented as a separate entry, so when flush is sent with filter of 'destination IP', flush only the match remotes. In case that there are no additional remotes, destroy the entry.
For example, the following are stored as one entry with several remotes: $ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.3 self permanent 00:00:00:00:00:00 dst 192.1.1.1 self permanent 00:00:00:00:00:00 dst 192.1.1.2 self permanent 00:00:00:00:00:00 dst 192.1.1.1 vni 1000 self permanent
When user flush by destination IP x, only the relevant remotes will be flushed: $ bridge fdb flush dev vx10 dst 192.1.1.1
$ bridge fdb show dev vx10 00:00:00:00:00:00 dst 192.1.1.3 self permanent 00:00:00:00:00:00 dst 192.1.1.2 self permanent
Signed-off-by: Amit Cohen amcohen@nvidia.com Reviewed-by: Ido Schimmel idosch@nvidia.com --- drivers/net/vxlan/vxlan_core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 1d6efca4ec4a..ece377b1b6bd 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3032,6 +3032,7 @@ struct vxlan_fdb_flush_desc { u32 nhid; __be32 vni; __be16 port; + union vxlan_addr dst_ip; };
static bool vxlan_fdb_is_default_entry(const struct vxlan_fdb *f, @@ -3072,7 +3073,7 @@ static bool vxlan_fdb_flush_matches(const struct vxlan_fdb *f, static bool vxlan_fdb_flush_should_match_remotes(const struct vxlan_fdb_flush_desc *desc) { - return desc->vni || desc->port; + return desc->vni || desc->port || desc->dst_ip.sa.sa_family; }
static bool @@ -3085,6 +3086,10 @@ vxlan_fdb_flush_remote_matches(const struct vxlan_fdb_flush_desc *desc, if (desc->port && rd->remote_port != desc->port) return false;
+ if (desc->dst_ip.sa.sa_family && + !vxlan_addr_equal(&rd->remote_ip, &desc->dst_ip)) + return false; + return true; }
@@ -3146,6 +3151,8 @@ static const struct nla_policy vxlan_del_bulk_policy[NDA_MAX + 1] = { [NDA_NH_ID] = { .type = NLA_U32 }, [NDA_VNI] = { .type = NLA_U32 }, [NDA_PORT] = { .type = NLA_U16 }, + [NDA_DST] = NLA_POLICY_RANGE(NLA_BINARY, sizeof(struct in_addr), + sizeof(struct in6_addr)), [NDA_NDM_STATE_MASK] = { .type = NLA_U16 }, [NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 }, }; @@ -3202,6 +3209,18 @@ static int vxlan_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev, if (tb[NDA_PORT]) desc.port = nla_get_be16(tb[NDA_PORT]);
+ if (tb[NDA_DST]) { + union vxlan_addr ip; + + err = vxlan_nla_get_addr(&ip, tb[NDA_DST]); + if (err) { + NL_SET_ERR_MSG_ATTR(extack, tb[NDA_DST], + "Unsupported address family"); + return err; + } + desc.dst_ip = ip; + } + vxlan_flush(vxlan, &desc);
return 0;
Test all the supported arguments for FDB flush. The test checks configuration, not traffic. Note that the flag 'offloaded' is not checked as it is not relevant when there is no hardware.
Signed-off-by: Amit Cohen amcohen@nvidia.com --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/fdb_flush.sh | 716 +++++++++++++++++++++++ 2 files changed, 717 insertions(+) create mode 100755 tools/testing/selftests/net/fdb_flush.sh
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 8b017070960d..61939a695f95 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -89,6 +89,7 @@ TEST_PROGS += test_vxlan_mdb.sh TEST_PROGS += test_bridge_neigh_suppress.sh TEST_PROGS += test_vxlan_nolocalbypass.sh TEST_PROGS += test_bridge_backup_port.sh +TEST_PROGS += fdb_flush.sh
TEST_FILES := settings
diff --git a/tools/testing/selftests/net/fdb_flush.sh b/tools/testing/selftests/net/fdb_flush.sh new file mode 100755 index 000000000000..3050b031f46d --- /dev/null +++ b/tools/testing/selftests/net/fdb_flush.sh @@ -0,0 +1,716 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# This test is for checking functionality of flushing FDB entries. +# Check that flush works as expected with all the supported arguments and verify +# some combinations of arguments. + +FLUSH_BY_STATE_TESTS=" + vxlan_test_flush_by_permanent + vxlan_test_flush_by_nopermanent + vxlan_test_flush_by_static + vxlan_test_flush_by_nostatic + vxlan_test_flush_by_dynamic + vxlan_test_flush_by_nodynamic +" + +FLUSH_BY_FLAG_TESTS=" + vxlan_test_flush_by_extern_learn + vxlan_test_flush_by_noextern_learn + vxlan_test_flush_by_router + vxlan_test_flush_by_norouter +" + +TESTS=" + vxlan_test_flush_by_dev + vxlan_test_flush_by_vni + vxlan_test_flush_by_src_vni + vxlan_test_flush_by_port + vxlan_test_flush_by_dst_ip + vxlan_test_flush_by_nhid + $FLUSH_BY_STATE_TESTS + $FLUSH_BY_FLAG_TESTS + vxlan_test_flush_by_several_args + vxlan_test_flush_by_remote_attributes +" + +: ${VERBOSE:=0} +: ${PAUSE_ON_FAIL:=no} +: ${PAUSE:=no} +: ${VXPORT:=4789} + +run_cmd() +{ + local cmd="$1" + local out + local rc + local stderr="2>/dev/null" + + if [ "$VERBOSE" = "1" ]; then + printf "COMMAND: $cmd\n" + stderr= + fi + + out=$(eval $cmd $stderr) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + + return $rc +} + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + local nsuccess + local nfail + local ret + + if [ ${rc} -eq ${expected} ]; then + printf "TEST: %-60s [ OK ]\n" "${msg}" + nsuccess=$((nsuccess+1)) + else + ret=1 + nfail=$((nfail+1)) + printf "TEST: %-60s [FAIL]\n" "${msg}" + if [ "$VERBOSE" = "1" ]; then + echo " rc=$rc, expected $expected" + fi + + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi + + if [ "${PAUSE}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + + [ "$VERBOSE" = "1" ] && echo +} + +MAC_POOL_1=" + de:ad:be:ef:13:10 + de:ad:be:ef:13:11 + de:ad:be:ef:13:12 + de:ad:be:ef:13:13 + de:ad:be:ef:13:14 +" +mac_pool_1_len=$(echo "$MAC_POOL_1" | grep -c .) + +MAC_POOL_2=" + ca:fe:be:ef:13:10 + ca:fe:be:ef:13:11 + ca:fe:be:ef:13:12 + ca:fe:be:ef:13:13 + ca:fe:be:ef:13:14 +" +mac_pool_2_len=$(echo "$MAC_POOL_2" | grep -c .) + +fdb_add_mac_pool_1() +{ + local dev=$1; shift + local args="$@" + + for mac in $MAC_POOL_1 + do + $BRIDGE fdb add $mac dev $dev $args + done +} + +fdb_add_mac_pool_2() +{ + local dev=$1; shift + local args="$@" + + for mac in $MAC_POOL_2 + do + $BRIDGE fdb add $mac dev $dev $args + done +} + +fdb_check_n_entries_by_dev_filter() +{ + local dev=$1; shift + local exp_entries=$1; shift + local filter="$@" + + local entries=$($BRIDGE fdb show dev $dev | grep "$filter" | wc -l) + + [[ $entries -eq $exp_entries ]] + rc=$? + + log_test $rc 0 "$dev: Expected $exp_entries FDB entries, got $entries" + return $rc +} + +vxlan_test_flush_by_dev() +{ + local vni=3000 + local dst_ip=192.0.2.1 + + fdb_add_mac_pool_1 vx10 vni $vni dst $dst_ip + fdb_add_mac_pool_2 vx20 vni $vni dst $dst_ip + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len + fdb_check_n_entries_by_dev_filter vx20 $mac_pool_2_len + + run_cmd "$BRIDGE fdb flush dev vx10" + log_test $? 0 "Flush FDB by dev vx10" + + fdb_check_n_entries_by_dev_filter vx10 0 + log_test $? 0 "Flush FDB by dev vx10 - test vx10 entries" + + fdb_check_n_entries_by_dev_filter vx20 $mac_pool_2_len + log_test $? 0 "Flush FDB by dev vx10 - test vx20 entries" +} + +vxlan_test_flush_by_vni() +{ + local vni_1=3000 + local vni_2=4000 + local dst_ip=192.0.2.1 + + fdb_add_mac_pool_1 vx10 vni $vni_1 dst $dst_ip + fdb_add_mac_pool_2 vx10 vni $vni_2 dst $dst_ip + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len vni $vni_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len vni $vni_2 + + run_cmd "$BRIDGE fdb flush dev vx10 vni $vni_2" + log_test $? 0 "Flush FDB by dev vx10 and vni $vni_2" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len vni $vni_1 + log_test $? 0 "Test entries with vni $vni_1" + + fdb_check_n_entries_by_dev_filter vx10 0 vni $vni_2 + log_test $? 0 "Test entries with vni $vni_2" +} + +vxlan_test_flush_by_src_vni() +{ + # Set some entries with {vni=x,src_vni=y} and some with the opposite - + # {vni=y,src_vni=x}, to verify that when we flush by src_vni=x, entries + # with vni=x are not flused. + local vni_1=3000 + local vni_2=4000 + local src_vni_1=4000 + local src_vni_2=3000 + local dst_ip=192.0.2.1 + + # Reconfigure vx10 with 'external' to get 'src_vni' details in + # 'bridge fdb' output + $IP link del dev vx10 + $IP link add name vx10 type vxlan dstport "$VXPORT" external + + fdb_add_mac_pool_1 vx10 vni $vni_1 src_vni $src_vni_1 dst $dst_ip + fdb_add_mac_pool_2 vx10 vni $vni_2 src_vni $src_vni_2 dst $dst_ip + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len \ + src_vni $src_vni_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len \ + src_vni $src_vni_2 + + run_cmd "$BRIDGE fdb flush dev vx10 src_vni $src_vni_2" + log_test $? 0 "Flush FDB by dev vx10 and src_vni $src_vni_2" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len \ + src_vni $src_vni_1 + log_test $? 0 "Test entries with src_vni $src_vni_1" + + fdb_check_n_entries_by_dev_filter vx10 0 src_vni $src_vni_2 + log_test $? 0 "Test entries with src_vni $src_vni_2" +} + +vxlan_test_flush_by_port() +{ + local port_1=1234 + local port_2=4321 + local dst_ip=192.0.2.1 + + fdb_add_mac_pool_1 vx10 port $port_1 dst $dst_ip + fdb_add_mac_pool_2 vx10 port $port_2 dst $dst_ip + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len port $port_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len port $port_2 + + run_cmd "$BRIDGE fdb flush dev vx10 port $port_2" + log_test $? 0 "Flush FDB by dev vx10 and port $port_2" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len port $port_1 + log_test $? 0 "Test entries with port $port_1" + + fdb_check_n_entries_by_dev_filter vx10 0 port $port_2 + log_test $? 0 "Test entries with port $port_2" +} + +vxlan_test_flush_by_dst_ip() +{ + local dst_ip_1=192.0.2.1 + local dst_ip_2=192.0.2.2 + + fdb_add_mac_pool_1 vx10 dst $dst_ip_1 + fdb_add_mac_pool_2 vx10 dst $dst_ip_2 + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len dst $dst_ip_2 + + run_cmd "$BRIDGE fdb flush dev vx10 dst $dst_ip_2" + log_test $? 0 "Flush FDB by dev vx10 and dst $dst_ip_2" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip_1 + log_test $? 0 "Test entries with dst $dst_ip_1" + + fdb_check_n_entries_by_dev_filter vx10 0 dst $dst_ip_2 + log_test $? 0 "Test entries with dst $dst_ip_2" +} + +nexthops_add() +{ + local nhid_1=$1; shift + local nhid_2=$1; shift + + $IP nexthop add id 10 via 192.0.2.1 fdb + $IP nexthop add id $nhid_1 group 10 fdb + + $IP nexthop add id 20 via 192.0.2.2 fdb + $IP nexthop add id $nhid_2 group 20 fdb +} + +vxlan_test_flush_by_nhid() +{ + local nhid_1=100 + local nhid_2=200 + + nexthops_add $nhid_1 $nhid_2 + + fdb_add_mac_pool_1 vx10 nhid $nhid_1 + fdb_add_mac_pool_2 vx10 nhid $nhid_2 + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len nhid $nhid_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len nhid $nhid_2 + + run_cmd "$BRIDGE fdb flush dev vx10 nhid $nhid_2" + log_test $? 0 "Flush FDB by dev vx10 and nhid $nhid_2" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len nhid $nhid_1 + log_test $? 0 "Test entries with nhid $nhid_1" + + fdb_check_n_entries_by_dev_filter vx10 0 nhid $nhid_2 + log_test $? 0 "Test entries with nhid $nhid_2" + + # Flush also entries with $nhid_1, and then verify that flushing by + # 'nhid' does not return an error when there are no entries with + # nexthops. + run_cmd "$BRIDGE fdb flush dev vx10 nhid $nhid_1" + log_test $? 0 "Flush FDB by dev vx10 and nhid $nhid_1" + + fdb_check_n_entries_by_dev_filter vx10 0 nhid + log_test $? 0 "Test entries with 'nhid' keyword" + + run_cmd "$BRIDGE fdb flush dev vx10 nhid $nhid_1" + log_test $? 0 "Flush FDB by nhid when there are no entries with nexthop" +} + +vxlan_test_flush_by_state() +{ + local flush_by_state=$1; shift + local state_1=$1; shift + local exp_state_1=$1; shift + local state_2=$1; shift + local exp_state_2=$1; shift + + local dst_ip_1=192.0.2.1 + local dst_ip_2=192.0.2.2 + + fdb_add_mac_pool_1 vx10 dst $dst_ip_1 $state_1 + fdb_add_mac_pool_2 vx10 dst $dst_ip_2 $state_2 + + # Check the entries by dst_ip as not all states appear in 'bridge fdb' + # output. + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len dst $dst_ip_2 + + run_cmd "$BRIDGE fdb flush dev vx10 $flush_by_state" + log_test $? 0 "Flush FDB by dev vx10 and state $flush_by_state" + + fdb_check_n_entries_by_dev_filter vx10 $exp_state_1 dst $dst_ip_1 + log_test $? 0 "Test entries with state $state_1" + + fdb_check_n_entries_by_dev_filter vx10 $exp_state_2 dst $dst_ip_2 + log_test $? 0 "Test entries with state $state_2" +} + +vxlan_test_flush_by_permanent() +{ + # Entries that are added without state get 'permanent' state by + # default, add some entries with flag 'extern_learn' instead of state, + # so they will be added with 'permanent' and should be flushed also. + local flush_by_state="permanent" + local state_1="permanent" + local exp_state_1=0 + local state_2="extern_learn" + local exp_state_2=0 + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_nopermanent() +{ + local flush_by_state="nopermanent" + local state_1="permanent" + local exp_state_1=$mac_pool_1_len + local state_2="static" + local exp_state_2=0 + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_static() +{ + local flush_by_state="static" + local state_1="static" + local exp_state_1=0 + local state_2="dynamic" + local exp_state_2=$mac_pool_2_len + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_nostatic() +{ + local flush_by_state="nostatic" + local state_1="permanent" + local exp_state_1=$mac_pool_1_len + local state_2="dynamic" + local exp_state_2=0 + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_dynamic() +{ + local flush_by_state="dynamic" + local state_1="dynamic" + local exp_state_1=0 + local state_2="static" + local exp_state_2=$mac_pool_2_len + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_nodynamic() +{ + local flush_by_state="nodynamic" + local state_1="permanent" + local exp_state_1=0 + local state_2="dynamic" + local exp_state_2=$mac_pool_2_len + + vxlan_test_flush_by_state $flush_by_state $state_1 $exp_state_1 \ + $state_2 $exp_state_2 +} + +vxlan_test_flush_by_flag() +{ + local flush_by_flag=$1; shift + local flag_1=$1; shift + local exp_flag_1=$1; shift + local flag_2=$1; shift + local exp_flag_2=$1; shift + + local dst_ip_1=192.0.2.1 + local dst_ip_2=192.0.2.2 + + fdb_add_mac_pool_1 vx10 dst $dst_ip_1 $flag_1 + fdb_add_mac_pool_2 vx10 dst $dst_ip_2 $flag_2 + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len $flag_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len $flag_2 + + run_cmd "$BRIDGE fdb flush dev vx10 $flush_by_flag" + log_test $? 0 "Flush FDB by dev vx10 and flag $flush_by_flag" + + fdb_check_n_entries_by_dev_filter vx10 $exp_flag_1 dst $dst_ip_1 + log_test $? 0 "Test entries with flag $flag_1" + + fdb_check_n_entries_by_dev_filter vx10 $exp_flag_2 dst $dst_ip_2 + log_test $? 0 "Test entries with flag $flag_2" +} + +vxlan_test_flush_by_extern_learn() +{ + local flush_by_flag="extern_learn" + local flag_1="extern_learn" + local exp_flag_1=0 + local flag_2="router" + local exp_flag_2=$mac_pool_2_len + + vxlan_test_flush_by_flag $flush_by_flag $flag_1 $exp_flag_1 \ + $flag_2 $exp_flag_2 +} + +vxlan_test_flush_by_noextern_learn() +{ + local flush_by_flag="noextern_learn" + local flag_1="extern_learn" + local exp_flag_1=$mac_pool_1_len + local flag_2="router" + local exp_flag_2=0 + + vxlan_test_flush_by_flag $flush_by_flag $flag_1 $exp_flag_1 \ + $flag_2 $exp_flag_2 +} + +vxlan_test_flush_by_router() +{ + local flush_by_flag="router" + local flag_1="router" + local exp_flag_1=0 + local flag_2="extern_learn" + local exp_flag_2=$mac_pool_2_len + + vxlan_test_flush_by_flag $flush_by_flag $flag_1 $exp_flag_1 \ + $flag_2 $exp_flag_2 +} + +vxlan_test_flush_by_norouter() +{ + + local flush_by_flag="norouter" + local flag_1="router" + local exp_flag_1=$mac_pool_1_len + local flag_2="extern_learn" + local exp_flag_2=0 + + vxlan_test_flush_by_flag $flush_by_flag $flag_1 $exp_flag_1 \ + $flag_2 $exp_flag_2 +} + +vxlan_test_flush_by_several_args() +{ + local dst_ip_1=192.0.2.1 + local dst_ip_2=192.0.2.2 + local state_1=permanent + local state_2=static + local vni=3000 + local port=1234 + local nhid=100 + local flag=router + local flush_args + + ################### Flush by 2 args - nhid and flag #################### + $IP nexthop add id 10 via 192.0.2.1 fdb + $IP nexthop add id $nhid group 10 fdb + + fdb_add_mac_pool_1 vx10 nhid $nhid $flag $state_1 + fdb_add_mac_pool_2 vx10 nhid $nhid $flag $state_2 + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len $state_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len $state_2 + + run_cmd "$BRIDGE fdb flush dev vx10 nhid $nhid $flag" + log_test $? 0 "Flush FDB by dev vx10 nhid $nhid $flag" + + # All entries should be flushed as 'state' is not an argument for flush + # filtering. + fdb_check_n_entries_by_dev_filter vx10 0 $state_1 + log_test $? 0 "Test entries with state $state_1" + + fdb_check_n_entries_by_dev_filter vx10 0 $state_2 + log_test $? 0 "Test entries with state $state_2" + + ################ Flush by 3 args - VNI, port and dst_ip ################ + fdb_add_mac_pool_1 vx10 vni $vni port $port dst $dst_ip_1 + fdb_add_mac_pool_2 vx10 vni $vni port $port dst $dst_ip_2 + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_2_len dst $dst_ip_2 + + flush_args="vni $vni port $port dst $dst_ip_2" + run_cmd "$BRIDGE fdb flush dev vx10 $flush_args" + log_test $? 0 "Flush FDB by dev vx10 $flush_args" + + # Only entries with $dst_ip_2 should be flushed, even the rest arguments + # match the filter, the flush should be AND of all the arguments. + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip_1 + log_test $? 0 "Test entries with dst $dst_ip_1" + + fdb_check_n_entries_by_dev_filter vx10 0 dst $dst_ip_2 + log_test $? 0 "Test entries with dst $dst_ip_2" +} + +multicast_fdb_entries_add() +{ + mac=00:00:00:00:00:00 + vnis=(2000 3000) + + for vni in "${vnis[@]}"; do + $BRIDGE fdb append $mac dev vx10 dst 192.0.2.1 vni $vni \ + src_vni 5000 + $BRIDGE fdb append $mac dev vx10 dst 192.0.2.1 vni $vni \ + port 1111 + $BRIDGE fdb append $mac dev vx10 dst 192.0.2.2 vni $vni \ + port 2222 + done +} + +vxlan_test_flush_by_remote_attributes() +{ + local flush_args + + # Reconfigure vx10 with 'external' to get 'src_vni' details in + # 'bridge fdb' output + $IP link del dev vx10 + $IP link add name vx10 type vxlan dstport "$VXPORT" external + + # For multicat FDB entries, the VXLAN driver stores a linked list of + # remotes for a given key. Verify that only the expected remotes are + # flushed. + multicast_fdb_entries_add + + ## Flush by 3 remote's attributes - destination IP, port and VNI ## + flush_args="dst 192.0.2.1 port 1111 vni 2000" + fdb_check_n_entries_by_dev_filter vx10 1 $flush_args + + t0_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + run_cmd "$BRIDGE fdb flush dev vx10 $flush_args" + log_test $? 0 "Flush FDB by dev vx10 $flush_args" + + fdb_check_n_entries_by_dev_filter vx10 0 $flush_args + + exp_n_entries=$((t0_n_entries - 1)) + t1_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + [[ $t1_n_entries -eq $exp_n_entries ]] + log_test $? 0 "Check how many entries were flushed" + + ## Flush by 2 remote's attributes - destination IP and port ## + flush_args="dst 192.0.2.2 port 2222" + + fdb_check_n_entries_by_dev_filter vx10 2 $flush_args + + t0_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + run_cmd "$BRIDGE fdb flush dev vx10 $flush_args" + log_test $? 0 "Flush FDB by dev vx10 $flush_args" + + fdb_check_n_entries_by_dev_filter vx10 0 $flush_args + + exp_n_entries=$((t0_n_entries - 2)) + t1_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + [[ $t1_n_entries -eq $exp_n_entries ]] + log_test $? 0 "Check how many entries were flushed" + + ## Flush by source VNI, which is not remote's attribute and VNI ## + flush_args="vni 3000 src_vni 5000" + + fdb_check_n_entries_by_dev_filter vx10 1 $flush_args + + t0_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + run_cmd "$BRIDGE fdb flush dev vx10 $flush_args" + log_test $? 0 "Flush FDB by dev vx10 $flush_args" + + fdb_check_n_entries_by_dev_filter vx10 0 $flush_args + + exp_n_entries=$((t0_n_entries -1)) + t1_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + [[ $t1_n_entries -eq $exp_n_entries ]] + log_test $? 0 "Check how many entries were flushed" + + # Flush by 1 remote's attribute - destination IP ## + flush_args="dst 192.0.2.1" + + fdb_check_n_entries_by_dev_filter vx10 2 $flush_args + + t0_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + run_cmd "$BRIDGE fdb flush dev vx10 $flush_args" + log_test $? 0 "Flush FDB by dev vx10 $flush_args" + + fdb_check_n_entries_by_dev_filter vx10 0 $flush_args + + exp_n_entries=$((t0_n_entries -2)) + t1_n_entries=$($BRIDGE fdb show dev vx10 | wc -l) + [[ $t1_n_entries -eq $exp_n_entries ]] + log_test $? 0 "Check how many entries were flushed" +} + +setup() +{ + IP="ip -netns ns1" + BRIDGE="bridge -netns ns1" + + ip netns add ns1 + + $IP link add name vx10 type vxlan id 1000 dstport "$VXPORT" + $IP link add name vx20 type vxlan id 2000 dstport "$VXPORT" +} + +cleanup() +{ + $IP link del dev vx20 + $IP link del dev vx10 + + ip netns del ns1 +} + +################################################################################ +# main + +while getopts :t:pPhvw: o +do + case $o in + t) TESTS=$OPTARG;; + p) PAUSE_ON_FAIL=yes;; + P) PAUSE=yes;; + v) VERBOSE=$(($VERBOSE + 1));; + w) PING_TIMEOUT=$OPTARG;; + h) usage; exit 0;; + *) usage; exit 1;; + esac +done + +# make sure we don't pause twice +[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no + +if [ "$(id -u)" -ne 0 ];then + echo "SKIP: Need root privileges" + exit $ksft_skip; +fi + +if [ ! -x "$(command -v ip)" ]; then + echo "SKIP: Could not run test without ip tool" + exit $ksft_skip +fi + +# Check a flag that is added to flush command as part of VXLAN flush support +bridge fdb help 2>&1 | grep -q "[no]router" +if [ $? -ne 0 ]; then + echo "SKIP: iproute2 too old, missing flush command for VXLAN" + exit $ksft_skip +fi + +ip link add dev vx10 type vxlan id 1000 2> /dev/null +out=$(bridge fdb flush dev vx10 2>&1 | grep -q "Operation not supported") +if [ $? -eq 0 ]; then + echo "SKIP: kernel lacks vxlan flush support" + exit $ksft_skip +fi +ip link del dev vx10 + +for t in $TESTS +do + setup; $t; cleanup; +done
Extend the test to check flushing with bridge device, test flush by device and by VID.
Add test case for flushing with "self" and "master" and attributes that are supported only in one driver, this is unrecommended configuration, check it to verify that user gets an error.
Signed-off-by: Amit Cohen amcohen@nvidia.com --- tools/testing/selftests/net/fdb_flush.sh | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+)
diff --git a/tools/testing/selftests/net/fdb_flush.sh b/tools/testing/selftests/net/fdb_flush.sh index 3050b031f46d..90e7a29e0476 100755 --- a/tools/testing/selftests/net/fdb_flush.sh +++ b/tools/testing/selftests/net/fdb_flush.sh @@ -32,6 +32,9 @@ TESTS=" $FLUSH_BY_FLAG_TESTS vxlan_test_flush_by_several_args vxlan_test_flush_by_remote_attributes + bridge_test_flush_by_dev + bridge_test_flush_by_vlan + bridge_vxlan_test_flush "
: ${VERBOSE:=0} @@ -647,6 +650,93 @@ vxlan_test_flush_by_remote_attributes() log_test $? 0 "Check how many entries were flushed" }
+bridge_test_flush_by_dev() +{ + local dst_ip=192.0.2.1 + local br0_n_ent_t0=$($BRIDGE fdb show dev br0 | wc -l) + local br1_n_ent_t0=$($BRIDGE fdb show dev br1 | wc -l) + + fdb_add_mac_pool_1 br0 dst $dst_ip + fdb_add_mac_pool_2 br1 dst $dst_ip + + # Each 'fdb add' command adds one extra entry in the bridge with the + # default vlan. + local exp_br0_n_ent=$(($br0_n_ent_t0 + 2 * $mac_pool_1_len)) + local exp_br1_n_ent=$(($br1_n_ent_t0 + 2 * $mac_pool_2_len)) + + fdb_check_n_entries_by_dev_filter br0 $exp_br0_n_ent + fdb_check_n_entries_by_dev_filter br1 $exp_br1_n_ent + + run_cmd "$BRIDGE fdb flush dev br0" + log_test $? 0 "Flush FDB by dev br0" + + # The default entry should not be flushed + fdb_check_n_entries_by_dev_filter br0 1 + log_test $? 0 "Flush FDB by dev br0 - test br0 entries" + + fdb_check_n_entries_by_dev_filter br1 $exp_br1_n_ent + log_test $? 0 "Flush FDB by dev br0 - test br1 entries" +} + +bridge_test_flush_by_vlan() +{ + local vlan_1=10 + local vlan_2=20 + local vlan_1_ent_t0 + local vlan_2_ent_t0 + + $BRIDGE vlan add vid $vlan_1 dev br0 self + $BRIDGE vlan add vid $vlan_2 dev br0 self + + vlan_1_ent_t0=$($BRIDGE fdb show dev br0 | grep "vlan $vlan_1" | wc -l) + vlan_2_ent_t0=$($BRIDGE fdb show dev br0 | grep "vlan $vlan_2" | wc -l) + + fdb_add_mac_pool_1 br0 vlan $vlan_1 + fdb_add_mac_pool_2 br0 vlan $vlan_2 + + local exp_vlan_1_ent=$(($vlan_1_ent_t0 + $mac_pool_1_len)) + local exp_vlan_2_ent=$(($vlan_2_ent_t0 + $mac_pool_2_len)) + + fdb_check_n_entries_by_dev_filter br0 $exp_vlan_1_ent vlan $vlan_1 + fdb_check_n_entries_by_dev_filter br0 $exp_vlan_2_ent vlan $vlan_2 + + run_cmd "$BRIDGE fdb flush dev br0 vlan $vlan_1" + log_test $? 0 "Flush FDB by dev br0 and vlan $vlan_1" + + fdb_check_n_entries_by_dev_filter br0 0 vlan $vlan_1 + log_test $? 0 "Test entries with vlan $vlan_1" + + fdb_check_n_entries_by_dev_filter br0 $exp_vlan_2_ent vlan $vlan_2 + log_test $? 0 "Test entries with vlan $vlan_2" +} + +bridge_vxlan_test_flush() +{ + local vlan_1=10 + local dst_ip=192.0.2.1 + + $IP link set dev vx10 master br0 + $BRIDGE vlan add vid $vlan_1 dev br0 self + $BRIDGE vlan add vid $vlan_1 dev vx10 + + fdb_add_mac_pool_1 vx10 vni 3000 dst $dst_ip self master + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len vlan $vlan_1 + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len vni 3000 + + # Such command should fail in VXLAN driver as vlan is not supported, + # but the command should flush the entries in the bridge + run_cmd "$BRIDGE fdb flush dev vx10 vlan $vlan_1 master self" + log_test $? 255 \ + "Flush FDB by dev vx10, vlan $vlan_1, master and self" + + fdb_check_n_entries_by_dev_filter vx10 0 vlan $vlan_1 + log_test $? 0 "Test entries with vlan $vlan_1" + + fdb_check_n_entries_by_dev_filter vx10 $mac_pool_1_len dst $dst_ip + log_test $? 0 "Test entries with dst $dst_ip" +} + setup() { IP="ip -netns ns1" @@ -656,10 +746,16 @@ setup()
$IP link add name vx10 type vxlan id 1000 dstport "$VXPORT" $IP link add name vx20 type vxlan id 2000 dstport "$VXPORT" + + $IP link add br0 type bridge vlan_filtering 1 + $IP link add br1 type bridge vlan_filtering 1 }
cleanup() { + $IP link del dev br1 + $IP link del dev br0 + $IP link del dev vx20 $IP link del dev vx10
On 10/9/23 13:06, Amit Cohen wrote:
The merge commit 92716869375b ("Merge branch 'br-flush-filtering'") added support for FDB flushing in bridge driver. Extend VXLAN driver to support FDB flushing also. Add support for filtering by fields which are relevant for VXLAN FDBs:
- Source VNI
- Nexthop ID
- 'router' flag
- Destination VNI
- Destination Port
- Destination IP
Without this set, flush for VXLAN device fails: $ bridge fdb flush dev vx10 RTNETLINK answers: Operation not supported
With this set, such flush works with the relevant arguments, for example: $ bridge fdb flush dev vx10 vni 5000 dst 193.2.2.1 < flush all vx10 entries with VNI 5000 and destination IP 193.2.2.1>
Some preparations are required, handle them before adding flushing support in VXLAN driver. See more details in commit messages.
Patch set overview: Patch #1 prepares flush policy to be used by VXLAN driver Patches #2-#3 are preparations in VXLAN driver Patch #4 adds an initial support for flushing in VXLAN driver Patches #5-#9 add support for filtering by several attributes Patch #10 adds a test for FDB flush with VXLAN Patch #11 extends the test to check FDB flush with bridge
Amit Cohen (11): net: Handle bulk delete policy in bridge driver vxlan: vxlan_core: Make vxlan_flush() more generic for future use vxlan: vxlan_core: Do not skip default entry in vxlan_flush() by default vxlan: vxlan_core: Add support for FDB flush vxlan: vxlan_core: Support FDB flushing by source VNI vxlan: vxlan_core: Support FDB flushing by nexthop ID vxlan: vxlan_core: Support FDB flushing by destination VNI vxlan: vxlan_core: Support FDB flushing by destination port vxlan: vxlan_core: Support FDB flushing by destination IP selftests: Add test cases for FDB flush with VXLAN device selftests: fdb_flush: Add test cases for FDB flush with bridge device
drivers/net/vxlan/vxlan_core.c | 207 +++++- include/linux/netdevice.h | 8 +- net/bridge/br_fdb.c | 29 +- net/bridge/br_private.h | 3 +- net/core/rtnetlink.c | 27 +- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/fdb_flush.sh | 812 +++++++++++++++++++++++ 7 files changed, 1049 insertions(+), 38 deletions(-) create mode 100755 tools/testing/selftests/net/fdb_flush.sh
Nice use of the flush api. :) The set looks good to me. For the set: Acked-by: Nikolay Aleksandrov razor@blackwall.org
Hello:
This series was applied to netdev/net-next.git (main) by David S. Miller davem@davemloft.net:
On Mon, 9 Oct 2023 13:06:07 +0300 you wrote:
The merge commit 92716869375b ("Merge branch 'br-flush-filtering'") added support for FDB flushing in bridge driver. Extend VXLAN driver to support FDB flushing also. Add support for filtering by fields which are relevant for VXLAN FDBs:
- Source VNI
- Nexthop ID
- 'router' flag
- Destination VNI
- Destination Port
- Destination IP
[...]
Here is the summary with links: - [net-next,01/11] net: Handle bulk delete policy in bridge driver https://git.kernel.org/netdev/net-next/c/38985e8c278b - [net-next,02/11] vxlan: vxlan_core: Make vxlan_flush() more generic for future use https://git.kernel.org/netdev/net-next/c/bfe36bf7811c - [net-next,03/11] vxlan: vxlan_core: Do not skip default entry in vxlan_flush() by default https://git.kernel.org/netdev/net-next/c/77b613efcc81 - [net-next,04/11] vxlan: vxlan_core: Add support for FDB flush https://git.kernel.org/netdev/net-next/c/d324eb9cec84 - [net-next,05/11] vxlan: vxlan_core: Support FDB flushing by source VNI https://git.kernel.org/netdev/net-next/c/a0f89d5e68b6 - [net-next,06/11] vxlan: vxlan_core: Support FDB flushing by nexthop ID https://git.kernel.org/netdev/net-next/c/36c111233b56 - [net-next,07/11] vxlan: vxlan_core: Support FDB flushing by destination VNI https://git.kernel.org/netdev/net-next/c/c499fccb71cb - [net-next,08/11] vxlan: vxlan_core: Support FDB flushing by destination port https://git.kernel.org/netdev/net-next/c/ac0db4ddd0cb - [net-next,09/11] vxlan: vxlan_core: Support FDB flushing by destination IP https://git.kernel.org/netdev/net-next/c/2dcd22023cab - [net-next,10/11] selftests: Add test cases for FDB flush with VXLAN device https://git.kernel.org/netdev/net-next/c/96eece693330 - [net-next,11/11] selftests: fdb_flush: Add test cases for FDB flush with bridge device https://git.kernel.org/netdev/net-next/c/f826f2a2ee1e
You are awesome, thank you!
linux-kselftest-mirror@lists.linaro.org