@@ -81,6 +81,7 @@ struct vxlan_fdb {
u16 flags; /* see ndm_flags and below */
struct list_head nh_list;
struct nexthop *nh;
+ struct vxlan_dev *vdev;
};
#define NTF_VXLAN_ADDED_BY_USER 0x100
@@ -811,8 +812,9 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
}
-static struct vxlan_fdb *vxlan_fdb_alloc(const u8 *mac, __u16 state,
- __be32 src_vni, __u16 ndm_flags)
+static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, const u8 *mac,
+ __u16 state, __be32 src_vni,
+ __u16 ndm_flags)
{
struct vxlan_fdb *f;
@@ -824,6 +826,7 @@ static struct vxlan_fdb *vxlan_fdb_alloc(const u8 *mac, __u16 state,
f->updated = f->used = jiffies;
f->vni = src_vni;
f->nh = NULL;
+ f->vdev = vxlan;
INIT_LIST_HEAD(&f->nh_list);
INIT_LIST_HEAD(&f->remotes);
memcpy(f->eth_addr, mac, ETH_ALEN);
@@ -902,7 +905,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
return -ENOSPC;
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
- f = vxlan_fdb_alloc(mac, state, src_vni, ndm_flags);
+ f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags);
if (!f)
return -ENOMEM;
@@ -954,6 +957,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
swdev_notify, NULL);
hlist_del_rcu(&f->hlist);
+ f->vdev = NULL;
call_rcu(&f->rcu, vxlan_fdb_free);
}
@@ -4576,6 +4580,25 @@ static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = {
.notifier_call = vxlan_switchdev_event,
};
+static int vxlan_nexthop_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct nexthop *nh = ptr;
+ struct vxlan_fdb *fdb;
+
+ if (!nh || event != NEXTHOP_EVENT_DEL)
+ return NOTIFY_DONE;
+
+ list_for_each_entry(fdb, &nh->fdb_list, nh_list)
+ vxlan_fdb_destroy(fdb->vdev, fdb, true, false);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block vxlan_nexthop_notifier_block __read_mostly = {
+ .notifier_call = vxlan_nexthop_event,
+};
+
static __net_init int vxlan_init_net(struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
@@ -4655,7 +4678,13 @@ static int __init vxlan_init_module(void)
if (rc)
goto out4;
+ rc = register_nexthop_notifier(&vxlan_nexthop_notifier_block);
+ if (rc)
+ goto out5;
+
return 0;
+out5:
+ rtnl_link_unregister(&vxlan_link_ops);
out4:
unregister_switchdev_notifier(&vxlan_switchdev_notifier_block);
out3:
@@ -4672,6 +4701,7 @@ static void __exit vxlan_cleanup_module(void)
rtnl_link_unregister(&vxlan_link_ops);
unregister_switchdev_notifier(&vxlan_switchdev_notifier_block);
unregister_netdevice_notifier(&vxlan_notifier_block);
+ unregister_nexthop_notifier(&vxlan_nexthop_notifier_block);
unregister_pernet_subsys(&vxlan_net_ops);
/* rcu_barrier() is called by netns */
}