Skip to content

Commit ff9fc0a

Browse files
committed
Merge branch 'ipv4-avoid-pathological-hash-tables'
Eric Dumazet says: ==================== ipv4: avoid pathological hash tables This series speeds up netns dismantles on hosts having many active netns, by making sure two hash tables used for IPV4 fib contains uniformly spread items. v2: changed second patch to add fib_info_laddrhash_bucket() for consistency (David Ahern suggestion). ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 8eb896a + 79eb15d commit ff9fc0a

File tree

1 file changed

+32
-33
lines changed

1 file changed

+32
-33
lines changed

net/ipv4/fib_semantics.c

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/init.h>
3030
#include <linux/slab.h>
3131
#include <linux/netlink.h>
32+
#include <linux/hash.h>
3233

3334
#include <net/arp.h>
3435
#include <net/ip.h>
@@ -51,6 +52,7 @@ static DEFINE_SPINLOCK(fib_info_lock);
5152
static struct hlist_head *fib_info_hash;
5253
static struct hlist_head *fib_info_laddrhash;
5354
static unsigned int fib_info_hash_size;
55+
static unsigned int fib_info_hash_bits;
5456
static unsigned int fib_info_cnt;
5557

5658
#define DEVINDEX_HASHBITS 8
@@ -319,11 +321,15 @@ static inline int nh_comp(struct fib_info *fi, struct fib_info *ofi)
319321

320322
static inline unsigned int fib_devindex_hashfn(unsigned int val)
321323
{
322-
unsigned int mask = DEVINDEX_HASHSIZE - 1;
324+
return hash_32(val, DEVINDEX_HASHBITS);
325+
}
326+
327+
static struct hlist_head *
328+
fib_info_devhash_bucket(const struct net_device *dev)
329+
{
330+
u32 val = net_hash_mix(dev_net(dev)) ^ dev->ifindex;
323331

324-
return (val ^
325-
(val >> DEVINDEX_HASHBITS) ^
326-
(val >> (DEVINDEX_HASHBITS * 2))) & mask;
332+
return &fib_info_devhash[fib_devindex_hashfn(val)];
327333
}
328334

