File Index
Files and directories
Sign in
FILE

nft_set_pipapo.h

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_set_pipapo.h C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#ifndef _NFT_SET_PIPAPO_H
  4
  5#include <linux/log2.h>
  6#include <net/ipv6.h>			/* For the maximum length of a field */
  7
  8/* Count of concatenated fields depends on count of 32-bit nftables registers */
  9#define NFT_PIPAPO_MAX_FIELDS		NFT_REG32_COUNT
 10
 11/* Restrict usage to multiple fields, make sure rbtree is used otherwise */
 12#define NFT_PIPAPO_MIN_FIELDS		2
 13
 14/* Largest supported field size */
 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/* Bits to be grouped together in table buckets depending on set size */
 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/* If a lookup table gets bigger than NFT_PIPAPO_LT_SIZE_HIGH, switch to the
 28 * small group width, and switch to the big group width if the table gets
 29 * smaller than NFT_PIPAPO_LT_SIZE_LOW.
 30 *
 31 * Picking 2MiB as threshold (for a single table) avoids as much as possible
 32 * crossing page boundaries on most architectures (x86-64 and MIPS huge pages,
 33 * ARMv7 supersections, POWER "large" pages, SPARC Level 1 regions, etc.), which
 34 * keeps performance nice in case kvmalloc() gives us non-contiguous areas.
 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/* Fields are padded to 32 bits in input registers */
 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/* Number of buckets given by 2 ^ n, with n bucket bits */
 50#define NFT_PIPAPO_BUCKETS(bb)		(1 << (bb))
 51
 52/* Each n-bit range maps to up to n * 2 rules */
 53#define NFT_PIPAPO_MAP_NBITS		(const_ilog2(NFT_PIPAPO_MAX_BITS * 2))
 54
 55/* Use the rest of mapping table buckets for rule indices, but it makes no sense
 56 * to exceed 32 bits
 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/* ...which gives us the highest allowed index for a rule */
 65#define NFT_PIPAPO_RULE0_MAX		((1UL << (NFT_PIPAPO_MAP_TOBITS - 1)) \
 66					- (1UL << NFT_PIPAPO_MAP_NBITS))
 67
 68/* Definitions for vectorised implementations */
 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#else
 74#define NFT_PIPAPO_ALIGN_HEADROOM	0
 75#define NFT_PIPAPO_LT_ALIGN(lt)		(lt)
 76#endif /* NFT_PIPAPO_ALIGN */
 77
 78#define nft_pipapo_for_each_field(field, index, match)		\
 79	for ((field) = (match)->f, (index) = 0;			\
 80	     (index) < (match)->field_count;			\
 81	     (index)++, (field)++)
 82
 83/**
 84 * union nft_pipapo_map_bucket - Bucket of mapping table
 85 * @to:		First rule number (in next field) this rule maps to
 86 * @n:		Number of rules (in next field) this rule maps to
 87 * @e:		If there's no next field, pointer to element this rule maps to
 88 */
 89union nft_pipapo_map_bucket {
 90	struct {
 91#if BITS_PER_LONG == 64
 92		static_assert(NFT_PIPAPO_MAP_TOBITS <= 32);
 93		u32 to;
 94
 95		static_assert(NFT_PIPAPO_MAP_NBITS <= 32);
 96		u32 n;
 97#else
 98		unsigned long to:NFT_PIPAPO_MAP_TOBITS;
 99		unsigned long  n:NFT_PIPAPO_MAP_NBITS;
100#endif
101	};
102	struct nft_pipapo_elem *e;
103};
104
105/**
106 * struct nft_pipapo_field - Lookup, mapping tables and related data for a field
107 * @rules:	Number of inserted rules
108 * @bsize:	Size of each bucket in lookup table, in longs
109 * @rules_alloc: Number of allocated rules, always >= rules
110 * @groups:	Amount of bit groups
111 * @bb:		Number of bits grouped together in lookup table buckets
112 * @lt:		Lookup table: 'groups' rows of buckets
113 * @mt:		Mapping table: one bucket per rule
114 */
115struct nft_pipapo_field {
116	unsigned int rules;
117	unsigned int bsize;
118	unsigned int rules_alloc;
119	u8 groups;
120	u8 bb;
121	unsigned long *lt;
122	union nft_pipapo_map_bucket *mt;
123};
124
125/**
126 * struct nft_pipapo_scratch - percpu data used for lookup and matching
127 * @bh_lock:    PREEMPT_RT local spinlock
128 * @map_index:	Current working bitmap index, toggled between field matches
129 * @__map:	store partial matching results during lookup
130 */
131struct nft_pipapo_scratch {
132	local_lock_t bh_lock;
133	u8 map_index;
134	unsigned long __map[];
135};
136
137/**
138 * struct nft_pipapo_match - Data used for lookup and matching
139 * @field_count:	Amount of fields in set
140 * @bsize_max:		Maximum lookup table bucket size of all fields, in longs
141 * @scratch:		Preallocated per-CPU maps for partial matching results
142 * @rcu:		Matching data is swapped on commits
143 * @f:			Fields, with lookup and mapping tables
144 */
145struct nft_pipapo_match {
146	u8 field_count;
147	unsigned int bsize_max;
148	struct nft_pipapo_scratch * __percpu *scratch;
149	struct rcu_head rcu;
150	struct nft_pipapo_field f[] __counted_by(field_count);
151};
152
153/**
154 * struct nft_pipapo - Representation of a set
155 * @match:	Currently in-use matching data
156 * @clone:	Copy where pending insertions and deletions are kept
157 * @width:	Total bytes to be matched for one packet, including padding
158 * @last_gc:	Timestamp of last garbage collection run, jiffies
159 * @gc_head:	list of nft_trans_gc to queue up for mem reclaim
160 */
161struct nft_pipapo {
162	struct nft_pipapo_match __rcu *match;
163	struct nft_pipapo_match *clone;
164	int width;
165	unsigned long last_gc;
166	struct list_head gc_head;
167};
168
169struct nft_pipapo_elem;
170
171/**
172 * struct nft_pipapo_elem - API-facing representation of single set element
173 * @priv:	element placeholder
174 * @ext:	nftables API extensions
175 */
176struct nft_pipapo_elem {
177	struct nft_elem_priv	priv;
178	struct nft_set_ext	ext;
179};
180
181int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules,
182		  unsigned long *dst,
183		  const union nft_pipapo_map_bucket *mt, bool match_only);
184
185/**
186 * pipapo_and_field_buckets_4bit() - Intersect 4-bit buckets
187 * @f:		Field including lookup table
188 * @dst:	Area to store result
189 * @data:	Input data selecting table buckets
190 */
191static inline void pipapo_and_field_buckets_4bit(const struct nft_pipapo_field *f,
192						 unsigned long *dst,
193						 const u8 *data)
194{
195	unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
196	int group;
197
198	for (group = 0; group < f->groups; group += BITS_PER_BYTE / 4, data++) {
199		u8 v;
200
201		v = *data >> 4;
202		__bitmap_and(dst, dst, lt + v * f->bsize,
203			     f->bsize * BITS_PER_LONG);
204		lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
205
206		v = *data & 0x0f;
207		__bitmap_and(dst, dst, lt + v * f->bsize,
208			     f->bsize * BITS_PER_LONG);
209		lt += f->bsize * NFT_PIPAPO_BUCKETS(4);
210	}
211}
212
213/**
214 * pipapo_and_field_buckets_8bit() - Intersect 8-bit buckets
215 * @f:		Field including lookup table
216 * @dst:	Area to store result
217 * @data:	Input data selecting table buckets
218 */
219static inline void pipapo_and_field_buckets_8bit(const struct nft_pipapo_field *f,
220						 unsigned long *dst,
221						 const u8 *data)
222{
223	unsigned long *lt = NFT_PIPAPO_LT_ALIGN(f->lt);
224	int group;
225
226	for (group = 0; group < f->groups; group++, data++) {
227		__bitmap_and(dst, dst, lt + *data * f->bsize,
228			     f->bsize * BITS_PER_LONG);
229		lt += f->bsize * NFT_PIPAPO_BUCKETS(8);
230	}
231}
232
233/**
234 * pipapo_estimate_size() - Estimate worst-case for set size
235 * @desc:	Set description, element count and field description used here
236 *
237 * The size for this set type can vary dramatically, as it depends on the number
238 * of rules (composing netmasks) the entries expand to. We compute the worst
239 * case here.
240 *
241 * In general, for a non-ranged entry or a single composing netmask, we need
242 * one bit in each of the sixteen NFT_PIPAPO_BUCKETS, for each 4-bit group (that
243 * is, each input bit needs four bits of matching data), plus a bucket in the
244 * mapping table for each field.
245 *
246 * Return: worst-case set size in bytes, 0 on any overflow
247 */
248static u64 pipapo_estimate_size(const struct nft_set_desc *desc)
249{
250	unsigned long entry_size;
251	u64 size;
252	int i;
253
254	for (i = 0, entry_size = 0; i < desc->field_count; i++) {
255		unsigned long rules;
256
257		if (desc->field_len[i] > NFT_PIPAPO_MAX_BYTES)
258			return 0;
259
260		/* Worst-case ranges for each concatenated field: each n-bit
261		 * field can expand to up to n * 2 rules in each bucket, and
262		 * each rule also needs a mapping bucket.
263		 */
264		rules = ilog2(desc->field_len[i] * BITS_PER_BYTE) * 2;
265		entry_size += rules *
266			      NFT_PIPAPO_BUCKETS(NFT_PIPAPO_GROUP_BITS_INIT) /
267			      BITS_PER_BYTE;
268		entry_size += rules * sizeof(union nft_pipapo_map_bucket);
269	}
270
271	/* Rules in lookup and mapping tables are needed for each entry */
272	size = desc->size * entry_size;
273	if (size && div_u64(size, desc->size) != entry_size)
274		return 0;
275
276	size += sizeof(struct nft_pipapo) + sizeof(struct nft_pipapo_match) * 2;
277
278	size += sizeof(struct nft_pipapo_field) * desc->field_count;
279
280	return size;
281}
282
283/**
284 * pipapo_resmap_init() - Initialise result map before first use
285 * @m:		Matching data, including mapping table
286 * @res_map:	Result map
287 *
288 * Initialize all bits covered by the first field to one, so that after
289 * the first step, only the matching bits of the first bit group remain.
290 *
291 * If other fields have a large bitmap, set remainder of res_map to 0.
292 */
293static inline void pipapo_resmap_init(const struct nft_pipapo_match *m, unsigned long *res_map)
294{
295	const struct nft_pipapo_field *f = m->f;
296	int i;
297
298	for (i = 0; i < f->bsize; i++)
299		res_map[i] = ULONG_MAX;
300
301	for (i = f->bsize; i < m->bsize_max; i++)
302		res_map[i] = 0ul;
303}
304#endif /* _NFT_SET_PIPAPO_H */
~/ Read-only file preview.