]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
44e36b42 DM |
2 | #ifndef _XFRM_HASH_H |
3 | #define _XFRM_HASH_H | |
4 | ||
5 | #include <linux/xfrm.h> | |
6 | #include <linux/socket.h> | |
b58555f1 | 7 | #include <linux/jhash.h> |
44e36b42 | 8 | |
5f803b58 | 9 | static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) |
44e36b42 DM |
10 | { |
11 | return ntohl(addr->a4); | |
12 | } | |
13 | ||
5f803b58 | 14 | static inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr) |
44e36b42 DM |
15 | { |
16 | return ntohl(addr->a6[2] ^ addr->a6[3]); | |
17 | } | |
18 | ||
5f803b58 DM |
19 | static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, |
20 | const xfrm_address_t *saddr) | |
44e36b42 | 21 | { |
0eae88f3 ED |
22 | u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4; |
23 | return ntohl((__force __be32)sum); | |
44e36b42 DM |
24 | } |
25 | ||
5f803b58 DM |
26 | static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr, |
27 | const xfrm_address_t *saddr) | |
44e36b42 DM |
28 | { |
29 | return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | |
30 | saddr->a6[2] ^ saddr->a6[3]); | |
31 | } | |
32 | ||
b58555f1 CG |
33 | static inline u32 __bits2mask32(__u8 bits) |
34 | { | |
35 | u32 mask32 = 0xffffffff; | |
36 | ||
37 | if (bits == 0) | |
38 | mask32 = 0; | |
39 | else if (bits < 32) | |
40 | mask32 <<= (32 - bits); | |
41 | ||
42 | return mask32; | |
43 | } | |
44 | ||
45 | static inline unsigned int __xfrm4_dpref_spref_hash(const xfrm_address_t *daddr, | |
46 | const xfrm_address_t *saddr, | |
47 | __u8 dbits, | |
48 | __u8 sbits) | |
49 | { | |
50 | return jhash_2words(ntohl(daddr->a4) & __bits2mask32(dbits), | |
51 | ntohl(saddr->a4) & __bits2mask32(sbits), | |
52 | 0); | |
53 | } | |
54 | ||
55 | static inline unsigned int __xfrm6_pref_hash(const xfrm_address_t *addr, | |
56 | __u8 prefixlen) | |
57 | { | |
d7f69466 AD |
58 | unsigned int pdw; |
59 | unsigned int pbi; | |
b58555f1 CG |
60 | u32 initval = 0; |
61 | ||
62 | pdw = prefixlen >> 5; /* num of whole u32 in prefix */ | |
63 | pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ | |
64 | ||
65 | if (pbi) { | |
66 | __be32 mask; | |
67 | ||
68 | mask = htonl((0xffffffff) << (32 - pbi)); | |
69 | ||
70 | initval = (__force u32)(addr->a6[pdw] & mask); | |
71 | } | |
72 | ||
73 | return jhash2((__force u32 *)addr->a6, pdw, initval); | |
74 | } | |
75 | ||
76 | static inline unsigned int __xfrm6_dpref_spref_hash(const xfrm_address_t *daddr, | |
77 | const xfrm_address_t *saddr, | |
78 | __u8 dbits, | |
79 | __u8 sbits) | |
80 | { | |
81 | return __xfrm6_pref_hash(daddr, dbits) ^ | |
82 | __xfrm6_pref_hash(saddr, sbits); | |
83 | } | |
84 | ||
5f803b58 DM |
85 | static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr, |
86 | const xfrm_address_t *saddr, | |
44e36b42 DM |
87 | u32 reqid, unsigned short family, |
88 | unsigned int hmask) | |
89 | { | |
90 | unsigned int h = family ^ reqid; | |
91 | switch (family) { | |
92 | case AF_INET: | |
93 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); | |
94 | break; | |
95 | case AF_INET6: | |
96 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); | |
97 | break; | |
98 | } | |
99 | return (h ^ (h >> 16)) & hmask; | |
100 | } | |
101 | ||
95c96174 ED |
102 | static inline unsigned int __xfrm_src_hash(const xfrm_address_t *daddr, |
103 | const xfrm_address_t *saddr, | |
104 | unsigned short family, | |
105 | unsigned int hmask) | |
44e36b42 DM |
106 | { |
107 | unsigned int h = family; | |
108 | switch (family) { | |
109 | case AF_INET: | |
667bbcb6 | 110 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); |
44e36b42 DM |
111 | break; |
112 | case AF_INET6: | |
667bbcb6 | 113 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); |
44e36b42 | 114 | break; |
ccbd6a5a | 115 | } |
44e36b42 DM |
116 | return (h ^ (h >> 16)) & hmask; |
117 | } | |
118 | ||
119 | static inline unsigned int | |
5f803b58 DM |
120 | __xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto, |
121 | unsigned short family, unsigned int hmask) | |
44e36b42 | 122 | { |
8122adf0 | 123 | unsigned int h = (__force u32)spi ^ proto; |
44e36b42 DM |
124 | switch (family) { |
125 | case AF_INET: | |
126 | h ^= __xfrm4_addr_hash(daddr); | |
127 | break; | |
128 | case AF_INET6: | |
129 | h ^= __xfrm6_addr_hash(daddr); | |
130 | break; | |
131 | } | |
132 | return (h ^ (h >> 10) ^ (h >> 20)) & hmask; | |
133 | } | |
134 | ||
135 | static inline unsigned int __idx_hash(u32 index, unsigned int hmask) | |
136 | { | |
137 | return (index ^ (index >> 8)) & hmask; | |
138 | } | |
139 | ||
5f803b58 | 140 | static inline unsigned int __sel_hash(const struct xfrm_selector *sel, |
b58555f1 CG |
141 | unsigned short family, unsigned int hmask, |
142 | u8 dbits, u8 sbits) | |
44e36b42 | 143 | { |
5f803b58 DM |
144 | const xfrm_address_t *daddr = &sel->daddr; |
145 | const xfrm_address_t *saddr = &sel->saddr; | |
44e36b42 DM |
146 | unsigned int h = 0; |
147 | ||
148 | switch (family) { | |
149 | case AF_INET: | |
b58555f1 CG |
150 | if (sel->prefixlen_d < dbits || |
151 | sel->prefixlen_s < sbits) | |
44e36b42 DM |
152 | return hmask + 1; |
153 | ||
b58555f1 | 154 | h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); |
44e36b42 DM |
155 | break; |
156 | ||
157 | case AF_INET6: | |
b58555f1 CG |
158 | if (sel->prefixlen_d < dbits || |
159 | sel->prefixlen_s < sbits) | |
44e36b42 DM |
160 | return hmask + 1; |
161 | ||
b58555f1 | 162 | h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); |
44e36b42 | 163 | break; |
ccbd6a5a | 164 | } |
44e36b42 DM |
165 | h ^= (h >> 16); |
166 | return h & hmask; | |
167 | } | |
168 | ||
5f803b58 DM |
169 | static inline unsigned int __addr_hash(const xfrm_address_t *daddr, |
170 | const xfrm_address_t *saddr, | |
b58555f1 CG |
171 | unsigned short family, |
172 | unsigned int hmask, | |
173 | u8 dbits, u8 sbits) | |
44e36b42 DM |
174 | { |
175 | unsigned int h = 0; | |
176 | ||
177 | switch (family) { | |
178 | case AF_INET: | |
b58555f1 | 179 | h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); |
44e36b42 DM |
180 | break; |
181 | ||
182 | case AF_INET6: | |
b58555f1 | 183 | h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); |
44e36b42 | 184 | break; |
ccbd6a5a | 185 | } |
44e36b42 DM |
186 | h ^= (h >> 16); |
187 | return h & hmask; | |
188 | } | |
189 | ||
c1b1203d JP |
190 | struct hlist_head *xfrm_hash_alloc(unsigned int sz); |
191 | void xfrm_hash_free(struct hlist_head *n, unsigned int sz); | |
44e36b42 DM |
192 | |
193 | #endif /* _XFRM_HASH_H */ |