~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/nft_set_pipapo_avx2.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 
  3 /* PIPAPO: PIle PAcket POlicies: AVX2 packet lookup routines
  4  *
  5  * Copyright (c) 2019-2020 Red Hat GmbH
  6  *
  7  * Author: Stefano Brivio <sbrivio@redhat.com>
  8  */
  9 
 10 #include <linux/kernel.h>
 11 #include <linux/init.h>
 12 #include <linux/module.h>
 13 #include <linux/netlink.h>
 14 #include <linux/netfilter.h>
 15 #include <linux/netfilter/nf_tables.h>
 16 #include <net/netfilter/nf_tables_core.h>
 17 #include <uapi/linux/netfilter/nf_tables.h>
 18 #include <linux/bitmap.h>
 19 #include <linux/bitops.h>
 20 
 21 #include <linux/compiler.h>
 22 #include <asm/fpu/api.h>
 23 
 24 #include "nft_set_pipapo_avx2.h"
 25 #include "nft_set_pipapo.h"
 26 
 27 #define NFT_PIPAPO_LONGS_PER_M256       (XSAVE_YMM_SIZE / BITS_PER_LONG)
 28 
 29 /* Load from memory into YMM register with non-temporal hint ("stream load"),
 30  * that is, don't fetch lines from memory into the cache. This avoids pushing
 31  * precious packet data out of the cache hierarchy, and is appropriate when:
 32  *
 33  * - loading buckets from lookup tables, as they are not going to be used
 34  *   again before packets are entirely classified
 35  *
 36  * - loading the result bitmap from the previous field, as it's never used
 37  *   again
 38  */
 39 #define NFT_PIPAPO_AVX2_LOAD(reg, loc)                                  \
 40         asm volatile("vmovntdqa %0, %%ymm" #reg : : "m" (loc))
 41 
 42 /* Stream a single lookup table bucket into YMM register given lookup table,
 43  * group index, value of packet bits, bucket size.
 44  */
 45 #define NFT_PIPAPO_AVX2_BUCKET_LOAD4(reg, lt, group, v, bsize)          \
 46         NFT_PIPAPO_AVX2_LOAD(reg,                                       \
 47                              lt[((group) * NFT_PIPAPO_BUCKETS(4) +      \
 48                                  (v)) * (bsize)])
 49 #define NFT_PIPAPO_AVX2_BUCKET_LOAD8(reg, lt, group, v, bsize)          \
 50         NFT_PIPAPO_AVX2_LOAD(reg,                                       \
 51                              lt[((group) * NFT_PIPAPO_BUCKETS(8) +      \
 52                                  (v)) * (bsize)])
 53 
 54 /* Bitwise AND: the staple operation of this algorithm */
 55 #define NFT_PIPAPO_AVX2_AND(dst, a, b)                                  \
 56         asm volatile("vpand %ymm" #a ", %ymm" #b ", %ymm" #dst)
 57 
 58 /* Jump to label if @reg is zero */
 59 #define NFT_PIPAPO_AVX2_NOMATCH_GOTO(reg, label)                        \
 60         asm goto("vptest %%ymm" #reg ", %%ymm" #reg ";" \
 61                           "je %l[" #label "]" : : : : label)
 62 
 63 /* Store 256 bits from YMM register into memory. Contrary to bucket load
 64  * operation, we don't bypass the cache here, as stored matching results
 65  * are always used shortly after.
 66  */
 67 #define NFT_PIPAPO_AVX2_STORE(loc, reg)                                 \
 68         asm volatile("vmovdqa %%ymm" #reg ", %0" : "=m" (loc))
 69 
 70 /* Zero out a complete YMM register, @reg */
 71 #define NFT_PIPAPO_AVX2_ZERO(reg)                                       \
 72         asm volatile("vpxor %ymm" #reg ", %ymm" #reg ", %ymm" #reg)
 73 
 74 /**
 75  * nft_pipapo_avx2_prepare() - Prepare before main algorithm body
 76  *
 77  * This zeroes out ymm15, which is later used whenever we need to clear a
 78  * memory location, by storing its content into memory.
 79  */
 80 static void nft_pipapo_avx2_prepare(void)
 81 {
 82         NFT_PIPAPO_AVX2_ZERO(15);
 83 }
 84 
 85 /**
 86  * nft_pipapo_avx2_fill() - Fill a bitmap region with ones
 87  * @data:       Base memory area
 88  * @start:      First bit to set
 89  * @len:        Count of bits to fill
 90  *
 91  * This is nothing else than a version of bitmap_set(), as used e.g. by
 92  * pipapo_refill(), tailored for the microarchitectures using it and better
 93  * suited for the specific usage: it's very likely that we'll set a small number
 94  * of bits, not crossing a word boundary, and correct branch prediction is
 95  * critical here.
 96  *
 97  * This function doesn't actually use any AVX2 instruction.
 98  */
 99 static void nft_pipapo_avx2_fill(unsigned long *data, int start, int len)
100 {
101         int offset = start % BITS_PER_LONG;
102         unsigned long mask;
103 
104         data += start / BITS_PER_LONG;
105 
106         if (likely(len == 1)) {
107                 *data |= BIT(offset);
108                 return;
109         }
110 
111         if (likely(len < BITS_PER_LONG || offset)) {
112                 if (likely(len + offset <= BITS_PER_LONG)) {
113                         *data |= GENMASK(len - 1 + offset, offset);
114                         return;
115                 }
116 
117                 *data |= ~0UL << offset;
118                 len -= BITS_PER_LONG - offset;
119                 data++;
120 
121                 if (len <= BITS_PER_LONG) {
122                         mask = ~0UL >> (BITS_PER_LONG - len);
123                         *data |= mask;
124                         return;
125                 }
126         }
127 
128         memset(data, 0xff, len / BITS_PER_BYTE);
129         data += len / BITS_PER_LONG;
130 
131         len %= BITS_PER_LONG;
132         if (len)
133                 *data |= ~0UL >> (BITS_PER_LONG - len);
134 }
135 
136 /**
137  * nft_pipapo_avx2_refill() - Scan bitmap, select mapping table item, set bits
138  * @offset:     Start from given bitmap (equivalent to bucket) offset, in longs
139  * @map:        Bitmap to be scanned for set bits
140  * @dst:        Destination bitmap
141  * @mt:         Mapping table containing bit set specifiers
142  * @last:       Return index of first set bit, if this is the last field
143  *
144  * This is an alternative implementation of pipapo_refill() suitable for usage
145  * with AVX2 lookup routines: we know there are four words to be scanned, at
146  * a given offset inside the map, for each matching iteration.
147  *
148  * This function doesn't actually use any AVX2 instruction.
149  *
150  * Return: first set bit index if @last, index of first filled word otherwise.
151  */
152 static int nft_pipapo_avx2_refill(int offset, unsigned long *map,
153                                   unsigned long *dst,
154                                   union nft_pipapo_map_bucket *mt, bool last)
155 {
156         int ret = -1;
157 
158 #define NFT_PIPAPO_AVX2_REFILL_ONE_WORD(x)                              \
159         do {                                                            \
160                 while (map[(x)]) {                                      \
161                         int r = __builtin_ctzl(map[(x)]);               \
162                         int i = (offset + (x)) * BITS_PER_LONG + r;     \
163                                                                         \
164                         if (last)                                       \
165                                 return i;                               \
166                                                                         \
167                         nft_pipapo_avx2_fill(dst, mt[i].to, mt[i].n);   \
168                                                                         \
169                         if (ret == -1)                                  \
170                                 ret = mt[i].to;                         \
171                                                                         \
172                         map[(x)] &= ~(1UL << r);                        \
173                 }                                                       \
174         } while (0)
175 
176         NFT_PIPAPO_AVX2_REFILL_ONE_WORD(0);
177         NFT_PIPAPO_AVX2_REFILL_ONE_WORD(1);
178         NFT_PIPAPO_AVX2_REFILL_ONE_WORD(2);
179         NFT_PIPAPO_AVX2_REFILL_ONE_WORD(3);
180 #undef NFT_PIPAPO_AVX2_REFILL_ONE_WORD
181 
182         return ret;
183 }
184 
185 /**
186  * nft_pipapo_avx2_lookup_4b_2() - AVX2-based lookup for 2 four-bit groups
187  * @map:        Previous match result, used as initial bitmap
188  * @fill:       Destination bitmap to be filled with current match result
189  * @f:          Field, containing lookup and mapping tables
190  * @offset:     Ignore buckets before the given index, no bits are filled there
191  * @pkt:        Packet data, pointer to input nftables register
192  * @first:      If this is the first field, don't source previous result
193  * @last:       Last field: stop at the first match and return bit index
194  *
195  * Load buckets from lookup table corresponding to the values of each 4-bit
196  * group of packet bytes, and perform a bitwise intersection between them. If
197  * this is the first field in the set, simply AND the buckets together
198  * (equivalent to using an all-ones starting bitmap), use the provided starting
199  * bitmap otherwise. Then call nft_pipapo_avx2_refill() to generate the next
200  * working bitmap, @fill.
201  *
202  * This is used for 8-bit fields (i.e. protocol numbers).
203  *
204  * Out-of-order (and superscalar) execution is vital here, so it's critical to
205  * avoid false data dependencies. CPU and compiler could (mostly) take care of
206  * this on their own, but the operation ordering is explicitly given here with
207  * a likely execution order in mind, to highlight possible stalls. That's why
208  * a number of logically distinct operations (i.e. loading buckets, intersecting
209  * buckets) are interleaved.
210  *
211  * Return: -1 on no match, rule index of match if @last, otherwise first long
212  * word index to be checked next (i.e. first filled word).
213  */
214 static int nft_pipapo_avx2_lookup_4b_2(unsigned long *map, unsigned long *fill,
215                                        const struct nft_pipapo_field *f,
216                                        int offset, const u8 *pkt,
217                                        bool first, bool last)
218 {
219         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
220         u8 pg[2] = { pkt[0] >> 4, pkt[0] & 0xf };
221         unsigned long *lt = f->lt, bsize = f->bsize;
222 
223         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
224         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
225                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
226 
227                 if (first) {
228                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0, lt, 0, pg[0], bsize);
229                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(1, lt, 1, pg[1], bsize);
230                         NFT_PIPAPO_AVX2_AND(4, 0, 1);
231                 } else {
232                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0, lt, 0, pg[0], bsize);
233                         NFT_PIPAPO_AVX2_LOAD(2, map[i_ul]);
234                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(1, lt, 1, pg[1], bsize);
235                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(2, nothing);
236                         NFT_PIPAPO_AVX2_AND(3, 0, 1);
237                         NFT_PIPAPO_AVX2_AND(4, 2, 3);
238                 }
239 
240                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(4, nomatch);
241                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 4);
242 
243                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
244                 if (last)
245                         return b;
246 
247                 if (unlikely(ret == -1))
248                         ret = b / XSAVE_YMM_SIZE;
249 
250                 continue;
251 nomatch:
252                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
253 nothing:
254                 ;
255         }
256 
257         return ret;
258 }
259 
260 /**
261  * nft_pipapo_avx2_lookup_4b_4() - AVX2-based lookup for 4 four-bit groups
262  * @map:        Previous match result, used as initial bitmap
263  * @fill:       Destination bitmap to be filled with current match result
264  * @f:          Field, containing lookup and mapping tables
265  * @offset:     Ignore buckets before the given index, no bits are filled there
266  * @pkt:        Packet data, pointer to input nftables register
267  * @first:      If this is the first field, don't source previous result
268  * @last:       Last field: stop at the first match and return bit index
269  *
270  * See nft_pipapo_avx2_lookup_4b_2().
271  *
272  * This is used for 16-bit fields (i.e. ports).
273  *
274  * Return: -1 on no match, rule index of match if @last, otherwise first long
275  * word index to be checked next (i.e. first filled word).
276  */
277 static int nft_pipapo_avx2_lookup_4b_4(unsigned long *map, unsigned long *fill,
278                                        const struct nft_pipapo_field *f,
279                                        int offset, const u8 *pkt,
280                                        bool first, bool last)
281 {
282         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
283         u8 pg[4] = { pkt[0] >> 4, pkt[0] & 0xf, pkt[1] >> 4, pkt[1] & 0xf };
284         unsigned long *lt = f->lt, bsize = f->bsize;
285 
286         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
287         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
288                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
289 
290                 if (first) {
291                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0, lt, 0, pg[0], bsize);
292                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(1, lt, 1, pg[1], bsize);
293                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(2, lt, 2, pg[2], bsize);
294                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(3, lt, 3, pg[3], bsize);
295                         NFT_PIPAPO_AVX2_AND(4, 0, 1);
296                         NFT_PIPAPO_AVX2_AND(5, 2, 3);
297                         NFT_PIPAPO_AVX2_AND(7, 4, 5);
298                 } else {
299                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0, lt, 0, pg[0], bsize);
300 
301                         NFT_PIPAPO_AVX2_LOAD(1, map[i_ul]);
302 
303                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(2, lt, 1, pg[1], bsize);
304                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(3, lt, 2, pg[2], bsize);
305                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(4, lt, 3, pg[3], bsize);
306                         NFT_PIPAPO_AVX2_AND(5, 0, 1);
307 
308                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nothing);
309 
310                         NFT_PIPAPO_AVX2_AND(6, 2, 3);
311                         NFT_PIPAPO_AVX2_AND(7, 4, 5);
312                         /* Stall */
313                         NFT_PIPAPO_AVX2_AND(7, 6, 7);
314                 }
315 
316                 /* Stall */
317                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(7, nomatch);
318                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 7);
319 
320                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
321                 if (last)
322                         return b;
323 
324                 if (unlikely(ret == -1))
325                         ret = b / XSAVE_YMM_SIZE;
326 
327                 continue;
328 nomatch:
329                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
330 nothing:
331                 ;
332         }
333 
334         return ret;
335 }
336 
337 /**
338  * nft_pipapo_avx2_lookup_4b_8() - AVX2-based lookup for 8 four-bit groups
339  * @map:        Previous match result, used as initial bitmap
340  * @fill:       Destination bitmap to be filled with current match result
341  * @f:          Field, containing lookup and mapping tables
342  * @offset:     Ignore buckets before the given index, no bits are filled there
343  * @pkt:        Packet data, pointer to input nftables register
344  * @first:      If this is the first field, don't source previous result
345  * @last:       Last field: stop at the first match and return bit index
346  *
347  * See nft_pipapo_avx2_lookup_4b_2().
348  *
349  * This is used for 32-bit fields (i.e. IPv4 addresses).
350  *
351  * Return: -1 on no match, rule index of match if @last, otherwise first long
352  * word index to be checked next (i.e. first filled word).
353  */
354 static int nft_pipapo_avx2_lookup_4b_8(unsigned long *map, unsigned long *fill,
355                                        const struct nft_pipapo_field *f,
356                                        int offset, const u8 *pkt,
357                                        bool first, bool last)
358 {
359         u8 pg[8] = {  pkt[0] >> 4,  pkt[0] & 0xf,  pkt[1] >> 4,  pkt[1] & 0xf,
360                       pkt[2] >> 4,  pkt[2] & 0xf,  pkt[3] >> 4,  pkt[3] & 0xf,
361                    };
362         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
363         unsigned long *lt = f->lt, bsize = f->bsize;
364 
365         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
366         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
367                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
368 
369                 if (first) {
370                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0,  lt, 0, pg[0], bsize);
371                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(1,  lt, 1, pg[1], bsize);
372                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(2,  lt, 2, pg[2], bsize);
373                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 3, pg[3], bsize);
374                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(4,  lt, 4, pg[4], bsize);
375                         NFT_PIPAPO_AVX2_AND(5,   0,  1);
376                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(6,  lt, 5, pg[5], bsize);
377                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(7,  lt, 6, pg[6], bsize);
378                         NFT_PIPAPO_AVX2_AND(8,   2,  3);
379                         NFT_PIPAPO_AVX2_AND(9,   4,  5);
380                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(10, lt, 7, pg[7], bsize);
381                         NFT_PIPAPO_AVX2_AND(11,  6,  7);
382                         NFT_PIPAPO_AVX2_AND(12,  8,  9);
383                         NFT_PIPAPO_AVX2_AND(13, 10, 11);
384 
385                         /* Stall */
386                         NFT_PIPAPO_AVX2_AND(1,  12, 13);
387                 } else {
388                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(0,  lt, 0, pg[0], bsize);
389                         NFT_PIPAPO_AVX2_LOAD(1, map[i_ul]);
390                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(2,  lt, 1, pg[1], bsize);
391                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 2, pg[2], bsize);
392                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(4,  lt, 3, pg[3], bsize);
393 
394                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nothing);
395 
396                         NFT_PIPAPO_AVX2_AND(5,   0,  1);
397                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(6,  lt, 4, pg[4], bsize);
398                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(7,  lt, 5, pg[5], bsize);
399                         NFT_PIPAPO_AVX2_AND(8,   2,  3);
400                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(9,  lt, 6, pg[6], bsize);
401                         NFT_PIPAPO_AVX2_AND(10,  4,  5);
402                         NFT_PIPAPO_AVX2_BUCKET_LOAD4(11, lt, 7, pg[7], bsize);
403                         NFT_PIPAPO_AVX2_AND(12,  6,  7);
404                         NFT_PIPAPO_AVX2_AND(13,  8,  9);
405                         NFT_PIPAPO_AVX2_AND(14, 10, 11);
406 
407                         /* Stall */
408                         NFT_PIPAPO_AVX2_AND(1,  12, 13);
409                         NFT_PIPAPO_AVX2_AND(1,   1, 14);
410                 }
411 
412                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nomatch);
413                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 1);
414 
415                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
416                 if (last)
417                         return b;
418 
419                 if (unlikely(ret == -1))
420                         ret = b / XSAVE_YMM_SIZE;
421 
422                 continue;
423 
424 nomatch:
425                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
426 nothing:
427                 ;
428         }
429 
430         return ret;
431 }
432 
433 /**
434  * nft_pipapo_avx2_lookup_4b_12() - AVX2-based lookup for 12 four-bit groups
435  * @map:        Previous match result, used as initial bitmap
436  * @fill:       Destination bitmap to be filled with current match result
437  * @f:          Field, containing lookup and mapping tables
438  * @offset:     Ignore buckets before the given index, no bits are filled there
439  * @pkt:        Packet data, pointer to input nftables register
440  * @first:      If this is the first field, don't source previous result
441  * @last:       Last field: stop at the first match and return bit index
442  *
443  * See nft_pipapo_avx2_lookup_4b_2().
444  *
445  * This is used for 48-bit fields (i.e. MAC addresses/EUI-48).
446  *
447  * Return: -1 on no match, rule index of match if @last, otherwise first long
448  * word index to be checked next (i.e. first filled word).
449  */
450 static int nft_pipapo_avx2_lookup_4b_12(unsigned long *map, unsigned long *fill,
451                                         const struct nft_pipapo_field *f,
452                                         int offset, const u8 *pkt,
453                                         bool first, bool last)
454 {
455         u8 pg[12] = {  pkt[0] >> 4,  pkt[0] & 0xf,  pkt[1] >> 4,  pkt[1] & 0xf,
456                        pkt[2] >> 4,  pkt[2] & 0xf,  pkt[3] >> 4,  pkt[3] & 0xf,
457                        pkt[4] >> 4,  pkt[4] & 0xf,  pkt[5] >> 4,  pkt[5] & 0xf,
458                     };
459         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
460         unsigned long *lt = f->lt, bsize = f->bsize;
461 
462         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
463         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
464                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
465 
466                 if (!first)
467                         NFT_PIPAPO_AVX2_LOAD(0, map[i_ul]);
468 
469                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(1,  lt,  0,  pg[0], bsize);
470                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(2,  lt,  1,  pg[1], bsize);
471                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt,  2,  pg[2], bsize);
472 
473                 if (!first) {
474                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(0, nothing);
475                         NFT_PIPAPO_AVX2_AND(1, 1, 0);
476                 }
477 
478                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(4,  lt,  3,  pg[3], bsize);
479                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(5,  lt,  4,  pg[4], bsize);
480                 NFT_PIPAPO_AVX2_AND(6,   2,  3);
481                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(7,  lt,  5,  pg[5], bsize);
482                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(8,  lt,  6,  pg[6], bsize);
483                 NFT_PIPAPO_AVX2_AND(9,   1,  4);
484                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(10, lt,  7,  pg[7], bsize);
485                 NFT_PIPAPO_AVX2_AND(11,  5,  6);
486                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(12, lt,  8,  pg[8], bsize);
487                 NFT_PIPAPO_AVX2_AND(13,  7,  8);
488                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(14, lt,  9,  pg[9], bsize);
489 
490                 NFT_PIPAPO_AVX2_AND(0,   9, 10);
491                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(1,  lt, 10,  pg[10], bsize);
492                 NFT_PIPAPO_AVX2_AND(2,  11, 12);
493                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 11,  pg[11], bsize);
494                 NFT_PIPAPO_AVX2_AND(4,  13, 14);
495                 NFT_PIPAPO_AVX2_AND(5,   0,  1);
496 
497                 NFT_PIPAPO_AVX2_AND(6,   2,  3);
498 
499                 /* Stalls */
500                 NFT_PIPAPO_AVX2_AND(7,   4,  5);
501                 NFT_PIPAPO_AVX2_AND(8,   6,  7);
502 
503                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(8, nomatch);
504                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 8);
505 
506                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
507                 if (last)
508                         return b;
509 
510                 if (unlikely(ret == -1))
511                         ret = b / XSAVE_YMM_SIZE;
512 
513                 continue;
514 nomatch:
515                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
516 nothing:
517                 ;
518         }
519 
520         return ret;
521 }
522 
523 /**
524  * nft_pipapo_avx2_lookup_4b_32() - AVX2-based lookup for 32 four-bit groups
525  * @map:        Previous match result, used as initial bitmap
526  * @fill:       Destination bitmap to be filled with current match result
527  * @f:          Field, containing lookup and mapping tables
528  * @offset:     Ignore buckets before the given index, no bits are filled there
529  * @pkt:        Packet data, pointer to input nftables register
530  * @first:      If this is the first field, don't source previous result
531  * @last:       Last field: stop at the first match and return bit index
532  *
533  * See nft_pipapo_avx2_lookup_4b_2().
534  *
535  * This is used for 128-bit fields (i.e. IPv6 addresses).
536  *
537  * Return: -1 on no match, rule index of match if @last, otherwise first long
538  * word index to be checked next (i.e. first filled word).
539  */
540 static int nft_pipapo_avx2_lookup_4b_32(unsigned long *map, unsigned long *fill,
541                                         const struct nft_pipapo_field *f,
542                                         int offset, const u8 *pkt,
543                                         bool first, bool last)
544 {
545         u8 pg[32] = {  pkt[0] >> 4,  pkt[0] & 0xf,  pkt[1] >> 4,  pkt[1] & 0xf,
546                        pkt[2] >> 4,  pkt[2] & 0xf,  pkt[3] >> 4,  pkt[3] & 0xf,
547                        pkt[4] >> 4,  pkt[4] & 0xf,  pkt[5] >> 4,  pkt[5] & 0xf,
548                        pkt[6] >> 4,  pkt[6] & 0xf,  pkt[7] >> 4,  pkt[7] & 0xf,
549                        pkt[8] >> 4,  pkt[8] & 0xf,  pkt[9] >> 4,  pkt[9] & 0xf,
550                       pkt[10] >> 4, pkt[10] & 0xf, pkt[11] >> 4, pkt[11] & 0xf,
551                       pkt[12] >> 4, pkt[12] & 0xf, pkt[13] >> 4, pkt[13] & 0xf,
552                       pkt[14] >> 4, pkt[14] & 0xf, pkt[15] >> 4, pkt[15] & 0xf,
553                     };
554         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
555         unsigned long *lt = f->lt, bsize = f->bsize;
556 
557         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
558         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
559                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
560 
561                 if (!first)
562                         NFT_PIPAPO_AVX2_LOAD(0, map[i_ul]);
563 
564                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(1,  lt,  0,  pg[0], bsize);
565                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(2,  lt,  1,  pg[1], bsize);
566                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt,  2,  pg[2], bsize);
567                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(4,  lt,  3,  pg[3], bsize);
568                 if (!first) {
569                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(0, nothing);
570                         NFT_PIPAPO_AVX2_AND(1, 1, 0);
571                 }
572 
573                 NFT_PIPAPO_AVX2_AND(5,   2,  3);
574                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(6,  lt,  4,  pg[4], bsize);
575                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(7,  lt,  5,  pg[5], bsize);
576                 NFT_PIPAPO_AVX2_AND(8,   1,  4);
577                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(9,  lt,  6,  pg[6], bsize);
578                 NFT_PIPAPO_AVX2_AND(10,  5,  6);
579                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(11, lt,  7,  pg[7], bsize);
580                 NFT_PIPAPO_AVX2_AND(12,  7,  8);
581                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(13, lt,  8,  pg[8], bsize);
582                 NFT_PIPAPO_AVX2_AND(14,  9, 10);
583 
584                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(0,  lt,  9,  pg[9], bsize);
585                 NFT_PIPAPO_AVX2_AND(1,  11, 12);
586                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(2,  lt, 10, pg[10], bsize);
587                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 11, pg[11], bsize);
588                 NFT_PIPAPO_AVX2_AND(4,  13, 14);
589                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(5,  lt, 12, pg[12], bsize);
590                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(6,  lt, 13, pg[13], bsize);
591                 NFT_PIPAPO_AVX2_AND(7,   0,  1);
592                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(8,  lt, 14, pg[14], bsize);
593                 NFT_PIPAPO_AVX2_AND(9,   2,  3);
594                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(10, lt, 15, pg[15], bsize);
595                 NFT_PIPAPO_AVX2_AND(11,  4,  5);
596                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(12, lt, 16, pg[16], bsize);
597                 NFT_PIPAPO_AVX2_AND(13,  6,  7);
598                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(14, lt, 17, pg[17], bsize);
599 
600                 NFT_PIPAPO_AVX2_AND(0,   8,  9);
601                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(1,  lt, 18, pg[18], bsize);
602                 NFT_PIPAPO_AVX2_AND(2,  10, 11);
603                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 19, pg[19], bsize);
604                 NFT_PIPAPO_AVX2_AND(4,  12, 13);
605                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(5,  lt, 20, pg[20], bsize);
606                 NFT_PIPAPO_AVX2_AND(6,  14,  0);
607                 NFT_PIPAPO_AVX2_AND(7,   1,  2);
608                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(8,  lt, 21, pg[21], bsize);
609                 NFT_PIPAPO_AVX2_AND(9,   3,  4);
610                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(10, lt, 22, pg[22], bsize);
611                 NFT_PIPAPO_AVX2_AND(11,  5,  6);
612                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(12, lt, 23, pg[23], bsize);
613                 NFT_PIPAPO_AVX2_AND(13,  7,  8);
614 
615                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(14, lt, 24, pg[24], bsize);
616                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(0,  lt, 25, pg[25], bsize);
617                 NFT_PIPAPO_AVX2_AND(1,   9, 10);
618                 NFT_PIPAPO_AVX2_AND(2,  11, 12);
619                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(3,  lt, 26, pg[26], bsize);
620                 NFT_PIPAPO_AVX2_AND(4,  13, 14);
621                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(5,  lt, 27, pg[27], bsize);
622                 NFT_PIPAPO_AVX2_AND(6,   0,  1);
623                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(7,  lt, 28, pg[28], bsize);
624                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(8,  lt, 29, pg[29], bsize);
625                 NFT_PIPAPO_AVX2_AND(9,   2,  3);
626                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(10, lt, 30, pg[30], bsize);
627                 NFT_PIPAPO_AVX2_AND(11,  4,  5);
628                 NFT_PIPAPO_AVX2_BUCKET_LOAD4(12, lt, 31, pg[31], bsize);
629 
630                 NFT_PIPAPO_AVX2_AND(0,   6,  7);
631                 NFT_PIPAPO_AVX2_AND(1,   8,  9);
632                 NFT_PIPAPO_AVX2_AND(2,  10, 11);
633                 NFT_PIPAPO_AVX2_AND(3,  12,  0);
634 
635                 /* Stalls */
636                 NFT_PIPAPO_AVX2_AND(4,   1,  2);
637                 NFT_PIPAPO_AVX2_AND(5,   3,  4);
638 
639                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(5, nomatch);
640                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 5);
641 
642                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
643                 if (last)
644                         return b;
645 
646                 if (unlikely(ret == -1))
647                         ret = b / XSAVE_YMM_SIZE;
648 
649                 continue;
650 nomatch:
651                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
652 nothing:
653                 ;
654         }
655 
656         return ret;
657 }
658 
659 /**
660  * nft_pipapo_avx2_lookup_8b_1() - AVX2-based lookup for one eight-bit group
661  * @map:        Previous match result, used as initial bitmap
662  * @fill:       Destination bitmap to be filled with current match result
663  * @f:          Field, containing lookup and mapping tables
664  * @offset:     Ignore buckets before the given index, no bits are filled there
665  * @pkt:        Packet data, pointer to input nftables register
666  * @first:      If this is the first field, don't source previous result
667  * @last:       Last field: stop at the first match and return bit index
668  *
669  * See nft_pipapo_avx2_lookup_4b_2().
670  *
671  * This is used for 8-bit fields (i.e. protocol numbers).
672  *
673  * Return: -1 on no match, rule index of match if @last, otherwise first long
674  * word index to be checked next (i.e. first filled word).
675  */
676 static int nft_pipapo_avx2_lookup_8b_1(unsigned long *map, unsigned long *fill,
677                                        const struct nft_pipapo_field *f,
678                                        int offset, const u8 *pkt,
679                                        bool first, bool last)
680 {
681         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
682         unsigned long *lt = f->lt, bsize = f->bsize;
683 
684         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
685         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
686                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
687 
688                 if (first) {
689                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2, lt, 0, pkt[0], bsize);
690                 } else {
691                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0, lt, 0, pkt[0], bsize);
692                         NFT_PIPAPO_AVX2_LOAD(1, map[i_ul]);
693                         NFT_PIPAPO_AVX2_AND(2, 0, 1);
694                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nothing);
695                 }
696 
697                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(2, nomatch);
698                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 2);
699 
700                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
701                 if (last)
702                         return b;
703 
704                 if (unlikely(ret == -1))
705                         ret = b / XSAVE_YMM_SIZE;
706 
707                 continue;
708 nomatch:
709                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
710 nothing:
711                 ;
712         }
713 
714         return ret;
715 }
716 
717 /**
718  * nft_pipapo_avx2_lookup_8b_2() - AVX2-based lookup for 2 eight-bit groups
719  * @map:        Previous match result, used as initial bitmap
720  * @fill:       Destination bitmap to be filled with current match result
721  * @f:          Field, containing lookup and mapping tables
722  * @offset:     Ignore buckets before the given index, no bits are filled there
723  * @pkt:        Packet data, pointer to input nftables register
724  * @first:      If this is the first field, don't source previous result
725  * @last:       Last field: stop at the first match and return bit index
726  *
727  * See nft_pipapo_avx2_lookup_4b_2().
728  *
729  * This is used for 16-bit fields (i.e. ports).
730  *
731  * Return: -1 on no match, rule index of match if @last, otherwise first long
732  * word index to be checked next (i.e. first filled word).
733  */
734 static int nft_pipapo_avx2_lookup_8b_2(unsigned long *map, unsigned long *fill,
735                                        const struct nft_pipapo_field *f,
736                                        int offset, const u8 *pkt,
737                                        bool first, bool last)
738 {
739         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
740         unsigned long *lt = f->lt, bsize = f->bsize;
741 
742         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
743         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
744                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
745 
746                 if (first) {
747                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0, lt, 0, pkt[0], bsize);
748                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 1, pkt[1], bsize);
749                         NFT_PIPAPO_AVX2_AND(4, 0, 1);
750                 } else {
751                         NFT_PIPAPO_AVX2_LOAD(0, map[i_ul]);
752                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 0, pkt[0], bsize);
753                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2, lt, 1, pkt[1], bsize);
754 
755                         /* Stall */
756                         NFT_PIPAPO_AVX2_AND(3, 0, 1);
757                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(0, nothing);
758                         NFT_PIPAPO_AVX2_AND(4, 3, 2);
759                 }
760 
761                 /* Stall */
762                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(4, nomatch);
763                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 4);
764 
765                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
766                 if (last)
767                         return b;
768 
769                 if (unlikely(ret == -1))
770                         ret = b / XSAVE_YMM_SIZE;
771 
772                 continue;
773 nomatch:
774                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
775 nothing:
776                 ;
777         }
778 
779         return ret;
780 }
781 
782 /**
783  * nft_pipapo_avx2_lookup_8b_4() - AVX2-based lookup for 4 eight-bit groups
784  * @map:        Previous match result, used as initial bitmap
785  * @fill:       Destination bitmap to be filled with current match result
786  * @f:          Field, containing lookup and mapping tables
787  * @offset:     Ignore buckets before the given index, no bits are filled there
788  * @pkt:        Packet data, pointer to input nftables register
789  * @first:      If this is the first field, don't source previous result
790  * @last:       Last field: stop at the first match and return bit index
791  *
792  * See nft_pipapo_avx2_lookup_4b_2().
793  *
794  * This is used for 32-bit fields (i.e. IPv4 addresses).
795  *
796  * Return: -1 on no match, rule index of match if @last, otherwise first long
797  * word index to be checked next (i.e. first filled word).
798  */
799 static int nft_pipapo_avx2_lookup_8b_4(unsigned long *map, unsigned long *fill,
800                                        const struct nft_pipapo_field *f,
801                                        int offset, const u8 *pkt,
802                                        bool first, bool last)
803 {
804         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
805         unsigned long *lt = f->lt, bsize = f->bsize;
806 
807         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
808         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
809                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
810 
811                 if (first) {
812                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0,  lt, 0, pkt[0], bsize);
813                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(1,  lt, 1, pkt[1], bsize);
814                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2,  lt, 2, pkt[2], bsize);
815                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(3,  lt, 3, pkt[3], bsize);
816 
817                         /* Stall */
818                         NFT_PIPAPO_AVX2_AND(4, 0, 1);
819                         NFT_PIPAPO_AVX2_AND(5, 2, 3);
820                         NFT_PIPAPO_AVX2_AND(0, 4, 5);
821                 } else {
822                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0,  lt, 0, pkt[0], bsize);
823                         NFT_PIPAPO_AVX2_LOAD(1, map[i_ul]);
824                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2,  lt, 1, pkt[1], bsize);
825                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(3,  lt, 2, pkt[2], bsize);
826                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(4,  lt, 3, pkt[3], bsize);
827 
828                         NFT_PIPAPO_AVX2_AND(5, 0, 1);
829                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nothing);
830                         NFT_PIPAPO_AVX2_AND(6, 2, 3);
831 
832                         /* Stall */
833                         NFT_PIPAPO_AVX2_AND(7, 4, 5);
834                         NFT_PIPAPO_AVX2_AND(0, 6, 7);
835                 }
836 
837                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(0, nomatch);
838                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 0);
839 
840                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
841                 if (last)
842                         return b;
843 
844                 if (unlikely(ret == -1))
845                         ret = b / XSAVE_YMM_SIZE;
846 
847                 continue;
848 
849 nomatch:
850                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
851 nothing:
852                 ;
853         }
854 
855         return ret;
856 }
857 
858 /**
859  * nft_pipapo_avx2_lookup_8b_6() - AVX2-based lookup for 6 eight-bit groups
860  * @map:        Previous match result, used as initial bitmap
861  * @fill:       Destination bitmap to be filled with current match result
862  * @f:          Field, containing lookup and mapping tables
863  * @offset:     Ignore buckets before the given index, no bits are filled there
864  * @pkt:        Packet data, pointer to input nftables register
865  * @first:      If this is the first field, don't source previous result
866  * @last:       Last field: stop at the first match and return bit index
867  *
868  * See nft_pipapo_avx2_lookup_4b_2().
869  *
870  * This is used for 48-bit fields (i.e. MAC addresses/EUI-48).
871  *
872  * Return: -1 on no match, rule index of match if @last, otherwise first long
873  * word index to be checked next (i.e. first filled word).
874  */
875 static int nft_pipapo_avx2_lookup_8b_6(unsigned long *map, unsigned long *fill,
876                                        const struct nft_pipapo_field *f,
877                                        int offset, const u8 *pkt,
878                                        bool first, bool last)
879 {
880         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
881         unsigned long *lt = f->lt, bsize = f->bsize;
882 
883         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
884         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
885                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
886 
887                 if (first) {
888                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0,  lt, 0, pkt[0], bsize);
889                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(1,  lt, 1, pkt[1], bsize);
890                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2,  lt, 2, pkt[2], bsize);
891                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(3,  lt, 3, pkt[3], bsize);
892                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(4,  lt, 4, pkt[4], bsize);
893 
894                         NFT_PIPAPO_AVX2_AND(5, 0, 1);
895                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(6,  lt, 5, pkt[5], bsize);
896                         NFT_PIPAPO_AVX2_AND(7, 2, 3);
897 
898                         /* Stall */
899                         NFT_PIPAPO_AVX2_AND(0, 4, 5);
900                         NFT_PIPAPO_AVX2_AND(1, 6, 7);
901                         NFT_PIPAPO_AVX2_AND(4, 0, 1);
902                 } else {
903                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(0,  lt, 0, pkt[0], bsize);
904                         NFT_PIPAPO_AVX2_LOAD(1, map[i_ul]);
905                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(2,  lt, 1, pkt[1], bsize);
906                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(3,  lt, 2, pkt[2], bsize);
907                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(4,  lt, 3, pkt[3], bsize);
908 
909                         NFT_PIPAPO_AVX2_AND(5, 0, 1);
910                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(1, nothing);
911 
912                         NFT_PIPAPO_AVX2_AND(6, 2, 3);
913                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(7,  lt, 4, pkt[4], bsize);
914                         NFT_PIPAPO_AVX2_AND(0, 4, 5);
915                         NFT_PIPAPO_AVX2_BUCKET_LOAD8(1,  lt, 5, pkt[5], bsize);
916                         NFT_PIPAPO_AVX2_AND(2, 6, 7);
917 
918                         /* Stall */
919                         NFT_PIPAPO_AVX2_AND(3, 0, 1);
920                         NFT_PIPAPO_AVX2_AND(4, 2, 3);
921                 }
922 
923                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(4, nomatch);
924                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 4);
925 
926                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
927                 if (last)
928                         return b;
929 
930                 if (unlikely(ret == -1))
931                         ret = b / XSAVE_YMM_SIZE;
932 
933                 continue;
934 
935 nomatch:
936                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
937 nothing:
938                 ;
939         }
940 
941         return ret;
942 }
943 
944 /**
945  * nft_pipapo_avx2_lookup_8b_16() - AVX2-based lookup for 16 eight-bit groups
946  * @map:        Previous match result, used as initial bitmap
947  * @fill:       Destination bitmap to be filled with current match result
948  * @f:          Field, containing lookup and mapping tables
949  * @offset:     Ignore buckets before the given index, no bits are filled there
950  * @pkt:        Packet data, pointer to input nftables register
951  * @first:      If this is the first field, don't source previous result
952  * @last:       Last field: stop at the first match and return bit index
953  *
954  * See nft_pipapo_avx2_lookup_4b_2().
955  *
956  * This is used for 128-bit fields (i.e. IPv6 addresses).
957  *
958  * Return: -1 on no match, rule index of match if @last, otherwise first long
959  * word index to be checked next (i.e. first filled word).
960  */
961 static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill,
962                                         const struct nft_pipapo_field *f,
963                                         int offset, const u8 *pkt,
964                                         bool first, bool last)
965 {
966         int i, ret = -1, m256_size = f->bsize / NFT_PIPAPO_LONGS_PER_M256, b;
967         unsigned long *lt = f->lt, bsize = f->bsize;
968 
969         lt += offset * NFT_PIPAPO_LONGS_PER_M256;
970         for (i = offset; i < m256_size; i++, lt += NFT_PIPAPO_LONGS_PER_M256) {
971                 int i_ul = i * NFT_PIPAPO_LONGS_PER_M256;
972 
973                 if (!first)
974                         NFT_PIPAPO_AVX2_LOAD(0, map[i_ul]);
975 
976                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt,  0,  pkt[0], bsize);
977                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(2, lt,  1,  pkt[1], bsize);
978                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt,  2,  pkt[2], bsize);
979                 if (!first) {
980                         NFT_PIPAPO_AVX2_NOMATCH_GOTO(0, nothing);
981                         NFT_PIPAPO_AVX2_AND(1, 1, 0);
982                 }
983                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(4, lt,  3,  pkt[3], bsize);
984 
985                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt,  4,  pkt[4], bsize);
986                 NFT_PIPAPO_AVX2_AND(6, 1, 2);
987                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt,  5,  pkt[5], bsize);
988                 NFT_PIPAPO_AVX2_AND(0, 3, 4);
989                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt,  6,  pkt[6], bsize);
990 
991                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(2, lt,  7,  pkt[7], bsize);
992                 NFT_PIPAPO_AVX2_AND(3, 5, 6);
993                 NFT_PIPAPO_AVX2_AND(4, 0, 1);
994                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt,  8,  pkt[8], bsize);
995 
996                 NFT_PIPAPO_AVX2_AND(6, 2, 3);
997                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt,  9,  pkt[9], bsize);
998                 NFT_PIPAPO_AVX2_AND(0, 4, 5);
999                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 10, pkt[10], bsize);
1000                 NFT_PIPAPO_AVX2_AND(2, 6, 7);
1001                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt, 11, pkt[11], bsize);
1002                 NFT_PIPAPO_AVX2_AND(4, 0, 1);
1003                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(5, lt, 12, pkt[12], bsize);
1004                 NFT_PIPAPO_AVX2_AND(6, 2, 3);
1005                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(7, lt, 13, pkt[13], bsize);
1006                 NFT_PIPAPO_AVX2_AND(0, 4, 5);
1007                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(1, lt, 14, pkt[14], bsize);
1008                 NFT_PIPAPO_AVX2_AND(2, 6, 7);
1009                 NFT_PIPAPO_AVX2_BUCKET_LOAD8(3, lt, 15, pkt[15], bsize);
1010                 NFT_PIPAPO_AVX2_AND(4, 0, 1);
1011 
1012                 /* Stall */
1013                 NFT_PIPAPO_AVX2_AND(5, 2, 3);
1014                 NFT_PIPAPO_AVX2_AND(6, 4, 5);
1015 
1016                 NFT_PIPAPO_AVX2_NOMATCH_GOTO(6, nomatch);
1017                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 6);
1018 
1019                 b = nft_pipapo_avx2_refill(i_ul, &map[i_ul], fill, f->mt, last);
1020                 if (last)
1021                         return b;
1022 
1023                 if (unlikely(ret == -1))
1024                         ret = b / XSAVE_YMM_SIZE;
1025 
1026                 continue;
1027 
1028 nomatch:
1029                 NFT_PIPAPO_AVX2_STORE(map[i_ul], 15);
1030 nothing:
1031                 ;
1032         }
1033 
1034         return ret;
1035 }
1036 
1037 /**
1038  * nft_pipapo_avx2_lookup_slow() - Fallback function for uncommon field sizes
1039  * @mdata:      Matching data, including mapping table
1040  * @map:        Previous match result, used as initial bitmap
1041  * @fill:       Destination bitmap to be filled with current match result
1042  * @f:          Field, containing lookup and mapping tables
1043  * @offset:     Ignore buckets before the given index, no bits are filled there
1044  * @pkt:        Packet data, pointer to input nftables register
1045  * @first:      If this is the first field, don't source previous result
1046  * @last:       Last field: stop at the first match and return bit index
1047  *
1048  * This function should never be called, but is provided for the case the field
1049  * size doesn't match any of the known data types. Matching rate is
1050  * substantially lower than AVX2 routines.
1051  *
1052  * Return: -1 on no match, rule index of match if @last, otherwise first long
1053  * word index to be checked next (i.e. first filled word).
1054  */
1055 static int nft_pipapo_avx2_lookup_slow(const struct nft_pipapo_match *mdata,
1056                                         unsigned long *map, unsigned long *fill,
1057                                         const struct nft_pipapo_field *f,
1058                                         int offset, const u8 *pkt,
1059                                         bool first, bool last)
1060 {
1061         unsigned long bsize = f->bsize;
1062         int i, ret = -1, b;
1063 
1064         if (first)
1065                 pipapo_resmap_init(mdata, map);
1066 
1067         for (i = offset; i < bsize; i++) {
1068                 if (f->bb == 8)
1069                         pipapo_and_field_buckets_8bit(f, map, pkt);
1070                 else
1071                         pipapo_and_field_buckets_4bit(f, map, pkt);
1072                 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
1073 
1074                 b = pipapo_refill(map, bsize, f->rules, fill, f->mt, last);
1075 
1076                 if (last)
1077                         return b;
1078 
1079                 if (ret == -1)
1080                         ret = b / XSAVE_YMM_SIZE;
1081         }
1082 
1083         return ret;
1084 }
1085 
1086 /**
1087  * nft_pipapo_avx2_estimate() - Set size, space and lookup complexity
1088  * @desc:       Set description, element count and field description used
1089  * @features:   Flags: NFT_SET_INTERVAL needs to be there
1090  * @est:        Storage for estimation data
1091  *
1092  * Return: true if set is compatible and AVX2 available, false otherwise.
1093  */
1094 bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features,
1095                               struct nft_set_estimate *est)
1096 {
1097         if (!(features & NFT_SET_INTERVAL) ||
1098             desc->field_count < NFT_PIPAPO_MIN_FIELDS)
1099                 return false;
1100 
1101         if (!boot_cpu_has(X86_FEATURE_AVX2) || !boot_cpu_has(X86_FEATURE_AVX))
1102                 return false;
1103 
1104         est->size = pipapo_estimate_size(desc);
1105         if (!est->size)
1106                 return false;
1107 
1108         est->lookup = NFT_SET_CLASS_O_LOG_N;
1109 
1110         est->space = NFT_SET_CLASS_O_N;
1111 
1112         return true;
1113 }
1114 
1115 /**
1116  * nft_pipapo_avx2_lookup() - Lookup function for AVX2 implementation
1117  * @net:        Network namespace
1118  * @set:        nftables API set representation
1119  * @key:        nftables API element representation containing key data
1120  * @ext:        nftables API extension pointer, filled with matching reference
1121  *
1122  * For more details, see DOC: Theory of Operation in nft_set_pipapo.c.
1123  *
1124  * This implementation exploits the repetitive characteristic of the algorithm
1125  * to provide a fast, vectorised version using the AVX2 SIMD instruction set.
1126  *
1127  * Return: true on match, false otherwise.
1128  */
1129 bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
1130                             const u32 *key, const struct nft_set_ext **ext)
1131 {
1132         struct nft_pipapo *priv = nft_set_priv(set);
1133         struct nft_pipapo_scratch *scratch;
1134         u8 genmask = nft_genmask_cur(net);
1135         const struct nft_pipapo_match *m;
1136         const struct nft_pipapo_field *f;
1137         const u8 *rp = (const u8 *)key;
1138         unsigned long *res, *fill;
1139         bool map_index;
1140         int i, ret = 0;
1141 
1142         local_bh_disable();
1143 
1144         if (unlikely(!irq_fpu_usable())) {
1145                 bool fallback_res = nft_pipapo_lookup(net, set, key, ext);
1146 
1147                 local_bh_enable();
1148                 return fallback_res;
1149         }
1150 
1151         m = rcu_dereference(priv->match);
1152 
1153         /* This also protects access to all data related to scratch maps.
1154          *
1155          * Note that we don't need a valid MXCSR state for any of the
1156          * operations we use here, so pass 0 as mask and spare a LDMXCSR
1157          * instruction.
1158          */
1159         kernel_fpu_begin_mask(0);
1160 
1161         scratch = *raw_cpu_ptr(m->scratch);
1162         if (unlikely(!scratch)) {
1163                 kernel_fpu_end();
1164                 local_bh_enable();
1165                 return false;
1166         }
1167 
1168         map_index = scratch->map_index;
1169 
1170         res  = scratch->map + (map_index ? m->bsize_max : 0);
1171         fill = scratch->map + (map_index ? 0 : m->bsize_max);
1172 
1173         /* Starting map doesn't need to be set for this implementation */
1174 
1175         nft_pipapo_avx2_prepare();
1176 
1177 next_match:
1178         nft_pipapo_for_each_field(f, i, m) {
1179                 bool last = i == m->field_count - 1, first = !i;
1180 
1181 #define NFT_SET_PIPAPO_AVX2_LOOKUP(b, n)                                \
1182                 (ret = nft_pipapo_avx2_lookup_##b##b_##n(res, fill, f,  \
1183                                                          ret, rp,       \
1184                                                          first, last))
1185 
1186                 if (likely(f->bb == 8)) {
1187                         if (f->groups == 1) {
1188                                 NFT_SET_PIPAPO_AVX2_LOOKUP(8, 1);
1189                         } else if (f->groups == 2) {
1190                                 NFT_SET_PIPAPO_AVX2_LOOKUP(8, 2);
1191                         } else if (f->groups == 4) {
1192                                 NFT_SET_PIPAPO_AVX2_LOOKUP(8, 4);
1193                         } else if (f->groups == 6) {
1194                                 NFT_SET_PIPAPO_AVX2_LOOKUP(8, 6);
1195                         } else if (f->groups == 16) {
1196                                 NFT_SET_PIPAPO_AVX2_LOOKUP(8, 16);
1197                         } else {
1198                                 ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f,
1199                                                                   ret, rp,
1200                                                                   first, last);
1201                         }
1202                 } else {
1203                         if (f->groups == 2) {
1204                                 NFT_SET_PIPAPO_AVX2_LOOKUP(4, 2);
1205                         } else if (f->groups == 4) {
1206                                 NFT_SET_PIPAPO_AVX2_LOOKUP(4, 4);
1207                         } else if (f->groups == 8) {
1208                                 NFT_SET_PIPAPO_AVX2_LOOKUP(4, 8);
1209                         } else if (f->groups == 12) {
1210                                 NFT_SET_PIPAPO_AVX2_LOOKUP(4, 12);
1211                         } else if (f->groups == 32) {
1212                                 NFT_SET_PIPAPO_AVX2_LOOKUP(4, 32);
1213                         } else {
1214                                 ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f,
1215                                                                   ret, rp,
1216                                                                   first, last);
1217                         }
1218                 }
1219                 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
1220 
1221 #undef NFT_SET_PIPAPO_AVX2_LOOKUP
1222 
1223                 if (ret < 0)
1224                         goto out;
1225 
1226                 if (last) {
1227                         *ext = &f->mt[ret].e->ext;
1228                         if (unlikely(nft_set_elem_expired(*ext) ||
1229                                      !nft_set_elem_active(*ext, genmask))) {
1230                                 ret = 0;
1231                                 goto next_match;
1232                         }
1233 
1234                         goto out;
1235                 }
1236 
1237                 swap(res, fill);
1238                 rp += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1239         }
1240 
1241 out:
1242         if (i % 2)
1243                 scratch->map_index = !map_index;
1244         kernel_fpu_end();
1245         local_bh_enable();
1246 
1247         return ret >= 0;
1248 }
1249 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php