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