0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 #include <linux/kernel.h>
0332 #include <linux/init.h>
0333 #include <linux/module.h>
0334 #include <linux/netlink.h>
0335 #include <linux/netfilter.h>
0336 #include <linux/netfilter/nf_tables.h>
0337 #include <net/netfilter/nf_tables_core.h>
0338 #include <uapi/linux/netfilter/nf_tables.h>
0339 #include <linux/bitmap.h>
0340 #include <linux/bitops.h>
0341
0342 #include "nft_set_pipapo_avx2.h"
0343 #include "nft_set_pipapo.h"
0344
0345
0346 static DEFINE_PER_CPU(bool, nft_pipapo_scratch_index);
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365 int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
0366 union nft_pipapo_map_bucket *mt, bool match_only)
0367 {
0368 unsigned long bitset;
0369 int k, ret = -1;
0370
0371 for (k = 0; k < len; k++) {
0372 bitset = map[k];
0373 while (bitset) {
0374 unsigned long t = bitset & -bitset;
0375 int r = __builtin_ctzl(bitset);
0376 int i = k * BITS_PER_LONG + r;
0377
0378 if (unlikely(i >= rules)) {
0379 map[k] = 0;
0380 return -1;
0381 }
0382
0383 if (match_only) {
0384 bitmap_clear(map, i, 1);
0385 return i;
0386 }
0387
0388 ret = 0;
0389
0390 bitmap_set(dst, mt[i].to, mt[i].n);
0391
0392 bitset ^= t;
0393 }
0394 map[k] = 0;
0395 }
0396
0397 return ret;
0398 }
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411 bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
0412 const u32 *key, const struct nft_set_ext **ext)
0413 {
0414 struct nft_pipapo *priv = nft_set_priv(set);
0415 unsigned long *res_map, *fill_map;
0416 u8 genmask = nft_genmask_cur(net);
0417 const u8 *rp = (const u8 *)key;
0418 struct nft_pipapo_match *m;
0419 struct nft_pipapo_field *f;
0420 bool map_index;
0421 int i;
0422
0423 local_bh_disable();
0424
0425 map_index = raw_cpu_read(nft_pipapo_scratch_index);
0426
0427 m = rcu_dereference(priv->match);
0428
0429 if (unlikely(!m || !*raw_cpu_ptr(m->scratch)))
0430 goto out;
0431
0432 res_map = *raw_cpu_ptr(m->scratch) + (map_index ? m->bsize_max : 0);
0433 fill_map = *raw_cpu_ptr(m->scratch) + (map_index ? 0 : m->bsize_max);
0434
0435 memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
0436
0437 nft_pipapo_for_each_field(f, i, m) {
0438 bool last = i == m->field_count - 1;
0439 int b;
0440
0441
0442
0443
0444 if (likely(f->bb == 8))
0445 pipapo_and_field_buckets_8bit(f, res_map, rp);
0446 else
0447 pipapo_and_field_buckets_4bit(f, res_map, rp);
0448 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
0449
0450 rp += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
0451
0452
0453
0454
0455
0456
0457
0458
0459 next_match:
0460 b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
0461 last);
0462 if (b < 0) {
0463 raw_cpu_write(nft_pipapo_scratch_index, map_index);
0464 local_bh_enable();
0465
0466 return false;
0467 }
0468
0469 if (last) {
0470 *ext = &f->mt[b].e->ext;
0471 if (unlikely(nft_set_elem_expired(*ext) ||
0472 !nft_set_elem_active(*ext, genmask)))
0473 goto next_match;
0474
0475
0476
0477
0478
0479
0480 raw_cpu_write(nft_pipapo_scratch_index, map_index);
0481 local_bh_enable();
0482
0483 return true;
0484 }
0485
0486
0487
0488
0489
0490 map_index = !map_index;
0491 swap(res_map, fill_map);
0492
0493 rp += NFT_PIPAPO_GROUPS_PADDING(f);
0494 }
0495
0496 out:
0497 local_bh_enable();
0498 return false;
0499 }
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514 static struct nft_pipapo_elem *pipapo_get(const struct net *net,
0515 const struct nft_set *set,
0516 const u8 *data, u8 genmask)
0517 {
0518 struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
0519 struct nft_pipapo *priv = nft_set_priv(set);
0520 struct nft_pipapo_match *m = priv->clone;
0521 unsigned long *res_map, *fill_map = NULL;
0522 struct nft_pipapo_field *f;
0523 int i;
0524
0525 res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
0526 if (!res_map) {
0527 ret = ERR_PTR(-ENOMEM);
0528 goto out;
0529 }
0530
0531 fill_map = kcalloc(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
0532 if (!fill_map) {
0533 ret = ERR_PTR(-ENOMEM);
0534 goto out;
0535 }
0536
0537 memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
0538
0539 nft_pipapo_for_each_field(f, i, m) {
0540 bool last = i == m->field_count - 1;
0541 int b;
0542
0543
0544
0545
0546 if (f->bb == 8)
0547 pipapo_and_field_buckets_8bit(f, res_map, data);
0548 else if (f->bb == 4)
0549 pipapo_and_field_buckets_4bit(f, res_map, data);
0550 else
0551 BUG();
0552
0553 data += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
0554
0555
0556
0557
0558
0559
0560
0561
0562 next_match:
0563 b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
0564 last);
0565 if (b < 0)
0566 goto out;
0567
0568 if (last) {
0569 if (nft_set_elem_expired(&f->mt[b].e->ext) ||
0570 (genmask &&
0571 !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
0572 goto next_match;
0573
0574 ret = f->mt[b].e;
0575 goto out;
0576 }
0577
0578 data += NFT_PIPAPO_GROUPS_PADDING(f);
0579
0580
0581
0582
0583
0584
0585 swap(res_map, fill_map);
0586 }
0587
0588 out:
0589 kfree(fill_map);
0590 kfree(res_map);
0591 return ret;
0592 }
0593
0594
0595
0596
0597
0598
0599
0600
0601 static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
0602 const struct nft_set_elem *elem, unsigned int flags)
0603 {
0604 return pipapo_get(net, set, (const u8 *)elem->key.val.data,
0605 nft_genmask_cur(net));
0606 }
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620 static int pipapo_resize(struct nft_pipapo_field *f, int old_rules, int rules)
0621 {
0622 long *new_lt = NULL, *new_p, *old_lt = f->lt, *old_p;
0623 union nft_pipapo_map_bucket *new_mt, *old_mt = f->mt;
0624 size_t new_bucket_size, copy;
0625 int group, bucket;
0626
0627 new_bucket_size = DIV_ROUND_UP(rules, BITS_PER_LONG);
0628 #ifdef NFT_PIPAPO_ALIGN
0629 new_bucket_size = roundup(new_bucket_size,
0630 NFT_PIPAPO_ALIGN / sizeof(*new_lt));
0631 #endif
0632
0633 if (new_bucket_size == f->bsize)
0634 goto mt;
0635
0636 if (new_bucket_size > f->bsize)
0637 copy = f->bsize;
0638 else
0639 copy = new_bucket_size;
0640
0641 new_lt = kvzalloc(f->groups * NFT_PIPAPO_BUCKETS(f->bb) *
0642 new_bucket_size * sizeof(*new_lt) +
0643 NFT_PIPAPO_ALIGN_HEADROOM,
0644 GFP_KERNEL);
0645 if (!new_lt)
0646 return -ENOMEM;
0647
0648 new_p = NFT_PIPAPO_LT_ALIGN(new_lt);
0649 old_p = NFT_PIPAPO_LT_ALIGN(old_lt);
0650
0651 for (group = 0; group < f->groups; group++) {
0652 for (bucket = 0; bucket < NFT_PIPAPO_BUCKETS(f->bb); bucket++) {
0653 memcpy(new_p, old_p, copy * sizeof(*new_p));
0654 new_p += copy;
0655 old_p += copy;
0656
0657 if (new_bucket_size > f->bsize)
0658 new_p += new_bucket_size - f->bsize;
0659 else
0660 old_p += f->bsize - new_bucket_size;
0661 }
0662 }
0663
0664 mt:
0665 new_mt = kvmalloc(rules * sizeof(*new_mt), GFP_KERNEL);
0666 if (!new_mt) {
0667 kvfree(new_lt);
0668 return -ENOMEM;
0669 }
0670
0671 memcpy(new_mt, f->mt, min(old_rules, rules) * sizeof(*new_mt));
0672 if (rules > old_rules) {
0673 memset(new_mt + old_rules, 0,
0674 (rules - old_rules) * sizeof(*new_mt));
0675 }
0676
0677 if (new_lt) {
0678 f->bsize = new_bucket_size;
0679 NFT_PIPAPO_LT_ASSIGN(f, new_lt);
0680 kvfree(old_lt);
0681 }
0682
0683 f->mt = new_mt;
0684 kvfree(old_mt);
0685
0686 return 0;
0687 }
0688
0689
0690
0691
0692
0693
0694
0695
0696 static void pipapo_bucket_set(struct nft_pipapo_field *f, int rule, int group,
0697 int v)
0698 {
0699 unsigned long *pos;
0700
0701 pos = NFT_PIPAPO_LT_ALIGN(f->lt);
0702 pos += f->bsize * NFT_PIPAPO_BUCKETS(f->bb) * group;
0703 pos += f->bsize * v;
0704
0705 __set_bit(rule, pos);
0706 }
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743 static void pipapo_lt_4b_to_8b(int old_groups, int bsize,
0744 unsigned long *old_lt, unsigned long *new_lt)
0745 {
0746 int g, b, i;
0747
0748 for (g = 0; g < old_groups / 2; g++) {
0749 int src_g0 = g * 2, src_g1 = g * 2 + 1;
0750
0751 for (b = 0; b < NFT_PIPAPO_BUCKETS(8); b++) {
0752 int src_b0 = b / NFT_PIPAPO_BUCKETS(4);
0753 int src_b1 = b % NFT_PIPAPO_BUCKETS(4);
0754 int src_i0 = src_g0 * NFT_PIPAPO_BUCKETS(4) + src_b0;
0755 int src_i1 = src_g1 * NFT_PIPAPO_BUCKETS(4) + src_b1;
0756
0757 for (i = 0; i < bsize; i++) {
0758 *new_lt = old_lt[src_i0 * bsize + i] &
0759 old_lt[src_i1 * bsize + i];
0760 new_lt++;
0761 }
0762 }
0763 }
0764 }
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789 static void pipapo_lt_8b_to_4b(int old_groups, int bsize,
0790 unsigned long *old_lt, unsigned long *new_lt)
0791 {
0792 int g, b, bsrc, i;
0793
0794 memset(new_lt, 0, old_groups * 2 * NFT_PIPAPO_BUCKETS(4) * bsize *
0795 sizeof(unsigned long));
0796
0797 for (g = 0; g < old_groups * 2; g += 2) {
0798 int src_g = g / 2;
0799
0800 for (b = 0; b < NFT_PIPAPO_BUCKETS(4); b++) {
0801 for (bsrc = NFT_PIPAPO_BUCKETS(8) * src_g;
0802 bsrc < NFT_PIPAPO_BUCKETS(8) * (src_g + 1);
0803 bsrc++) {
0804 if (((bsrc & 0xf0) >> 4) != b)
0805 continue;
0806
0807 for (i = 0; i < bsize; i++)
0808 new_lt[i] |= old_lt[bsrc * bsize + i];
0809 }
0810
0811 new_lt += bsize;
0812 }
0813
0814 for (b = 0; b < NFT_PIPAPO_BUCKETS(4); b++) {
0815 for (bsrc = NFT_PIPAPO_BUCKETS(8) * src_g;
0816 bsrc < NFT_PIPAPO_BUCKETS(8) * (src_g + 1);
0817 bsrc++) {
0818 if ((bsrc & 0x0f) != b)
0819 continue;
0820
0821 for (i = 0; i < bsize; i++)
0822 new_lt[i] |= old_lt[bsrc * bsize + i];
0823 }
0824
0825 new_lt += bsize;
0826 }
0827 }
0828 }
0829
0830
0831
0832
0833
0834 static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f)
0835 {
0836 unsigned long *new_lt;
0837 int groups, bb;
0838 size_t lt_size;
0839
0840 lt_size = f->groups * NFT_PIPAPO_BUCKETS(f->bb) * f->bsize *
0841 sizeof(*f->lt);
0842
0843 if (f->bb == NFT_PIPAPO_GROUP_BITS_SMALL_SET &&
0844 lt_size > NFT_PIPAPO_LT_SIZE_HIGH) {
0845 groups = f->groups * 2;
0846 bb = NFT_PIPAPO_GROUP_BITS_LARGE_SET;
0847
0848 lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
0849 sizeof(*f->lt);
0850 } else if (f->bb == NFT_PIPAPO_GROUP_BITS_LARGE_SET &&
0851 lt_size < NFT_PIPAPO_LT_SIZE_LOW) {
0852 groups = f->groups / 2;
0853 bb = NFT_PIPAPO_GROUP_BITS_SMALL_SET;
0854
0855 lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
0856 sizeof(*f->lt);
0857
0858
0859
0860
0861 if (lt_size > NFT_PIPAPO_LT_SIZE_HIGH)
0862 return;
0863 } else {
0864 return;
0865 }
0866
0867 new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL);
0868 if (!new_lt)
0869 return;
0870
0871 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
0872 if (f->bb == 4 && bb == 8) {
0873 pipapo_lt_4b_to_8b(f->groups, f->bsize,
0874 NFT_PIPAPO_LT_ALIGN(f->lt),
0875 NFT_PIPAPO_LT_ALIGN(new_lt));
0876 } else if (f->bb == 8 && bb == 4) {
0877 pipapo_lt_8b_to_4b(f->groups, f->bsize,
0878 NFT_PIPAPO_LT_ALIGN(f->lt),
0879 NFT_PIPAPO_LT_ALIGN(new_lt));
0880 } else {
0881 BUG();
0882 }
0883
0884 f->groups = groups;
0885 f->bb = bb;
0886 kvfree(f->lt);
0887 NFT_PIPAPO_LT_ASSIGN(f, new_lt);
0888 }
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901 static int pipapo_insert(struct nft_pipapo_field *f, const uint8_t *k,
0902 int mask_bits)
0903 {
0904 int rule = f->rules++, group, ret, bit_offset = 0;
0905
0906 ret = pipapo_resize(f, f->rules - 1, f->rules);
0907 if (ret)
0908 return ret;
0909
0910 for (group = 0; group < f->groups; group++) {
0911 int i, v;
0912 u8 mask;
0913
0914 v = k[group / (BITS_PER_BYTE / f->bb)];
0915 v &= GENMASK(BITS_PER_BYTE - bit_offset - 1, 0);
0916 v >>= (BITS_PER_BYTE - bit_offset) - f->bb;
0917
0918 bit_offset += f->bb;
0919 bit_offset %= BITS_PER_BYTE;
0920
0921 if (mask_bits >= (group + 1) * f->bb) {
0922
0923 pipapo_bucket_set(f, rule, group, v);
0924 } else if (mask_bits <= group * f->bb) {
0925
0926 for (i = 0; i < NFT_PIPAPO_BUCKETS(f->bb); i++)
0927 pipapo_bucket_set(f, rule, group, i);
0928 } else {
0929
0930 mask = GENMASK(f->bb - 1, 0);
0931 mask >>= mask_bits - group * f->bb;
0932 for (i = 0; i < NFT_PIPAPO_BUCKETS(f->bb); i++) {
0933 if ((i & ~mask) == (v & ~mask))
0934 pipapo_bucket_set(f, rule, group, i);
0935 }
0936 }
0937 }
0938
0939 pipapo_lt_bits_adjust(f);
0940
0941 return 1;
0942 }
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954 static bool pipapo_step_diff(u8 *base, int step, int len)
0955 {
0956
0957 #ifdef __BIG_ENDIAN__
0958 return !(BIT(step % BITS_PER_BYTE) & base[step / BITS_PER_BYTE]);
0959 #else
0960 return !(BIT(step % BITS_PER_BYTE) &
0961 base[len - 1 - step / BITS_PER_BYTE]);
0962 #endif
0963 }
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976 static bool pipapo_step_after_end(const u8 *base, const u8 *end, int step,
0977 int len)
0978 {
0979 u8 tmp[NFT_PIPAPO_MAX_BYTES];
0980 int i;
0981
0982 memcpy(tmp, base, len);
0983
0984
0985 for (i = 0; i <= step; i++)
0986 #ifdef __BIG_ENDIAN__
0987 tmp[i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);
0988 #else
0989 tmp[len - 1 - i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);
0990 #endif
0991
0992 return memcmp(tmp, end, len) > 0;
0993 }
0994
0995
0996
0997
0998
0999
1000
1001 static void pipapo_base_sum(u8 *base, int step, int len)
1002 {
1003 bool carry = false;
1004 int i;
1005
1006
1007 #ifdef __BIG_ENDIAN__
1008 for (i = step / BITS_PER_BYTE; i < len; i++) {
1009 #else
1010 for (i = len - 1 - step / BITS_PER_BYTE; i >= 0; i--) {
1011 #endif
1012 if (carry)
1013 base[i]++;
1014 else
1015 base[i] += 1 << (step % BITS_PER_BYTE);
1016
1017 if (base[i])
1018 break;
1019
1020 carry = true;
1021 }
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 static int pipapo_expand(struct nft_pipapo_field *f,
1037 const u8 *start, const u8 *end, int len)
1038 {
1039 int step, masks = 0, bytes = DIV_ROUND_UP(len, BITS_PER_BYTE);
1040 u8 base[NFT_PIPAPO_MAX_BYTES];
1041
1042 memcpy(base, start, bytes);
1043 while (memcmp(base, end, bytes) <= 0) {
1044 int err;
1045
1046 step = 0;
1047 while (pipapo_step_diff(base, step, bytes)) {
1048 if (pipapo_step_after_end(base, end, step, bytes))
1049 break;
1050
1051 step++;
1052 if (step >= len) {
1053 if (!masks) {
1054 pipapo_insert(f, base, 0);
1055 masks = 1;
1056 }
1057 goto out;
1058 }
1059 }
1060
1061 err = pipapo_insert(f, base, len - step);
1062
1063 if (err < 0)
1064 return err;
1065
1066 masks++;
1067 pipapo_base_sum(base, step, bytes);
1068 }
1069 out:
1070 return masks;
1071 }
1072
1073
1074
1075
1076
1077
1078
1079
1080 static void pipapo_map(struct nft_pipapo_match *m,
1081 union nft_pipapo_map_bucket map[NFT_PIPAPO_MAX_FIELDS],
1082 struct nft_pipapo_elem *e)
1083 {
1084 struct nft_pipapo_field *f;
1085 int i, j;
1086
1087 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++) {
1088 for (j = 0; j < map[i].n; j++) {
1089 f->mt[map[i].to + j].to = map[i + 1].to;
1090 f->mt[map[i].to + j].n = map[i + 1].n;
1091 }
1092 }
1093
1094
1095 for (j = 0; j < map[i].n; j++)
1096 f->mt[map[i].to + j].e = e;
1097 }
1098
1099
1100
1101
1102
1103
1104
1105
1106 static int pipapo_realloc_scratch(struct nft_pipapo_match *clone,
1107 unsigned long bsize_max)
1108 {
1109 int i;
1110
1111 for_each_possible_cpu(i) {
1112 unsigned long *scratch;
1113 #ifdef NFT_PIPAPO_ALIGN
1114 unsigned long *scratch_aligned;
1115 #endif
1116
1117 scratch = kzalloc_node(bsize_max * sizeof(*scratch) * 2 +
1118 NFT_PIPAPO_ALIGN_HEADROOM,
1119 GFP_KERNEL, cpu_to_node(i));
1120 if (!scratch) {
1121
1122
1123
1124
1125
1126
1127
1128 return -ENOMEM;
1129 }
1130
1131 kfree(*per_cpu_ptr(clone->scratch, i));
1132
1133 *per_cpu_ptr(clone->scratch, i) = scratch;
1134
1135 #ifdef NFT_PIPAPO_ALIGN
1136 scratch_aligned = NFT_PIPAPO_LT_ALIGN(scratch);
1137 *per_cpu_ptr(clone->scratch_aligned, i) = scratch_aligned;
1138 #endif
1139 }
1140
1141 return 0;
1142 }
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153 static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
1154 const struct nft_set_elem *elem,
1155 struct nft_set_ext **ext2)
1156 {
1157 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
1158 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1159 const u8 *start = (const u8 *)elem->key.val.data, *end;
1160 struct nft_pipapo_elem *e = elem->priv, *dup;
1161 struct nft_pipapo *priv = nft_set_priv(set);
1162 struct nft_pipapo_match *m = priv->clone;
1163 u8 genmask = nft_genmask_next(net);
1164 struct nft_pipapo_field *f;
1165 int i, bsize_max, err = 0;
1166
1167 if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
1168 end = (const u8 *)nft_set_ext_key_end(ext)->data;
1169 else
1170 end = start;
1171
1172 dup = pipapo_get(net, set, start, genmask);
1173 if (!IS_ERR(dup)) {
1174
1175 const struct nft_data *dup_key, *dup_end;
1176
1177 dup_key = nft_set_ext_key(&dup->ext);
1178 if (nft_set_ext_exists(&dup->ext, NFT_SET_EXT_KEY_END))
1179 dup_end = nft_set_ext_key_end(&dup->ext);
1180 else
1181 dup_end = dup_key;
1182
1183 if (!memcmp(start, dup_key->data, sizeof(*dup_key->data)) &&
1184 !memcmp(end, dup_end->data, sizeof(*dup_end->data))) {
1185 *ext2 = &dup->ext;
1186 return -EEXIST;
1187 }
1188
1189 return -ENOTEMPTY;
1190 }
1191
1192 if (PTR_ERR(dup) == -ENOENT) {
1193
1194 dup = pipapo_get(net, set, end, nft_genmask_next(net));
1195 }
1196
1197 if (PTR_ERR(dup) != -ENOENT) {
1198 if (IS_ERR(dup))
1199 return PTR_ERR(dup);
1200 *ext2 = &dup->ext;
1201 return -ENOTEMPTY;
1202 }
1203
1204
1205 nft_pipapo_for_each_field(f, i, m) {
1206 const u8 *start_p = start, *end_p = end;
1207
1208 if (f->rules >= (unsigned long)NFT_PIPAPO_RULE0_MAX)
1209 return -ENOSPC;
1210
1211 if (memcmp(start_p, end_p,
1212 f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f)) > 0)
1213 return -EINVAL;
1214
1215 start_p += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1216 end_p += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1217 }
1218
1219
1220 priv->dirty = true;
1221
1222 bsize_max = m->bsize_max;
1223
1224 nft_pipapo_for_each_field(f, i, m) {
1225 int ret;
1226
1227 rulemap[i].to = f->rules;
1228
1229 ret = memcmp(start, end,
1230 f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f));
1231 if (!ret)
1232 ret = pipapo_insert(f, start, f->groups * f->bb);
1233 else
1234 ret = pipapo_expand(f, start, end, f->groups * f->bb);
1235
1236 if (f->bsize > bsize_max)
1237 bsize_max = f->bsize;
1238
1239 rulemap[i].n = ret;
1240
1241 start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1242 end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1243 }
1244
1245 if (!*get_cpu_ptr(m->scratch) || bsize_max > m->bsize_max) {
1246 put_cpu_ptr(m->scratch);
1247
1248 err = pipapo_realloc_scratch(m, bsize_max);
1249 if (err)
1250 return err;
1251
1252 m->bsize_max = bsize_max;
1253 } else {
1254 put_cpu_ptr(m->scratch);
1255 }
1256
1257 *ext2 = &e->ext;
1258
1259 pipapo_map(m, rulemap, e);
1260
1261 return 0;
1262 }
1263
1264
1265
1266
1267
1268
1269
1270 static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
1271 {
1272 struct nft_pipapo_field *dst, *src;
1273 struct nft_pipapo_match *new;
1274 int i;
1275
1276 new = kmalloc(sizeof(*new) + sizeof(*dst) * old->field_count,
1277 GFP_KERNEL);
1278 if (!new)
1279 return ERR_PTR(-ENOMEM);
1280
1281 new->field_count = old->field_count;
1282 new->bsize_max = old->bsize_max;
1283
1284 new->scratch = alloc_percpu(*new->scratch);
1285 if (!new->scratch)
1286 goto out_scratch;
1287
1288 #ifdef NFT_PIPAPO_ALIGN
1289 new->scratch_aligned = alloc_percpu(*new->scratch_aligned);
1290 if (!new->scratch_aligned)
1291 goto out_scratch;
1292 #endif
1293 for_each_possible_cpu(i)
1294 *per_cpu_ptr(new->scratch, i) = NULL;
1295
1296 if (pipapo_realloc_scratch(new, old->bsize_max))
1297 goto out_scratch_realloc;
1298
1299 rcu_head_init(&new->rcu);
1300
1301 src = old->f;
1302 dst = new->f;
1303
1304 for (i = 0; i < old->field_count; i++) {
1305 unsigned long *new_lt;
1306
1307 memcpy(dst, src, offsetof(struct nft_pipapo_field, lt));
1308
1309 new_lt = kvzalloc(src->groups * NFT_PIPAPO_BUCKETS(src->bb) *
1310 src->bsize * sizeof(*dst->lt) +
1311 NFT_PIPAPO_ALIGN_HEADROOM,
1312 GFP_KERNEL);
1313 if (!new_lt)
1314 goto out_lt;
1315
1316 NFT_PIPAPO_LT_ASSIGN(dst, new_lt);
1317
1318 memcpy(NFT_PIPAPO_LT_ALIGN(new_lt),
1319 NFT_PIPAPO_LT_ALIGN(src->lt),
1320 src->bsize * sizeof(*dst->lt) *
1321 src->groups * NFT_PIPAPO_BUCKETS(src->bb));
1322
1323 dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL);
1324 if (!dst->mt)
1325 goto out_mt;
1326
1327 memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt));
1328 src++;
1329 dst++;
1330 }
1331
1332 return new;
1333
1334 out_mt:
1335 kvfree(dst->lt);
1336 out_lt:
1337 for (dst--; i > 0; i--) {
1338 kvfree(dst->mt);
1339 kvfree(dst->lt);
1340 dst--;
1341 }
1342 out_scratch_realloc:
1343 for_each_possible_cpu(i)
1344 kfree(*per_cpu_ptr(new->scratch, i));
1345 #ifdef NFT_PIPAPO_ALIGN
1346 free_percpu(new->scratch_aligned);
1347 #endif
1348 out_scratch:
1349 free_percpu(new->scratch);
1350 kfree(new);
1351
1352 return ERR_PTR(-ENOMEM);
1353 }
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384 static int pipapo_rules_same_key(struct nft_pipapo_field *f, int first)
1385 {
1386 struct nft_pipapo_elem *e = NULL;
1387 int r;
1388
1389 for (r = first; r < f->rules; r++) {
1390 if (r != first && e != f->mt[r].e)
1391 return r - first;
1392
1393 e = f->mt[r].e;
1394 }
1395
1396 if (r != first)
1397 return r - first;
1398
1399 return 0;
1400 }
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440 static void pipapo_unmap(union nft_pipapo_map_bucket *mt, int rules,
1441 int start, int n, int to_offset, bool is_last)
1442 {
1443 int i;
1444
1445 memmove(mt + start, mt + start + n, (rules - start - n) * sizeof(*mt));
1446 memset(mt + rules - n, 0, n * sizeof(*mt));
1447
1448 if (is_last)
1449 return;
1450
1451 for (i = start; i < rules - n; i++)
1452 mt[i].to -= to_offset;
1453 }
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492 static void pipapo_drop(struct nft_pipapo_match *m,
1493 union nft_pipapo_map_bucket rulemap[])
1494 {
1495 struct nft_pipapo_field *f;
1496 int i;
1497
1498 nft_pipapo_for_each_field(f, i, m) {
1499 int g;
1500
1501 for (g = 0; g < f->groups; g++) {
1502 unsigned long *pos;
1503 int b;
1504
1505 pos = NFT_PIPAPO_LT_ALIGN(f->lt) + g *
1506 NFT_PIPAPO_BUCKETS(f->bb) * f->bsize;
1507
1508 for (b = 0; b < NFT_PIPAPO_BUCKETS(f->bb); b++) {
1509 bitmap_cut(pos, pos, rulemap[i].to,
1510 rulemap[i].n,
1511 f->bsize * BITS_PER_LONG);
1512
1513 pos += f->bsize;
1514 }
1515 }
1516
1517 pipapo_unmap(f->mt, f->rules, rulemap[i].to, rulemap[i].n,
1518 rulemap[i + 1].n, i == m->field_count - 1);
1519 if (pipapo_resize(f, f->rules, f->rules - rulemap[i].n)) {
1520
1521
1522
1523 ;
1524 }
1525 f->rules -= rulemap[i].n;
1526
1527 pipapo_lt_bits_adjust(f);
1528 }
1529 }
1530
1531
1532
1533
1534
1535
1536 static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
1537 {
1538 struct nft_pipapo *priv = nft_set_priv(set);
1539 int rules_f0, first_rule = 0;
1540 struct nft_pipapo_elem *e;
1541
1542 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1543 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1544 struct nft_pipapo_field *f;
1545 int i, start, rules_fx;
1546
1547 start = first_rule;
1548 rules_fx = rules_f0;
1549
1550 nft_pipapo_for_each_field(f, i, m) {
1551 rulemap[i].to = start;
1552 rulemap[i].n = rules_fx;
1553
1554 if (i < m->field_count - 1) {
1555 rules_fx = f->mt[start].n;
1556 start = f->mt[start].to;
1557 }
1558 }
1559
1560
1561 f--;
1562 i--;
1563 e = f->mt[rulemap[i].to].e;
1564 if (nft_set_elem_expired(&e->ext) &&
1565 !nft_set_elem_mark_busy(&e->ext)) {
1566 priv->dirty = true;
1567 pipapo_drop(m, rulemap);
1568
1569 rcu_barrier();
1570 nft_set_elem_destroy(set, e, true);
1571
1572
1573
1574
1575 } else {
1576 first_rule += rules_f0;
1577 }
1578 }
1579
1580 e = nft_set_catchall_gc(set);
1581 if (e)
1582 nft_set_elem_destroy(set, e, true);
1583
1584 priv->last_gc = jiffies;
1585 }
1586
1587
1588
1589
1590
1591 static void pipapo_free_fields(struct nft_pipapo_match *m)
1592 {
1593 struct nft_pipapo_field *f;
1594 int i;
1595
1596 nft_pipapo_for_each_field(f, i, m) {
1597 kvfree(f->lt);
1598 kvfree(f->mt);
1599 }
1600 }
1601
1602
1603
1604
1605
1606 static void pipapo_reclaim_match(struct rcu_head *rcu)
1607 {
1608 struct nft_pipapo_match *m;
1609 int i;
1610
1611 m = container_of(rcu, struct nft_pipapo_match, rcu);
1612
1613 for_each_possible_cpu(i)
1614 kfree(*per_cpu_ptr(m->scratch, i));
1615
1616 #ifdef NFT_PIPAPO_ALIGN
1617 free_percpu(m->scratch_aligned);
1618 #endif
1619 free_percpu(m->scratch);
1620
1621 pipapo_free_fields(m);
1622
1623 kfree(m);
1624 }
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637 static void pipapo_commit(const struct nft_set *set)
1638 {
1639 struct nft_pipapo *priv = nft_set_priv(set);
1640 struct nft_pipapo_match *new_clone, *old;
1641
1642 if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
1643 pipapo_gc(set, priv->clone);
1644
1645 if (!priv->dirty)
1646 return;
1647
1648 new_clone = pipapo_clone(priv->clone);
1649 if (IS_ERR(new_clone))
1650 return;
1651
1652 priv->dirty = false;
1653
1654 old = rcu_access_pointer(priv->match);
1655 rcu_assign_pointer(priv->match, priv->clone);
1656 if (old)
1657 call_rcu(&old->rcu, pipapo_reclaim_match);
1658
1659 priv->clone = new_clone;
1660 }
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674 static void nft_pipapo_activate(const struct net *net,
1675 const struct nft_set *set,
1676 const struct nft_set_elem *elem)
1677 {
1678 struct nft_pipapo_elem *e;
1679
1680 e = pipapo_get(net, set, (const u8 *)elem->key.val.data, 0);
1681 if (IS_ERR(e))
1682 return;
1683
1684 nft_set_elem_change_active(net, set, &e->ext);
1685 nft_set_elem_clear_busy(&e->ext);
1686
1687 pipapo_commit(set);
1688 }
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703 static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
1704 const u8 *data, const struct nft_set_ext *ext)
1705 {
1706 struct nft_pipapo_elem *e;
1707
1708 e = pipapo_get(net, set, data, nft_genmask_next(net));
1709 if (IS_ERR(e))
1710 return NULL;
1711
1712 nft_set_elem_change_active(net, set, &e->ext);
1713
1714 return e;
1715 }
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725 static void *nft_pipapo_deactivate(const struct net *net,
1726 const struct nft_set *set,
1727 const struct nft_set_elem *elem)
1728 {
1729 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
1730
1731 return pipapo_deactivate(net, set, (const u8 *)elem->key.val.data, ext);
1732 }
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752 static bool nft_pipapo_flush(const struct net *net, const struct nft_set *set,
1753 void *elem)
1754 {
1755 struct nft_pipapo_elem *e = elem;
1756
1757 return pipapo_deactivate(net, set, (const u8 *)nft_set_ext_key(&e->ext),
1758 &e->ext);
1759 }
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808 static int pipapo_get_boundaries(struct nft_pipapo_field *f, int first_rule,
1809 int rule_count, u8 *left, u8 *right)
1810 {
1811 int g, mask_len = 0, bit_offset = 0;
1812 u8 *l = left, *r = right;
1813
1814 for (g = 0; g < f->groups; g++) {
1815 int b, x0, x1;
1816
1817 x0 = -1;
1818 x1 = -1;
1819 for (b = 0; b < NFT_PIPAPO_BUCKETS(f->bb); b++) {
1820 unsigned long *pos;
1821
1822 pos = NFT_PIPAPO_LT_ALIGN(f->lt) +
1823 (g * NFT_PIPAPO_BUCKETS(f->bb) + b) * f->bsize;
1824 if (test_bit(first_rule, pos) && x0 == -1)
1825 x0 = b;
1826 if (test_bit(first_rule + rule_count - 1, pos))
1827 x1 = b;
1828 }
1829
1830 *l |= x0 << (BITS_PER_BYTE - f->bb - bit_offset);
1831 *r |= x1 << (BITS_PER_BYTE - f->bb - bit_offset);
1832
1833 bit_offset += f->bb;
1834 if (bit_offset >= BITS_PER_BYTE) {
1835 bit_offset %= BITS_PER_BYTE;
1836 l++;
1837 r++;
1838 }
1839
1840 if (x1 - x0 == 0)
1841 mask_len += 4;
1842 else if (x1 - x0 == 1)
1843 mask_len += 3;
1844 else if (x1 - x0 == 3)
1845 mask_len += 2;
1846 else if (x1 - x0 == 7)
1847 mask_len += 1;
1848 }
1849
1850 return mask_len;
1851 }
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863 static bool pipapo_match_field(struct nft_pipapo_field *f,
1864 int first_rule, int rule_count,
1865 const u8 *start, const u8 *end)
1866 {
1867 u8 right[NFT_PIPAPO_MAX_BYTES] = { 0 };
1868 u8 left[NFT_PIPAPO_MAX_BYTES] = { 0 };
1869
1870 pipapo_get_boundaries(f, first_rule, rule_count, left, right);
1871
1872 return !memcmp(start, left,
1873 f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f)) &&
1874 !memcmp(end, right, f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f));
1875 }
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888 static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
1889 const struct nft_set_elem *elem)
1890 {
1891 struct nft_pipapo *priv = nft_set_priv(set);
1892 struct nft_pipapo_match *m = priv->clone;
1893 struct nft_pipapo_elem *e = elem->priv;
1894 int rules_f0, first_rule = 0;
1895 const u8 *data;
1896
1897 data = (const u8 *)nft_set_ext_key(&e->ext);
1898
1899 e = pipapo_get(net, set, data, 0);
1900 if (IS_ERR(e))
1901 return;
1902
1903 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1904 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1905 const u8 *match_start, *match_end;
1906 struct nft_pipapo_field *f;
1907 int i, start, rules_fx;
1908
1909 match_start = data;
1910 match_end = (const u8 *)nft_set_ext_key_end(&e->ext)->data;
1911
1912 start = first_rule;
1913 rules_fx = rules_f0;
1914
1915 nft_pipapo_for_each_field(f, i, m) {
1916 if (!pipapo_match_field(f, start, rules_fx,
1917 match_start, match_end))
1918 break;
1919
1920 rulemap[i].to = start;
1921 rulemap[i].n = rules_fx;
1922
1923 rules_fx = f->mt[start].n;
1924 start = f->mt[start].to;
1925
1926 match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1927 match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1928 }
1929
1930 if (i == m->field_count) {
1931 priv->dirty = true;
1932 pipapo_drop(m, rulemap);
1933 pipapo_commit(set);
1934 return;
1935 }
1936
1937 first_rule += rules_f0;
1938 }
1939 }
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951 static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
1952 struct nft_set_iter *iter)
1953 {
1954 struct nft_pipapo *priv = nft_set_priv(set);
1955 struct nft_pipapo_match *m;
1956 struct nft_pipapo_field *f;
1957 int i, r;
1958
1959 rcu_read_lock();
1960 m = rcu_dereference(priv->match);
1961
1962 if (unlikely(!m))
1963 goto out;
1964
1965 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
1966 ;
1967
1968 for (r = 0; r < f->rules; r++) {
1969 struct nft_pipapo_elem *e;
1970 struct nft_set_elem elem;
1971
1972 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
1973 continue;
1974
1975 if (iter->count < iter->skip)
1976 goto cont;
1977
1978 e = f->mt[r].e;
1979 if (nft_set_elem_expired(&e->ext))
1980 goto cont;
1981
1982 elem.priv = e;
1983
1984 iter->err = iter->fn(ctx, set, iter, &elem);
1985 if (iter->err < 0)
1986 goto out;
1987
1988 cont:
1989 iter->count++;
1990 }
1991
1992 out:
1993 rcu_read_unlock();
1994 }
1995
1996
1997
1998
1999
2000
2001
2002
2003 static u64 nft_pipapo_privsize(const struct nlattr * const nla[],
2004 const struct nft_set_desc *desc)
2005 {
2006 return sizeof(struct nft_pipapo);
2007 }
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017 static bool nft_pipapo_estimate(const struct nft_set_desc *desc, u32 features,
2018 struct nft_set_estimate *est)
2019 {
2020 if (!(features & NFT_SET_INTERVAL) ||
2021 desc->field_count < NFT_PIPAPO_MIN_FIELDS)
2022 return false;
2023
2024 est->size = pipapo_estimate_size(desc);
2025 if (!est->size)
2026 return false;
2027
2028 est->lookup = NFT_SET_CLASS_O_LOG_N;
2029
2030 est->space = NFT_SET_CLASS_O_N;
2031
2032 return true;
2033 }
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047 static int nft_pipapo_init(const struct nft_set *set,
2048 const struct nft_set_desc *desc,
2049 const struct nlattr * const nla[])
2050 {
2051 struct nft_pipapo *priv = nft_set_priv(set);
2052 struct nft_pipapo_match *m;
2053 struct nft_pipapo_field *f;
2054 int err, i, field_count;
2055
2056 field_count = desc->field_count ? : 1;
2057
2058 if (field_count > NFT_PIPAPO_MAX_FIELDS)
2059 return -EINVAL;
2060
2061 m = kmalloc(sizeof(*priv->match) + sizeof(*f) * field_count,
2062 GFP_KERNEL);
2063 if (!m)
2064 return -ENOMEM;
2065
2066 m->field_count = field_count;
2067 m->bsize_max = 0;
2068
2069 m->scratch = alloc_percpu(unsigned long *);
2070 if (!m->scratch) {
2071 err = -ENOMEM;
2072 goto out_scratch;
2073 }
2074 for_each_possible_cpu(i)
2075 *per_cpu_ptr(m->scratch, i) = NULL;
2076
2077 #ifdef NFT_PIPAPO_ALIGN
2078 m->scratch_aligned = alloc_percpu(unsigned long *);
2079 if (!m->scratch_aligned) {
2080 err = -ENOMEM;
2081 goto out_free;
2082 }
2083 for_each_possible_cpu(i)
2084 *per_cpu_ptr(m->scratch_aligned, i) = NULL;
2085 #endif
2086
2087 rcu_head_init(&m->rcu);
2088
2089 nft_pipapo_for_each_field(f, i, m) {
2090 int len = desc->field_len[i] ? : set->klen;
2091
2092 f->bb = NFT_PIPAPO_GROUP_BITS_INIT;
2093 f->groups = len * NFT_PIPAPO_GROUPS_PER_BYTE(f);
2094
2095 priv->width += round_up(len, sizeof(u32));
2096
2097 f->bsize = 0;
2098 f->rules = 0;
2099 NFT_PIPAPO_LT_ASSIGN(f, NULL);
2100 f->mt = NULL;
2101 }
2102
2103
2104 priv->clone = pipapo_clone(m);
2105 if (IS_ERR(priv->clone)) {
2106 err = PTR_ERR(priv->clone);
2107 goto out_free;
2108 }
2109
2110 priv->dirty = false;
2111
2112 rcu_assign_pointer(priv->match, m);
2113
2114 return 0;
2115
2116 out_free:
2117 #ifdef NFT_PIPAPO_ALIGN
2118 free_percpu(m->scratch_aligned);
2119 #endif
2120 free_percpu(m->scratch);
2121 out_scratch:
2122 kfree(m);
2123
2124 return err;
2125 }
2126
2127
2128
2129
2130
2131
2132 static void nft_set_pipapo_match_destroy(const struct nft_set *set,
2133 struct nft_pipapo_match *m)
2134 {
2135 struct nft_pipapo_field *f;
2136 int i, r;
2137
2138 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
2139 ;
2140
2141 for (r = 0; r < f->rules; r++) {
2142 struct nft_pipapo_elem *e;
2143
2144 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
2145 continue;
2146
2147 e = f->mt[r].e;
2148
2149 nft_set_elem_destroy(set, e, true);
2150 }
2151 }
2152
2153
2154
2155
2156
2157 static void nft_pipapo_destroy(const struct nft_set *set)
2158 {
2159 struct nft_pipapo *priv = nft_set_priv(set);
2160 struct nft_pipapo_match *m;
2161 int cpu;
2162
2163 m = rcu_dereference_protected(priv->match, true);
2164 if (m) {
2165 rcu_barrier();
2166
2167 nft_set_pipapo_match_destroy(set, m);
2168
2169 #ifdef NFT_PIPAPO_ALIGN
2170 free_percpu(m->scratch_aligned);
2171 #endif
2172 for_each_possible_cpu(cpu)
2173 kfree(*per_cpu_ptr(m->scratch, cpu));
2174 free_percpu(m->scratch);
2175 pipapo_free_fields(m);
2176 kfree(m);
2177 priv->match = NULL;
2178 }
2179
2180 if (priv->clone) {
2181 m = priv->clone;
2182
2183 if (priv->dirty)
2184 nft_set_pipapo_match_destroy(set, m);
2185
2186 #ifdef NFT_PIPAPO_ALIGN
2187 free_percpu(priv->clone->scratch_aligned);
2188 #endif
2189 for_each_possible_cpu(cpu)
2190 kfree(*per_cpu_ptr(priv->clone->scratch, cpu));
2191 free_percpu(priv->clone->scratch);
2192
2193 pipapo_free_fields(priv->clone);
2194 kfree(priv->clone);
2195 priv->clone = NULL;
2196 }
2197 }
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208 static void nft_pipapo_gc_init(const struct nft_set *set)
2209 {
2210 struct nft_pipapo *priv = nft_set_priv(set);
2211
2212 priv->last_gc = jiffies;
2213 }
2214
2215 const struct nft_set_type nft_set_pipapo_type = {
2216 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2217 NFT_SET_TIMEOUT,
2218 .ops = {
2219 .lookup = nft_pipapo_lookup,
2220 .insert = nft_pipapo_insert,
2221 .activate = nft_pipapo_activate,
2222 .deactivate = nft_pipapo_deactivate,
2223 .flush = nft_pipapo_flush,
2224 .remove = nft_pipapo_remove,
2225 .walk = nft_pipapo_walk,
2226 .get = nft_pipapo_get,
2227 .privsize = nft_pipapo_privsize,
2228 .estimate = nft_pipapo_estimate,
2229 .init = nft_pipapo_init,
2230 .destroy = nft_pipapo_destroy,
2231 .gc_init = nft_pipapo_gc_init,
2232 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2233 },
2234 };
2235
2236 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
2237 const struct nft_set_type nft_set_pipapo_avx2_type = {
2238 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2239 NFT_SET_TIMEOUT,
2240 .ops = {
2241 .lookup = nft_pipapo_avx2_lookup,
2242 .insert = nft_pipapo_insert,
2243 .activate = nft_pipapo_activate,
2244 .deactivate = nft_pipapo_deactivate,
2245 .flush = nft_pipapo_flush,
2246 .remove = nft_pipapo_remove,
2247 .walk = nft_pipapo_walk,
2248 .get = nft_pipapo_get,
2249 .privsize = nft_pipapo_privsize,
2250 .estimate = nft_pipapo_avx2_estimate,
2251 .init = nft_pipapo_init,
2252 .destroy = nft_pipapo_destroy,
2253 .gc_init = nft_pipapo_gc_init,
2254 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2255 },
2256 };
2257 #endif