1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _XFRM_HASH_H 3 #define _XFRM_HASH_H 4 5 #include <linux/xfrm.h> 6 #include <linux/socket.h> 7 #include <linux/jhash.h> 8 9 static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) 10 { 11 return ntohl(addr->a4); 12 } 13 14 static inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr) 15 { 16 return ntohl(addr->a6[2] ^ addr->a6[3]); 17 } 18 19 static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, 20 const xfrm_address_t *saddr) 21 { 22 u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4; 23 return ntohl((__force __be32)sum); 24 } 25 26 static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr, 27 const xfrm_address_t *saddr) 28 { 29 return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ 30 saddr->a6[2] ^ saddr->a6[3]); 31 } 32 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 { 58 unsigned int pdw; 59 unsigned int pbi; 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 85 static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr, 86 const xfrm_address_t *saddr, 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 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) 106 { 107 unsigned int h = family; 108 switch (family) { 109 case AF_INET: 110 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); 111 break; 112 case AF_INET6: 113 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); 114 break; 115 } 116 return (h ^ (h >> 16)) & hmask; 117 } 118 119 static inline unsigned int 120 __xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto, 121 unsigned short family, unsigned int hmask) 122 { 123 unsigned int h = (__force u32)spi ^ proto; 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 140 static inline unsigned int __sel_hash(const struct xfrm_selector *sel, 141 unsigned short family, unsigned int hmask, 142 u8 dbits, u8 sbits) 143 { 144 const xfrm_address_t *daddr = &sel->daddr; 145 const xfrm_address_t *saddr = &sel->saddr; 146 unsigned int h = 0; 147 148 switch (family) { 149 case AF_INET: 150 if (sel->prefixlen_d < dbits || 151 sel->prefixlen_s < sbits) 152 return hmask + 1; 153 154 h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); 155 break; 156 157 case AF_INET6: 158 if (sel->prefixlen_d < dbits || 159 sel->prefixlen_s < sbits) 160 return hmask + 1; 161 162 h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); 163 break; 164 } 165 h ^= (h >> 16); 166 return h & hmask; 167 } 168 169 static inline unsigned int __addr_hash(const xfrm_address_t *daddr, 170 const xfrm_address_t *saddr, 171 unsigned short family, 172 unsigned int hmask, 173 u8 dbits, u8 sbits) 174 { 175 unsigned int h = 0; 176 177 switch (family) { 178 case AF_INET: 179 h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); 180 break; 181 182 case AF_INET6: 183 h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); 184 break; 185 } 186 h ^= (h >> 16); 187 return h & hmask; 188 } 189 190 struct hlist_head *xfrm_hash_alloc(unsigned int sz); 191 void xfrm_hash_free(struct hlist_head *n, unsigned int sz); 192 193 #endif /* _XFRM_HASH_H */ 194