Skip to content

Commit 1f763fa

Browse files
idoschPaolo Abeni
authored andcommitted
vxlan: Convert FDB table to rhashtable
FDB entries are currently stored in a hash table with a fixed number of buckets (256), resulting in performance degradation as the number of entries grows. Solve this by converting the driver to use rhashtable which maintains more or less constant performance regardless of the number of entries. Measured transmitted packets per second using a single pktgen thread with varying number of entries when the transmitted packet always hits the default entry (worst case): Number of entries | Improvement ------------------|------------ 1k | +1.12% 4k | +9.22% 16k | +55% 64k | +585% 256k | +2460% In addition, the change reduces the size of the VXLAN device structure from 2584 bytes to 672 bytes. Reviewed-by: Petr Machata <petrm@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20250415121143.345227-16-idosch@nvidia.com Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent f13f3b4 commit 1f763fa

File tree

3 files changed

+43
-63
lines changed

3 files changed

+43
-63
lines changed

drivers/net/vxlan/vxlan_core.c

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
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

6465
static 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

6974
static 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 */
412380
static 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

432396
static 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+
}
927903
errout:
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)
29202901
err_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)
33293314
static 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;

drivers/net/vxlan/vxlan_private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct vxlan_fdb_key {
3131

3232
/* Forwarding table entry */
3333
struct vxlan_fdb {
34-
struct hlist_node hlist; /* linked list of entries */
34+
struct rhash_head rhnode;
3535
struct rcu_head rcu;
3636
unsigned long updated; /* jiffies */
3737
unsigned long used;

include/net/vxlan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ struct vxlan_dev {
304304

305305
struct vxlan_vni_group __rcu *vnigrp;
306306

307-
struct hlist_head fdb_head[FDB_HASH_SIZE];
307+
struct rhashtable fdb_hash_tbl;
308308

309309
struct rhashtable mdb_tbl;
310310
struct hlist_head fdb_list;

0 commit comments

Comments
 (0)