From: Petr Machata <pe...@mellanox.com>

When a VXLAN device becomes relevant to a driver (such as when it is
attached to an offloaded bridge), the driver will generally need to walk
the existing FDB entries and offload them.

Add a function vxlan_fdb_replay() to call a given notifier block for
each FDB entry with a given VNI.

Signed-off-by: Petr Machata <pe...@mellanox.com>
Signed-off-by: Ido Schimmel <ido...@mellanox.com>
---
 drivers/net/vxlan.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 include/net/vxlan.h |  9 +++++++++
 2 files changed, 56 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index fe5cd22e4b4d..3e44a358f7ea 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -556,6 +556,53 @@ int vxlan_fdb_find_uc(struct net_device *dev, const u8 
*mac, __be32 vni,
 }
 EXPORT_SYMBOL_GPL(vxlan_fdb_find_uc);
 
+static int vxlan_fdb_notify_one(struct notifier_block *nb,
+                               const struct vxlan_dev *vxlan,
+                               const struct vxlan_fdb *f,
+                               const struct vxlan_rdst *rdst)
+{
+       struct switchdev_notifier_vxlan_fdb_info fdb_info;
+       int rc;
+
+       fdb_info = vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst);
+       rc = nb->notifier_call(nb, SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE,
+                              &fdb_info);
+       return notifier_to_errno(rc);
+}
+
+int vxlan_fdb_replay(const struct net_device *dev, __be32 vni,
+                    struct notifier_block *nb)
+{
+       struct vxlan_dev *vxlan;
+       struct vxlan_rdst *rdst;
+       struct vxlan_fdb *f;
+       unsigned int h;
+       int rc = 0;
+
+       if (!netif_is_vxlan(dev))
+               return -EINVAL;
+       vxlan = netdev_priv(dev);
+
+       spin_lock_bh(&vxlan->hash_lock);
+       for (h = 0; h < FDB_HASH_SIZE; ++h) {
+               hlist_for_each_entry(f, &vxlan->fdb_head[h], hlist) {
+                       if (f->vni == vni) {
+                               list_for_each_entry(rdst, &f->remotes, list) {
+                                       rc = vxlan_fdb_notify_one(nb, vxlan,
+                                                                 f, rdst);
+                                       if (rc)
+                                               goto out;
+                               }
+                       }
+               }
+       }
+
+out:
+       spin_unlock_bh(&vxlan->hash_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(vxlan_fdb_replay);
+
 /* Replace destination of unicast mac */
 static int vxlan_fdb_replace(struct vxlan_fdb *f,
                             union vxlan_addr *ip, __be16 port, __be32 vni,
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index b73c670df184..f49aa9afe598 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -427,6 +427,9 @@ struct switchdev_notifier_vxlan_fdb_info {
 #if IS_ENABLED(CONFIG_VXLAN)
 int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni,
                      struct switchdev_notifier_vxlan_fdb_info *fdb_info);
+int vxlan_fdb_replay(const struct net_device *dev, __be32 vni,
+                    struct notifier_block *nb);
+
 #else
 static inline int
 vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni,
@@ -434,6 +437,12 @@ vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, 
__be32 vni,
 {
        return -ENOENT;
 }
+
+static inline int vxlan_fdb_replay(const struct net_device *dev, __be32 vni,
+                                  struct notifier_block *nb)
+{
+       return -EOPNOTSUPP;
+}
 #endif
 
 #endif
-- 
2.19.1

Reply via email to