1515#include <linux/igmp.h>
1616#include <linux/if_ether.h>
1717#include <linux/ethtool.h>
18+ #include <linux/rhashtable.h>
1819#include <net/arp.h>
1920#include <net/ndisc.h>
2021#include <net/gro.h>
@@ -63,8 +64,12 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan);
6364
6465static void vxlan_vs_del_dev (struct vxlan_dev * vxlan );
6566
66- /* salt for hash table */
67- static u32 vxlan_salt __read_mostly ;
67+ static const struct rhashtable_params vxlan_fdb_rht_params = {
68+ .head_offset = offsetof(struct vxlan_fdb , rhnode ),
69+ .key_offset = offsetof(struct vxlan_fdb , key ),
70+ .key_len = sizeof (struct vxlan_fdb_key ),
71+ .automatic_shrinking = true,
72+ };
6873
6974static inline bool vxlan_collect_metadata (struct vxlan_sock * vs )
7075{
@@ -371,62 +376,21 @@ static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN])
371376 vxlan_fdb_notify (vxlan , & f , & remote , RTM_GETNEIGH , true, NULL );
372377}
373378
374- /* Hash Ethernet address */
375- static u32 eth_hash (const unsigned char * addr )
376- {
377- u64 value = get_unaligned ((u64 * )addr );
378-
379- /* only want 6 bytes */
380- #ifdef __BIG_ENDIAN
381- value >>= 16 ;
382- #else
383- value <<= 16 ;
384- #endif
385- return hash_64 (value , FDB_HASH_BITS );
386- }
387-
388- u32 eth_vni_hash (const unsigned char * addr , __be32 vni )
389- {
390- /* use 1 byte of OUI and 3 bytes of NIC */
391- u32 key = get_unaligned ((u32 * )(addr + 2 ));
392-
393- return jhash_2words (key , vni , vxlan_salt ) & (FDB_HASH_SIZE - 1 );
394- }
395-
396- u32 fdb_head_index (struct vxlan_dev * vxlan , const u8 * mac , __be32 vni )
397- {
398- if (vxlan -> cfg .flags & VXLAN_F_COLLECT_METADATA )
399- return eth_vni_hash (mac , vni );
400- else
401- return eth_hash (mac );
402- }
403-
404- /* Hash chain to use given mac address */
405- static inline struct hlist_head * vxlan_fdb_head (struct vxlan_dev * vxlan ,
406- const u8 * mac , __be32 vni )
407- {
408- return & vxlan -> fdb_head [fdb_head_index (vxlan , mac , vni )];
409- }
410-
411379/* Look up Ethernet address in forwarding table */
412380static struct vxlan_fdb * vxlan_find_mac_rcu (struct vxlan_dev * vxlan ,
413381 const u8 * mac , __be32 vni )
414382{
415- struct hlist_head * head = vxlan_fdb_head (vxlan , mac , vni );
416- struct vxlan_fdb * f ;
383+ struct vxlan_fdb_key key ;
417384
418- hlist_for_each_entry_rcu (f , head , hlist ) {
419- if (ether_addr_equal (mac , f -> key .eth_addr )) {
420- if (vxlan -> cfg .flags & VXLAN_F_COLLECT_METADATA ) {
421- if (vni == f -> key .vni )
422- return f ;
423- } else {
424- return f ;
425- }
426- }
427- }
385+ memset (& key , 0 , sizeof (key ));
386+ memcpy (key .eth_addr , mac , sizeof (key .eth_addr ));
387+ if (!(vxlan -> cfg .flags & VXLAN_F_COLLECT_METADATA ))
388+ key .vni = vxlan -> default_dst .remote_vni ;
389+ else
390+ key .vni = vni ;
428391
429- return NULL ;
392+ return rhashtable_lookup (& vxlan -> fdb_hash_tbl , & key ,
393+ vxlan_fdb_rht_params );
430394}
431395
432396static struct vxlan_fdb * vxlan_find_mac_tx (struct vxlan_dev * vxlan ,
@@ -915,15 +879,27 @@ int vxlan_fdb_create(struct vxlan_dev *vxlan,
915879 if (rc < 0 )
916880 goto errout ;
917881
882+ rc = rhashtable_lookup_insert_fast (& vxlan -> fdb_hash_tbl , & f -> rhnode ,
883+ vxlan_fdb_rht_params );
884+ if (rc )
885+ goto destroy_remote ;
886+
918887 ++ vxlan -> addrcnt ;
919- hlist_add_head_rcu (& f -> hlist ,
920- vxlan_fdb_head (vxlan , mac , src_vni ));
921888 hlist_add_head_rcu (& f -> fdb_node , & vxlan -> fdb_list );
922889
923890 * fdb = f ;
924891
925892 return 0 ;
926893
894+ destroy_remote :
895+ if (rcu_access_pointer (f -> nh )) {
896+ list_del_rcu (& f -> nh_list );
897+ nexthop_put (rtnl_dereference (f -> nh ));
898+ } else {
899+ list_del (& rd -> list );
900+ dst_cache_destroy (& rd -> dst_cache );
901+ kfree (rd );
902+ }
927903errout :
928904 kfree (f );
929905 return rc ;
@@ -974,7 +950,8 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
974950 }
975951
976952 hlist_del_init_rcu (& f -> fdb_node );
977- hlist_del_rcu (& f -> hlist );
953+ rhashtable_remove_fast (& vxlan -> fdb_hash_tbl , & f -> rhnode ,
954+ vxlan_fdb_rht_params );
978955 list_del_rcu (& f -> nh_list );
979956 call_rcu (& f -> rcu , vxlan_fdb_free );
980957}
@@ -2898,10 +2875,14 @@ static int vxlan_init(struct net_device *dev)
28982875 struct vxlan_dev * vxlan = netdev_priv (dev );
28992876 int err ;
29002877
2878+ err = rhashtable_init (& vxlan -> fdb_hash_tbl , & vxlan_fdb_rht_params );
2879+ if (err )
2880+ return err ;
2881+
29012882 if (vxlan -> cfg .flags & VXLAN_F_VNIFILTER ) {
29022883 err = vxlan_vnigroup_init (vxlan );
29032884 if (err )
2904- return err ;
2885+ goto err_rhashtable_destroy ;
29052886 }
29062887
29072888 err = gro_cells_init (& vxlan -> gro_cells , dev );
@@ -2920,6 +2901,8 @@ static int vxlan_init(struct net_device *dev)
29202901err_vnigroup_uninit :
29212902 if (vxlan -> cfg .flags & VXLAN_F_VNIFILTER )
29222903 vxlan_vnigroup_uninit (vxlan );
2904+ err_rhashtable_destroy :
2905+ rhashtable_destroy (& vxlan -> fdb_hash_tbl );
29232906 return err ;
29242907}
29252908
@@ -2933,6 +2916,8 @@ static void vxlan_uninit(struct net_device *dev)
29332916 vxlan_vnigroup_uninit (vxlan );
29342917
29352918 gro_cells_destroy (& vxlan -> gro_cells );
2919+
2920+ rhashtable_destroy (& vxlan -> fdb_hash_tbl );
29362921}
29372922
29382923/* Start ageing timer and join group when device is brought up */
@@ -3329,7 +3314,6 @@ static void vxlan_offload_rx_ports(struct net_device *dev, bool push)
33293314static void vxlan_setup (struct net_device * dev )
33303315{
33313316 struct vxlan_dev * vxlan = netdev_priv (dev );
3332- unsigned int h ;
33333317
33343318 eth_hw_addr_random (dev );
33353319 ether_setup (dev );
@@ -3362,8 +3346,6 @@ static void vxlan_setup(struct net_device *dev)
33623346
33633347 vxlan -> dev = dev ;
33643348
3365- for (h = 0 ; h < FDB_HASH_SIZE ; ++ h )
3366- INIT_HLIST_HEAD (& vxlan -> fdb_head [h ]);
33673349 INIT_HLIST_HEAD (& vxlan -> fdb_list );
33683350}
33693351
@@ -4944,8 +4926,6 @@ static int __init vxlan_init_module(void)
49444926{
49454927 int rc ;
49464928
4947- get_random_bytes (& vxlan_salt , sizeof (vxlan_salt ));
4948-
49494929 rc = register_pernet_subsys (& vxlan_net_ops );
49504930 if (rc )
49514931 goto out1 ;
0 commit comments