Skip to content

Commit 79472fe

Browse files
roopa-prabhudavem330
authored andcommitted
vxlan: few locking fixes in nexthop event handler
- remove fdb from nh_list before the rcu grace period - protect fdb->vdev with rcu - hold spin lock before destroying fdb Fixes: c7cdbe2 ("vxlan: support for nexthop notifiers") Signed-off-by: Roopa Prabhu <[email protected]> Reviewed-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 72b4868 commit 79472fe

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

drivers/net/vxlan.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ struct vxlan_fdb {
8181
u16 flags; /* see ndm_flags and below */
8282
struct list_head nh_list;
8383
struct nexthop __rcu *nh;
84-
struct vxlan_dev *vdev;
84+
struct vxlan_dev __rcu *vdev;
8585
};
8686

8787
#define NTF_VXLAN_ADDED_BY_USER 0x100
@@ -837,7 +837,7 @@ static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, const u8 *mac,
837837
f->updated = f->used = jiffies;
838838
f->vni = src_vni;
839839
f->nh = NULL;
840-
f->vdev = vxlan;
840+
RCU_INIT_POINTER(f->vdev, vxlan);
841841
INIT_LIST_HEAD(&f->nh_list);
842842
INIT_LIST_HEAD(&f->remotes);
843843
memcpy(f->eth_addr, mac, ETH_ALEN);
@@ -963,7 +963,7 @@ static void __vxlan_fdb_free(struct vxlan_fdb *f)
963963
nh = rcu_dereference_raw(f->nh);
964964
if (nh) {
965965
rcu_assign_pointer(f->nh, NULL);
966-
list_del_rcu(&f->nh_list);
966+
rcu_assign_pointer(f->vdev, NULL);
967967
nexthop_put(nh);
968968
}
969969

@@ -1000,7 +1000,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
10001000
}
10011001

10021002
hlist_del_rcu(&f->hlist);
1003-
f->vdev = NULL;
1003+
list_del_rcu(&f->nh_list);
10041004
call_rcu(&f->rcu, vxlan_fdb_free);
10051005
}
10061006

@@ -4615,17 +4615,35 @@ static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = {
46154615
.notifier_call = vxlan_switchdev_event,
46164616
};
46174617

4618+
static void vxlan_fdb_nh_flush(struct nexthop *nh)
4619+
{
4620+
struct vxlan_fdb *fdb;
4621+
struct vxlan_dev *vxlan;
4622+
u32 hash_index;
4623+
4624+
rcu_read_lock();
4625+
list_for_each_entry_rcu(fdb, &nh->fdb_list, nh_list) {
4626+
vxlan = rcu_dereference(fdb->vdev);
4627+
WARN_ON(!vxlan);
4628+
hash_index = fdb_head_index(vxlan, fdb->eth_addr,
4629+
vxlan->default_dst.remote_vni);
4630+
spin_lock_bh(&vxlan->hash_lock[hash_index]);
4631+
if (!hlist_unhashed(&fdb->hlist))
4632+
vxlan_fdb_destroy(vxlan, fdb, false, false);
4633+
spin_unlock_bh(&vxlan->hash_lock[hash_index]);
4634+
}
4635+
rcu_read_unlock();
4636+
}
4637+
46184638
static int vxlan_nexthop_event(struct notifier_block *nb,
46194639
unsigned long event, void *ptr)
46204640
{
46214641
struct nexthop *nh = ptr;
4622-
struct vxlan_fdb *fdb, *tmp;
46234642

46244643
if (!nh || event != NEXTHOP_EVENT_DEL)
46254644
return NOTIFY_DONE;
46264645

4627-
list_for_each_entry_safe(fdb, tmp, &nh->fdb_list, nh_list)
4628-
vxlan_fdb_destroy(fdb->vdev, fdb, false, false);
4646+
vxlan_fdb_nh_flush(nh);
46294647

46304648
return NOTIFY_DONE;
46314649
}

0 commit comments

Comments
 (0)