@@ -81,7 +81,7 @@ struct vxlan_fdb {
81
81
u16 flags ; /* see ndm_flags and below */
82
82
struct list_head nh_list ;
83
83
struct nexthop __rcu * nh ;
84
- struct vxlan_dev * vdev ;
84
+ struct vxlan_dev __rcu * vdev ;
85
85
};
86
86
87
87
#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,
837
837
f -> updated = f -> used = jiffies ;
838
838
f -> vni = src_vni ;
839
839
f -> nh = NULL ;
840
- f -> vdev = vxlan ;
840
+ RCU_INIT_POINTER ( f -> vdev , vxlan ) ;
841
841
INIT_LIST_HEAD (& f -> nh_list );
842
842
INIT_LIST_HEAD (& f -> remotes );
843
843
memcpy (f -> eth_addr , mac , ETH_ALEN );
@@ -963,7 +963,7 @@ static void __vxlan_fdb_free(struct vxlan_fdb *f)
963
963
nh = rcu_dereference_raw (f -> nh );
964
964
if (nh ) {
965
965
rcu_assign_pointer (f -> nh , NULL );
966
- list_del_rcu ( & f -> nh_list );
966
+ rcu_assign_pointer ( f -> vdev , NULL );
967
967
nexthop_put (nh );
968
968
}
969
969
@@ -1000,7 +1000,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
1000
1000
}
1001
1001
1002
1002
hlist_del_rcu (& f -> hlist );
1003
- f -> vdev = NULL ;
1003
+ list_del_rcu ( & f -> nh_list ) ;
1004
1004
call_rcu (& f -> rcu , vxlan_fdb_free );
1005
1005
}
1006
1006
@@ -1196,6 +1196,10 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
1196
1196
struct net * net = dev_net (vxlan -> dev );
1197
1197
int err ;
1198
1198
1199
+ if (tb [NDA_NH_ID ] && (tb [NDA_DST ] || tb [NDA_VNI ] || tb [NDA_IFINDEX ] ||
1200
+ tb [NDA_PORT ]))
1201
+ return - EINVAL ;
1202
+
1199
1203
if (tb [NDA_DST ]) {
1200
1204
err = vxlan_nla_get_addr (ip , tb [NDA_DST ]);
1201
1205
if (err )
@@ -4611,17 +4615,35 @@ static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = {
4611
4615
.notifier_call = vxlan_switchdev_event ,
4612
4616
};
4613
4617
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
+
4614
4638
static int vxlan_nexthop_event (struct notifier_block * nb ,
4615
4639
unsigned long event , void * ptr )
4616
4640
{
4617
4641
struct nexthop * nh = ptr ;
4618
- struct vxlan_fdb * fdb , * tmp ;
4619
4642
4620
4643
if (!nh || event != NEXTHOP_EVENT_DEL )
4621
4644
return NOTIFY_DONE ;
4622
4645
4623
- list_for_each_entry_safe (fdb , tmp , & nh -> fdb_list , nh_list )
4624
- vxlan_fdb_destroy (fdb -> vdev , fdb , false, false);
4646
+ vxlan_fdb_nh_flush (nh );
4625
4647
4626
4648
return NOTIFY_DONE ;
4627
4649
}
0 commit comments