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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.