OSDN Git Service

vxlan: Add vxlan_fdb_replay()
authorPetr Machata <petrm@mellanox.com>
Fri, 7 Dec 2018 19:55:04 +0000 (19:55 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Dec 2018 20:59:08 +0000 (12:59 -0800)
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 <petrm@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/vxlan.c
include/net/vxlan.h

index d3db031..d9cb0d9 100644 (file)
@@ -552,6 +552,53 @@ out:
 }
 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;
+
+       vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, &fdb_info);
+       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,
index b73c670..f49aa9a 100644 (file)
@@ -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