1
2
3#ifndef _NFT_SET_PIPAPO_H
4
5#include <linux/log2.h>
6#include <net/ipv6.h>
7
8
9#define NFT_PIPAPO_MAX_FIELDS NFT_REG32_COUNT
10
11
12#define NFT_PIPAPO_MIN_FIELDS 2
13
14
15#define NFT_PIPAPO_MAX_BYTES (sizeof(struct in6_addr))
16#define NFT_PIPAPO_MAX_BITS (NFT_PIPAPO_MAX_BYTES * BITS_PER_BYTE)
17
18
19#define NFT_PIPAPO_GROUP_BITS_INIT NFT_PIPAPO_GROUP_BITS_SMALL_SET
20#define NFT_PIPAPO_GROUP_BITS_SMALL_SET 8
21#define NFT_PIPAPO_GROUP_BITS_LARGE_SET 4
22#define NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4 \
23 BUILD_BUG_ON((NFT_PIPAPO_GROUP_BITS_SMALL_SET != 8) || \
24 (NFT_PIPAPO_GROUP_BITS_LARGE_SET != 4))
25#define NFT_PIPAPO_GROUPS_PER_BYTE(f) (BITS_PER_BYTE / (f)->bb)
26
27
28
29
30
31
32
33
34
35
36#define NFT_PIPAPO_LT_SIZE_THRESHOLD (1 << 21)
37#define NFT_PIPAPO_LT_SIZE_HYSTERESIS (1 << 16)
38#define NFT_PIPAPO_LT_SIZE_HIGH NFT_PIPAPO_LT_SIZE_THRESHOLD
39#define NFT_PIPAPO_LT_SIZE_LOW NFT_PIPAPO_LT_SIZE_THRESHOLD - \
40 NFT_PIPAPO_LT_SIZE_HYSTERESIS
41
42
43#define NFT_PIPAPO_GROUPS_PADDED_SIZE(f) \
44 (round_up((f)->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f), sizeof(u32)))
45#define NFT_PIPAPO_GROUPS_PADDING(f) \
46 (NFT_PIPAPO_GROUPS_PADDED_SIZE(f) - (f)->groups / \
47 NFT_PIPAPO_GROUPS_PER_BYTE(f))
48
49
50#define NFT_PIPAPO_BUCKETS(bb) (1 << (bb))
51
52
53#define NFT_PIPAPO_MAP_NBITS (const_ilog2(NFT_PIPAPO_MAX_BITS * 2))
54
55
56
57
58#if BITS_PER_LONG == 64
59#define NFT_PIPAPO_MAP_TOBITS 32
60#else
61#define NFT_PIPAPO_MAP_TOBITS (BITS_PER_LONG - NFT_PIPAPO_MAP_NBITS)
62#endif
63
64
65#define NFT_PIPAPO_RULE0_MAX ((1UL << (NFT_PIPAPO_MAP_TOBITS - 1)) \
66 - (1UL << NFT_PIPAPO_MAP_NBITS))
67
68
69#ifdef NFT_PIPAPO_ALIGN
70#define NFT_PIPAPO_ALIGN_HEADROOM \
71 (NFT_PIPAPO_ALIGN - ARCH_KMALLOC_MINALIGN)
72#define NFT_PIPAPO_LT_ALIGN(lt) (PTR_ALIGN((lt), NFT_PIPAPO_ALIGN))
73#define NFT_PIPAPO_LT_ASSIGN(field, x) \
74 do { \
75 (field)->lt_aligned = NFT_PIPAPO_LT_ALIGN(x); \
76 (field)->lt = (x); \
77 } while (0)
78#else
79#define NFT_PIPAPO_ALIGN_HEADROOM 0
80#define NFT_PIPAPO_LT_ALIGN(lt) (lt)
81#define NFT_PIPAPO_LT_ASSIGN(field, x) ((field)->lt = (x))
82#endif
83
84#define nft_pipapo_for_each_field(field, index, match) \
85 for ((field) = (match)->f, (index) = 0; \
86 (index) < (match)->field_count; \
87 (index)++, (field)++)
88
89
90
91
92
93
94
95union nft_pipapo_map_bucket {
96 struct {
97#if BITS_PER_LONG == 64
98 static_assert(NFT_PIPAPO_MAP_TOBITS <= 32);
99 u32 to;
100
101 static_assert(NFT_PIPAPO_MAP_NBITS <= 32);
102 u32 n;
103#else
104 unsigned long to:NFT_PIPAPO_MAP_TOBITS;
105 unsigned long n:NFT_PIPAPO_MAP_NBITS;
106#endif
107 };
108 struct nft_pipapo_elem *e;
109};
110
111
112
113
114
115
116
117
118
119
120
121struct nft_pipapo_field {
122 int groups;
123 unsigned long rules;
124 size_t bsize;
125 int bb;
126#ifdef NFT_PIPAPO_ALIGN
127 unsigned long *lt_aligned;
128#endif
129 unsigned long *lt;
130 union nft_pipapo_map_bucket *mt;
131};
132
133
134
135
136
137
138
139
140
141
142struct nft_pipapo_match {
143 int field_count;
144#ifdef NFT_PIPAPO_ALIGN
145 unsigned long * __percpu *scratch_aligned;
146#endif
147 unsigned long * __percpu *scratch;
148 size_t bsize_max;
149 struct rcu_head rcu;
150 struct nft_pipapo_field f[];
151};
152
153
154
155
156
157
158
159
160
161struct nft_pipapo {
162 struct nft_pipapo_match __rcu *match;
163 struct nft_pipapo_match *clone;
164 int width;
165 bool dirty;
166 unsigned long last_gc;
167};
168
169struct nft_pipapo_elem;
170
171
172
173
174
175struct nft_pipapo_elem {
176 struct nft_set_ext ext;
177};
178
179int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
180 union nft_pipapo_map_bucket *mt, bool match_only);
181
182
183
184
185
186
187
188static inline void pipapo_and_field_buckets_4bit(struct nft_pipapo_field *f,
189 unsigned long *dst,
190 const u8 *data)
191{
192 unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
193 int group;
194
195 for (group = 0; group < f->groups; group += BITS_PER_BYTE / 4, data++) {
196 u8 v;
197
198 v = *data >> 4;
199 __bitmap_and(dst, dst, lt + v * f->bsize,
200 f->bsize * BITS_PER_LONG);
201 lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
202
203 v = *data & 0x0f;
204 __bitmap_and(dst, dst, lt + v * f->bsize,
205 f->bsize * BITS_PER_LONG);
206 lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
207 }
208}
209
210
211
212
213
214
215
216static inline void pipapo_and_field_buckets_8bit(struct nft_pipapo_field *f,
217 unsigned long *dst,
218 const u8 *data)
219{
220 unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
221 int group;
222
223 for (group = 0; group < f->groups; group++, data++) {
224 __bitmap_and(dst, dst, lt + *data * f->bsize,
225 f->bsize * BITS_PER_LONG);
226 lt += f->bsize * NFT_PIPAPO_BUCKETS(8);
227 }
228}
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245static u64 pipapo_estimate_size(const struct nft_set_desc *desc)
246{
247 unsigned long entry_size;
248 u64 size;
249 int i;
250
251 for (i = 0, entry_size = 0; i < desc->field_count; i++) {
252 unsigned long rules;
253
254 if (desc->field_len[i] > NFT_PIPAPO_MAX_BYTES)
255 return 0;
256
257
258
259
260
261 rules = ilog2(desc->field_len[i] * BITS_PER_BYTE) * 2;
262 entry_size += rules *
263 NFT_PIPAPO_BUCKETS(NFT_PIPAPO_GROUP_BITS_INIT) /
264 BITS_PER_BYTE;
265 entry_size += rules * sizeof(union nft_pipapo_map_bucket);
266 }
267
268
269 size = desc->size * entry_size;
270 if (size && div_u64(size, desc->size) != entry_size)
271 return 0;
272
273 size += sizeof(struct nft_pipapo) + sizeof(struct nft_pipapo_match) * 2;
274
275 size += sizeof(struct nft_pipapo_field) * desc->field_count;
276
277 return size;
278}
279
280#endif
281