vxlan fdb can have NDA_IFINDEX, which indicates an out interface.
If the interface is removed, that fdb will not work.
So, when interface is removed, vxlan's fdb can be removed.

Test commands:
    ip link add dummy0 type dummy
    ip link add vxlan0 type vxlan vni 1000
    bridge fdb add 11:22:33:44:55:66 dst 1.1.1.1 dev vxlan0 via dummy0 self
    ip link del dummy0

Before this patch, fdbs will not be removed.
Result:
    bridge fdb show dev vxlan0
11:22:33:44:55:66 dst 1.1.1.1 via if10 self permanent

'if10' indicates 'dummy0' interface index.
But the dummy0 interface was removed so this fdb will not work.

Signed-off-by: Taehee Yoo <ap420...@gmail.com>
---
 drivers/net/vxlan.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index a0015cdedfaf..52ca735bd91a 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -4440,6 +4440,39 @@ struct net_device *vxlan_dev_create(struct net *net, 
const char *name,
 }
 EXPORT_SYMBOL_GPL(vxlan_dev_create);
 
+static void vxlan_delete_rdst(struct vxlan_dev *vxlan, unsigned int h,
+                             int ifindex)
+{
+       struct hlist_node *tmp;
+       struct vxlan_fdb *f;
+
+       spin_lock_bh(&vxlan->hash_lock[h]);
+       hlist_for_each_entry_safe(f, tmp, &vxlan->fdb_head[h], hlist) {
+               struct vxlan_rdst *rd, *rd_next;
+
+               list_for_each_entry_safe(rd, rd_next, &f->remotes, list) {
+                       if (rd->remote_ifindex != ifindex)
+                               continue;
+
+                       if (list_is_singular(&f->remotes))
+                               vxlan_fdb_destroy(vxlan, f, true, true);
+                       else
+                               vxlan_fdb_dst_destroy(vxlan, f, rd, true);
+               }
+       }
+       spin_unlock_bh(&vxlan->hash_lock[h]);
+}
+
+static void vxlan_delete_rdsts(struct vxlan_net *vn, struct net_device *dev)
+{
+       struct vxlan_dev *vxlan, *next;
+       unsigned int h;
+
+       list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next)
+               for (h = 0; h < FDB_HASH_SIZE; ++h)
+                       vxlan_delete_rdst(vxlan, h, dev->ifindex);
+}
+
 static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
                                             struct net_device *dev)
 {
@@ -4470,6 +4503,7 @@ static int vxlan_netdevice_event(struct notifier_block 
*unused,
 
        if (event == NETDEV_UNREGISTER) {
                vxlan_offload_rx_ports(dev, false);
+               vxlan_delete_rdsts(vn, dev);
                vxlan_handle_lowerdev_unregister(vn, dev);
        } else if (event == NETDEV_REGISTER) {
                vxlan_offload_rx_ports(dev, true);
-- 
2.17.1

Reply via email to