0001
0002
0003 #ifndef _NFT_SET_PIPAPO_H
0004
0005 #include <linux/log2.h>
0006 #include <net/ipv6.h> /* For the maximum length of a field */
0007
0008
0009 #define NFT_PIPAPO_MAX_FIELDS NFT_REG32_COUNT
0010
0011
0012 #define NFT_PIPAPO_MIN_FIELDS 2
0013
0014
0015 #define NFT_PIPAPO_MAX_BYTES (sizeof(struct in6_addr))
0016 #define NFT_PIPAPO_MAX_BITS (NFT_PIPAPO_MAX_BYTES * BITS_PER_BYTE)
0017
0018
0019 #define NFT_PIPAPO_GROUP_BITS_INIT NFT_PIPAPO_GROUP_BITS_SMALL_SET
0020 #define NFT_PIPAPO_GROUP_BITS_SMALL_SET 8
0021 #define NFT_PIPAPO_GROUP_BITS_LARGE_SET 4
0022 #define NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4 \
0023 BUILD_BUG_ON((NFT_PIPAPO_GROUP_BITS_SMALL_SET != 8) || \
0024 (NFT_PIPAPO_GROUP_BITS_LARGE_SET != 4))
0025 #define NFT_PIPAPO_GROUPS_PER_BYTE(f) (BITS_PER_BYTE / (f)->bb)
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #define NFT_PIPAPO_LT_SIZE_THRESHOLD (1 << 21)
0037 #define NFT_PIPAPO_LT_SIZE_HYSTERESIS (1 << 16)
0038 #define NFT_PIPAPO_LT_SIZE_HIGH NFT_PIPAPO_LT_SIZE_THRESHOLD
0039 #define NFT_PIPAPO_LT_SIZE_LOW NFT_PIPAPO_LT_SIZE_THRESHOLD - \
0040 NFT_PIPAPO_LT_SIZE_HYSTERESIS
0041
0042
0043 #define NFT_PIPAPO_GROUPS_PADDED_SIZE(f) \
0044 (round_up((f)->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f), sizeof(u32)))
0045 #define NFT_PIPAPO_GROUPS_PADDING(f) \
0046 (NFT_PIPAPO_GROUPS_PADDED_SIZE(f) - (f)->groups / \
0047 NFT_PIPAPO_GROUPS_PER_BYTE(f))
0048
0049
0050 #define NFT_PIPAPO_BUCKETS(bb) (1 << (bb))
0051
0052
0053 #define NFT_PIPAPO_MAP_NBITS (const_ilog2(NFT_PIPAPO_MAX_BITS * 2))
0054
0055
0056
0057
0058 #if BITS_PER_LONG == 64
0059 #define NFT_PIPAPO_MAP_TOBITS 32
0060 #else
0061 #define NFT_PIPAPO_MAP_TOBITS (BITS_PER_LONG - NFT_PIPAPO_MAP_NBITS)
0062 #endif
0063
0064
0065 #define NFT_PIPAPO_RULE0_MAX ((1UL << (NFT_PIPAPO_MAP_TOBITS - 1)) \
0066 - (1UL << NFT_PIPAPO_MAP_NBITS))
0067
0068
0069 #ifdef NFT_PIPAPO_ALIGN
0070 #define NFT_PIPAPO_ALIGN_HEADROOM \
0071 (NFT_PIPAPO_ALIGN - ARCH_KMALLOC_MINALIGN)
0072 #define NFT_PIPAPO_LT_ALIGN(lt) (PTR_ALIGN((lt), NFT_PIPAPO_ALIGN))
0073 #define NFT_PIPAPO_LT_ASSIGN(field, x) \
0074 do { \
0075 (field)->lt_aligned = NFT_PIPAPO_LT_ALIGN(x); \
0076 (field)->lt = (x); \
0077 } while (0)
0078 #else
0079 #define NFT_PIPAPO_ALIGN_HEADROOM 0
0080 #define NFT_PIPAPO_LT_ALIGN(lt) (lt)
0081 #define NFT_PIPAPO_LT_ASSIGN(field, x) ((field)->lt = (x))
0082 #endif
0083
0084 #define nft_pipapo_for_each_field(field, index, match) \
0085 for ((field) = (match)->f, (index) = 0; \
0086 (index) < (match)->field_count; \
0087 (index)++, (field)++)
0088
0089
0090
0091
0092
0093
0094
0095 union nft_pipapo_map_bucket {
0096 struct {
0097 #if BITS_PER_LONG == 64
0098 static_assert(NFT_PIPAPO_MAP_TOBITS <= 32);
0099 u32 to;
0100
0101 static_assert(NFT_PIPAPO_MAP_NBITS <= 32);
0102 u32 n;
0103 #else
0104 unsigned long to:NFT_PIPAPO_MAP_TOBITS;
0105 unsigned long n:NFT_PIPAPO_MAP_NBITS;
0106 #endif
0107 };
0108 struct nft_pipapo_elem *e;
0109 };
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 struct nft_pipapo_field {
0122 int groups;
0123 unsigned long rules;
0124 size_t bsize;
0125 int bb;
0126 #ifdef NFT_PIPAPO_ALIGN
0127 unsigned long *lt_aligned;
0128 #endif
0129 unsigned long *lt;
0130 union nft_pipapo_map_bucket *mt;
0131 };
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 struct nft_pipapo_match {
0143 int field_count;
0144 #ifdef NFT_PIPAPO_ALIGN
0145 unsigned long * __percpu *scratch_aligned;
0146 #endif
0147 unsigned long * __percpu *scratch;
0148 size_t bsize_max;
0149 struct rcu_head rcu;
0150 struct nft_pipapo_field f[];
0151 };
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 struct nft_pipapo {
0162 struct nft_pipapo_match __rcu *match;
0163 struct nft_pipapo_match *clone;
0164 int width;
0165 bool dirty;
0166 unsigned long last_gc;
0167 };
0168
0169 struct nft_pipapo_elem;
0170
0171
0172
0173
0174
0175 struct nft_pipapo_elem {
0176 struct nft_set_ext ext;
0177 };
0178
0179 int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
0180 union nft_pipapo_map_bucket *mt, bool match_only);
0181
0182
0183
0184
0185
0186
0187
0188 static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f,
0189 unsigned long *dst,
0190 const u8 *data)
0191 {
0192 unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
0193 int group;
0194
0195 for (group = 0; group < f->groups; group += BITS_PER_BYTE / 4, data++) {
0196 u8 v;
0197
0198 v = *data >> 4;
0199 __bitmap_and(dst, dst, lt + v * f->bsize,
0200 f->bsize * BITS_PER_LONG);
0201 lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
0202
0203 v = *data & 0x0f;
0204 __bitmap_and(dst, dst, lt + v * f->bsize,
0205 f->bsize * BITS_PER_LONG);
0206 lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
0207 }
0208 }
0209
0210
0211
0212
0213
0214
0215
0216 static inline void pipapo_and_field_buckets_8bit(struct nft_pipapo_field *f,
0217 unsigned long *dst,
0218 const u8 *data)
0219 {
0220 unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
0221 int group;
0222
0223 for (group = 0; group < f->groups; group++, data++) {
0224 __bitmap_and(dst, dst, lt + *data * f->bsize,
0225 f->bsize * BITS_PER_LONG);
0226 lt += f->bsize * NFT_PIPAPO_BUCKETS(8);
0227 }
0228 }
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 static u64 pipapo_estimate_size(const struct nft_set_desc *desc)
0246 {
0247 unsigned long entry_size;
0248 u64 size;
0249 int i;
0250
0251 for (i = 0, entry_size = 0; i < desc->field_count; i++) {
0252 unsigned long rules;
0253
0254 if (desc->field_len[i] > NFT_PIPAPO_MAX_BYTES)
0255 return 0;
0256
0257
0258
0259
0260
0261 rules = ilog2(desc->field_len[i] * BITS_PER_BYTE) * 2;
0262 entry_size += rules *
0263 NFT_PIPAPO_BUCKETS(NFT_PIPAPO_GROUP_BITS_INIT) /
0264 BITS_PER_BYTE;
0265 entry_size += rules * sizeof(union nft_pipapo_map_bucket);
0266 }
0267
0268
0269 size = desc->size * entry_size;
0270 if (size && div_u64(size, desc->size) != entry_size)
0271 return 0;
0272
0273 size += sizeof(struct nft_pipapo) + sizeof(struct nft_pipapo_match) * 2;
0274
0275 size += sizeof(struct nft_pipapo_field) * desc->field_count;
0276
0277 return size;
0278 }
0279
0280 #endif