Commit b79a79471bd31d737c939a6ddc347417047b4320

Authored by Jussi Mäki
Committed by David S. Miller
1 parent 082ba88a5e

Fix xfrm hash collisions by changing __xfrm4_daddr_saddr_hash to hash addresses with addition

This patch fixes hash collisions in cases where number
of entries have incrementing IP source and destination addresses
from single respective subnets (i.e. 192.168.0.1-172.16.0.1,
192.168.0.2-172.16.0.2, and so on.).

Signed-off-by: Jussi Maki <joamaki@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 1 additions and 1 deletions Inline Diff

net/xfrm/xfrm_hash.h
1 #ifndef _XFRM_HASH_H 1 #ifndef _XFRM_HASH_H
2 #define _XFRM_HASH_H 2 #define _XFRM_HASH_H
3 3
4 #include <linux/xfrm.h> 4 #include <linux/xfrm.h>
5 #include <linux/socket.h> 5 #include <linux/socket.h>
6 6
7 static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr) 7 static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
8 { 8 {
9 return ntohl(addr->a4); 9 return ntohl(addr->a4);
10 } 10 }
11 11
12 static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr) 12 static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
13 { 13 {
14 return ntohl(addr->a6[2] ^ addr->a6[3]); 14 return ntohl(addr->a6[2] ^ addr->a6[3]);
15 } 15 }
16 16
17 static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) 17 static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
18 { 18 {
19 return ntohl(daddr->a4 ^ saddr->a4); 19 return ntohl(daddr->a4 + saddr->a4);
20 } 20 }
21 21
22 static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) 22 static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
23 { 23 {
24 return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ 24 return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
25 saddr->a6[2] ^ saddr->a6[3]); 25 saddr->a6[2] ^ saddr->a6[3]);
26 } 26 }
27 27
28 static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, 28 static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr,
29 u32 reqid, unsigned short family, 29 u32 reqid, unsigned short family,
30 unsigned int hmask) 30 unsigned int hmask)
31 { 31 {
32 unsigned int h = family ^ reqid; 32 unsigned int h = family ^ reqid;
33 switch (family) { 33 switch (family) {
34 case AF_INET: 34 case AF_INET:
35 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); 35 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
36 break; 36 break;
37 case AF_INET6: 37 case AF_INET6:
38 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); 38 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
39 break; 39 break;
40 } 40 }
41 return (h ^ (h >> 16)) & hmask; 41 return (h ^ (h >> 16)) & hmask;
42 } 42 }
43 43
44 static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr, 44 static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
45 xfrm_address_t *saddr, 45 xfrm_address_t *saddr,
46 unsigned short family, 46 unsigned short family,
47 unsigned int hmask) 47 unsigned int hmask)
48 { 48 {
49 unsigned int h = family; 49 unsigned int h = family;
50 switch (family) { 50 switch (family) {
51 case AF_INET: 51 case AF_INET:
52 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); 52 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
53 break; 53 break;
54 case AF_INET6: 54 case AF_INET6:
55 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); 55 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
56 break; 56 break;
57 }; 57 };
58 return (h ^ (h >> 16)) & hmask; 58 return (h ^ (h >> 16)) & hmask;
59 } 59 }
60 60
61 static inline unsigned int 61 static inline unsigned int
62 __xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family, 62 __xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
63 unsigned int hmask) 63 unsigned int hmask)
64 { 64 {
65 unsigned int h = (__force u32)spi ^ proto; 65 unsigned int h = (__force u32)spi ^ proto;
66 switch (family) { 66 switch (family) {
67 case AF_INET: 67 case AF_INET:
68 h ^= __xfrm4_addr_hash(daddr); 68 h ^= __xfrm4_addr_hash(daddr);
69 break; 69 break;
70 case AF_INET6: 70 case AF_INET6:
71 h ^= __xfrm6_addr_hash(daddr); 71 h ^= __xfrm6_addr_hash(daddr);
72 break; 72 break;
73 } 73 }
74 return (h ^ (h >> 10) ^ (h >> 20)) & hmask; 74 return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
75 } 75 }
76 76
77 static inline unsigned int __idx_hash(u32 index, unsigned int hmask) 77 static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
78 { 78 {
79 return (index ^ (index >> 8)) & hmask; 79 return (index ^ (index >> 8)) & hmask;
80 } 80 }
81 81
82 static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask) 82 static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask)
83 { 83 {
84 xfrm_address_t *daddr = &sel->daddr; 84 xfrm_address_t *daddr = &sel->daddr;
85 xfrm_address_t *saddr = &sel->saddr; 85 xfrm_address_t *saddr = &sel->saddr;
86 unsigned int h = 0; 86 unsigned int h = 0;
87 87
88 switch (family) { 88 switch (family) {
89 case AF_INET: 89 case AF_INET:
90 if (sel->prefixlen_d != 32 || 90 if (sel->prefixlen_d != 32 ||
91 sel->prefixlen_s != 32) 91 sel->prefixlen_s != 32)
92 return hmask + 1; 92 return hmask + 1;
93 93
94 h = __xfrm4_daddr_saddr_hash(daddr, saddr); 94 h = __xfrm4_daddr_saddr_hash(daddr, saddr);
95 break; 95 break;
96 96
97 case AF_INET6: 97 case AF_INET6:
98 if (sel->prefixlen_d != 128 || 98 if (sel->prefixlen_d != 128 ||
99 sel->prefixlen_s != 128) 99 sel->prefixlen_s != 128)
100 return hmask + 1; 100 return hmask + 1;
101 101
102 h = __xfrm6_daddr_saddr_hash(daddr, saddr); 102 h = __xfrm6_daddr_saddr_hash(daddr, saddr);
103 break; 103 break;
104 }; 104 };
105 h ^= (h >> 16); 105 h ^= (h >> 16);
106 return h & hmask; 106 return h & hmask;
107 } 107 }
108 108
109 static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask) 109 static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask)
110 { 110 {
111 unsigned int h = 0; 111 unsigned int h = 0;
112 112
113 switch (family) { 113 switch (family) {
114 case AF_INET: 114 case AF_INET:
115 h = __xfrm4_daddr_saddr_hash(daddr, saddr); 115 h = __xfrm4_daddr_saddr_hash(daddr, saddr);
116 break; 116 break;
117 117
118 case AF_INET6: 118 case AF_INET6:
119 h = __xfrm6_daddr_saddr_hash(daddr, saddr); 119 h = __xfrm6_daddr_saddr_hash(daddr, saddr);
120 break; 120 break;
121 }; 121 };
122 h ^= (h >> 16); 122 h ^= (h >> 16);
123 return h & hmask; 123 return h & hmask;
124 } 124 }
125 125
126 extern struct hlist_head *xfrm_hash_alloc(unsigned int sz); 126 extern struct hlist_head *xfrm_hash_alloc(unsigned int sz);
127 extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz); 127 extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz);
128 128
129 #endif /* _XFRM_HASH_H */ 129 #endif /* _XFRM_HASH_H */
130 130