329335
static unsigned int fib_info_hashfn_1(int init_val, u8 protocol, u8 scope,
@@ -433,12 +439,11 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev)
433439
{
434440
struct hlist_head *head;
435441
struct fib_nh *nh;
436-
unsigned int hash;
437442

438443
spin_lock(&fib_info_lock);
439444

440-
hash = fib_devindex_hashfn(dev->ifindex);
441-
head = &fib_info_devhash[hash];
445+
head = fib_info_devhash_bucket(dev);
446+
442447
hlist_for_each_entry(nh, head, nh_hash) {
443448
if (nh->fib_nh_dev == dev &&
444449
nh->fib_nh_gw4 == gw &&
@@ -1243,13 +1248,13 @@ int fib_check_nh(struct net *net, struct fib_nh *nh, u32 table, u8 scope,
12431248
return err;
12441249
}
12451250

1246-
static inline unsigned int fib_laddr_hashfn(__be32 val)
1251+
static struct hlist_head *
1252+
fib_info_laddrhash_bucket(const struct net *net, __be32 val)
12471253
{
1248-
unsigned int mask = (fib_info_hash_size - 1);
1254+
u32 slot = hash_32(net_hash_mix(net) ^ (__force u32)val,
1255+
fib_info_hash_bits);
12491256

1250-
return ((__force u32)val ^
1251-
((__force u32)val >> 7) ^
1252-
((__force u32)val >> 14)) & mask;
1257+
return &fib_info_laddrhash[slot];
12531258
}
12541259

12551260
static struct hlist_head *fib_info_hash_alloc(int bytes)
@@ -1285,6 +1290,7 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
12851290
old_info_hash = fib_info_hash;
12861291
old_laddrhash = fib_info_laddrhash;
12871292
fib_info_hash_size = new_size;
1293+
fib_info_hash_bits = ilog2(new_size);
12881294

12891295
for (i = 0; i < old_size; i++) {
12901296
struct hlist_head *head = &fib_info_hash[i];
@@ -1302,21 +1308,20 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
13021308
}
13031309
fib_info_hash = new_info_hash;
13041310

1311+
fib_info_laddrhash = new_laddrhash;
13051312
for (i = 0; i < old_size; i++) {
1306-
struct hlist_head *lhead = &fib_info_laddrhash[i];
1313+
struct hlist_head *lhead = &old_laddrhash[i];
13071314
struct hlist_node *n;
13081315
struct fib_info *fi;
13091316

13101317
hlist_for_each_entry_safe(fi, n, lhead, fib_lhash) {
13111318
struct hlist_head *ldest;
1312-
unsigned int new_hash;
13131319

1314-
new_hash = fib_laddr_hashfn(fi->fib_prefsrc);
1315-
ldest = &new_laddrhash[new_hash];
1320+
ldest = fib_info_laddrhash_bucket(fi->fib_net,
1321+
fi->fib_prefsrc);
13161322
hlist_add_head(&fi->fib_lhash, ldest);
13171323
}
13181324
}
1319-
fib_info_laddrhash = new_laddrhash;
13201325

13211326
spin_unlock_bh(&fib_info_lock);
13221327

@@ -1601,20 +1606,18 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
16011606
if (fi->fib_prefsrc) {
16021607
struct hlist_head *head;
16031608

1604-
head = &fib_info_laddrhash[fib_laddr_hashfn(fi->fib_prefsrc)];
1609+
head = fib_info_laddrhash_bucket(net, fi->fib_prefsrc);
16051610
hlist_add_head(&fi->fib_lhash, head);
16061611
}
16071612
if (fi->nh) {
16081613
list_add(&fi->nh_list, &nh->fi_list);
16091614
} else {
16101615
change_nexthops(fi) {
16111616
struct hlist_head *head;
1612-
unsigned int hash;
16131617

16141618
if (!nexthop_nh->fib_nh_dev)
16151619
continue;
1616-
hash = fib_devindex_hashfn(nexthop_nh->fib_nh_dev->ifindex);
1617-
head = &fib_info_devhash[hash];
1620+
head = fib_info_devhash_bucket(nexthop_nh->fib_nh_dev);
16181621
hlist_add_head(&nexthop_nh->nh_hash, head);
16191622
} endfor_nexthops(fi)
16201623
}
@@ -1875,16 +1878,16 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
18751878
*/
18761879
int fib_sync_down_addr(struct net_device *dev, __be32 local)
18771880
{
1878-
int ret = 0;
1879-
unsigned int hash = fib_laddr_hashfn(local);
1880-
struct hlist_head *head = &fib_info_laddrhash[hash];
18811881
int tb_id = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
18821882
struct net *net = dev_net(dev);
1883+
struct hlist_head *head;
18831884
struct fib_info *fi;
1885+
int ret = 0;
18841886

18851887
if (!fib_info_laddrhash || local == 0)
18861888
return 0;
18871889

1890+
head = fib_info_laddrhash_bucket(net, local);
18881891
hlist_for_each_entry(fi, head, fib_lhash) {
18891892
if (!net_eq(fi->fib_net, net) ||
18901893
fi->fib_tb_id != tb_id)
@@ -1966,8 +1969,7 @@ void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
19661969

19671970
void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
19681971
{
1969-
unsigned int hash = fib_devindex_hashfn(dev->ifindex);
1970-
struct hlist_head *head = &fib_info_devhash[hash];
1972+
struct hlist_head *head = fib_info_devhash_bucket(dev);
19711973
struct fib_nh *nh;
19721974

19731975
hlist_for_each_entry(nh, head, nh_hash) {
@@ -1986,12 +1988,11 @@ void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
19861988
*/
19871989
int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force)
19881990
{
1989-
int ret = 0;
1990-
int scope = RT_SCOPE_NOWHERE;
1991+
struct hlist_head *head = fib_info_devhash_bucket(dev);
19911992
struct fib_info *prev_fi = NULL;
1992-
unsigned int hash = fib_devindex_hashfn(dev->ifindex);
1993-
struct hlist_head *head = &fib_info_devhash[hash];
1993+
int scope = RT_SCOPE_NOWHERE;
19941994
struct fib_nh *nh;
1995+
int ret = 0;
19951996

19961997
if (force)
19971998
scope = -1;
@@ -2136,7 +2137,6 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
21362137
int fib_sync_up(struct net_device *dev, unsigned char nh_flags)
21372138
{
21382139
struct fib_info *prev_fi;
2139-
unsigned int hash;
21402140
struct hlist_head *head;
21412141
struct fib_nh *nh;
21422142
int ret;
@@ -2152,8 +2152,7 @@ int fib_sync_up(struct net_device *dev, unsigned char nh_flags)
21522152
}
21532153

21542154
prev_fi = NULL;
2155-
hash = fib_devindex_hashfn(dev->ifindex);
2156-
head = &fib_info_devhash[hash];
2155+
head = fib_info_devhash_bucket(dev);
21572156
ret = 0;
21582157

21592158
hlist_for_each_entry(nh, head, nh_hash) {

0 commit comments

Comments
 (0)