1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331#include <linux/kernel.h>
332#include <linux/init.h>
333#include <linux/module.h>
334#include <linux/netlink.h>
335#include <linux/netfilter.h>
336#include <linux/netfilter/nf_tables.h>
337#include <net/netfilter/nf_tables_core.h>
338#include <uapi/linux/netfilter/nf_tables.h>
339#include <linux/bitmap.h>
340#include <linux/bitops.h>
341
342#include "nft_set_pipapo_avx2.h"
343#include "nft_set_pipapo.h"
344
345
346static DEFINE_PER_CPU(bool, nft_pipapo_scratch_index);
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365int pipapo_refill(unsigned long *map, int len, int rules, unsigned long *dst,
366 union nft_pipapo_map_bucket *mt, bool match_only)
367{
368 unsigned long bitset;
369 int k, ret = -1;
370
371 for (k = 0; k < len; k++) {
372 bitset = map[k];
373 while (bitset) {
374 unsigned long t = bitset & -bitset;
375 int r = __builtin_ctzl(bitset);
376 int i = k * BITS_PER_LONG + r;
377
378 if (unlikely(i >= rules)) {
379 map[k] = 0;
380 return -1;
381 }
382
383 if (match_only) {
384 bitmap_clear(map, i, 1);
385 return i;
386 }
387
388 ret = 0;
389
390 bitmap_set(dst, mt[i].to, mt[i].n);
391
392 bitset ^= t;
393 }
394 map[k] = 0;
395 }
396
397 return ret;
398}
399
400
401
402
403
404
405
406
407
408
409
410
411bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
412 const u32 *key, const struct nft_set_ext **ext)
413{
414 struct nft_pipapo *priv = nft_set_priv(set);
415 unsigned long *res_map, *fill_map;
416 u8 genmask = nft_genmask_cur(net);
417 const u8 *rp = (const u8 *)key;
418 struct nft_pipapo_match *m;
419 struct nft_pipapo_field *f;
420 bool map_index;
421 int i;
422
423 local_bh_disable();
424
425 map_index = raw_cpu_read(nft_pipapo_scratch_index);
426
427 m = rcu_dereference(priv->match);
428
429 if (unlikely(!m || !*raw_cpu_ptr(m->scratch)))
430 goto out;
431
432 res_map = *raw_cpu_ptr(m->scratch) + (map_index ? m->bsize_max : 0);
433 fill_map = *raw_cpu_ptr(m->scratch) + (map_index ? 0 : m->bsize_max);
434
435 memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
436
437 nft_pipapo_for_each_field(f, i, m) {
438 bool last = i == m->field_count - 1;
439 int b;
440
441
442
443
444 if (likely(f->bb == 8))
445 pipapo_and_field_buckets_8bit(f, res_map, rp);
446 else
447 pipapo_and_field_buckets_4bit(f, res_map, rp);
448 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
449
450 rp += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
451
452
453
454
455
456
457
458
459next_match:
460 b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
461 last);
462 if (b < 0) {
463 raw_cpu_write(nft_pipapo_scratch_index, map_index);
464 local_bh_enable();
465
466 return false;
467 }
468
469 if (last) {
470 *ext = &f->mt[b].e->ext;
471 if (unlikely(nft_set_elem_expired(*ext) ||
472 !nft_set_elem_active(*ext, genmask)))
473 goto next_match;
474
475
476
477
478
479
480 raw_cpu_write(nft_pipapo_scratch_index, map_index);
481 local_bh_enable();
482
483 return true;
484 }
485
486
487
488
489
490 map_index = !map_index;
491 swap(res_map, fill_map);
492
493 rp += NFT_PIPAPO_GROUPS_PADDING(f);
494 }
495
496out:
497 local_bh_enable();
498 return false;
499}
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514static struct nft_pipapo_elem *pipapo_get(const struct net *net,
515 const struct nft_set *set,
516 const u8 *data, u8 genmask)
517{
518 struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
519 struct nft_pipapo *priv = nft_set_priv(set);
520 struct nft_pipapo_match *m = priv->clone;
521 unsigned long *res_map, *fill_map = NULL;
522 struct nft_pipapo_field *f;
523 int i;
524
525 res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
526 if (!res_map) {
527 ret = ERR_PTR(-ENOMEM);
528 goto out;
529 }
530
531 fill_map = kcalloc(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
532 if (!fill_map) {
533 ret = ERR_PTR(-ENOMEM);
534 goto out;
535 }
536
537 memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
538
539 nft_pipapo_for_each_field(f, i, m) {
540 bool last = i == m->field_count - 1;
541 int b;
542
543
544
545
546 if (f->bb == 8)
547 pipapo_and_field_buckets_8bit(f, res_map, data);
548 else if (f->bb == 4)
549 pipapo_and_field_buckets_4bit(f, res_map, data);
550 else
551 BUG();
552
553 data += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
554
555
556
557
558
559
560
561
562next_match:
563 b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
564 last);
565 if (b < 0)
566 goto out;
567
568 if (last) {
569 if (nft_set_elem_expired(&f->mt[b].e->ext) ||
570 (genmask &&
571 !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
572 goto next_match;
573
574 ret = f->mt[b].e;
575 goto out;
576 }
577
578 data += NFT_PIPAPO_GROUPS_PADDING(f);
579
580
581
582
583
584
585 swap(res_map, fill_map);
586 }
587
588out:
589 kfree(fill_map);
590 kfree(res_map);
591 return ret;
592}
593
594
595
596
597
598
599
600
601static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
602 const struct nft_set_elem *elem, unsigned int flags)
603{
604 return pipapo_get(net, set, (const u8 *)elem->key.val.data,
605 nft_genmask_cur(net));
606}
607
608
609
610
611
612
613
614
615
616
617
618
619
620static int pipapo_resize(struct nft_pipapo_field *f, int old_rules, int rules)
621{
622 long *new_lt = NULL, *new_p, *old_lt = f->lt, *old_p;
623 union nft_pipapo_map_bucket *new_mt, *old_mt = f->mt;
624 size_t new_bucket_size, copy;
625 int group, bucket;
626
627 new_bucket_size = DIV_ROUND_UP(rules, BITS_PER_LONG);
628#ifdef NFT_PIPAPO_ALIGN
629 new_bucket_size = roundup(new_bucket_size,
630 NFT_PIPAPO_ALIGN / sizeof(*new_lt));
631#endif
632
633 if (new_bucket_size == f->bsize)
634 goto mt;
635
636 if (new_bucket_size > f->bsize)
637 copy = f->bsize;
638 else
639 copy = new_bucket_size;
640
641 new_lt = kvzalloc(f->groups * NFT_PIPAPO_BUCKETS(f->bb) *
642 new_bucket_size * sizeof(*new_lt) +
643 NFT_PIPAPO_ALIGN_HEADROOM,
644 GFP_KERNEL);
645 if (!new_lt)
646 return -ENOMEM;
647
648 new_p = NFT_PIPAPO_LT_ALIGN(new_lt);
649 old_p = NFT_PIPAPO_LT_ALIGN(old_lt);
650
651 for (group = 0; group < f->groups; group++) {
652 for (bucket = 0; bucket < NFT_PIPAPO_BUCKETS(f->bb); bucket++) {
653 memcpy(new_p, old_p, copy * sizeof(*new_p));
654 new_p += copy;
655 old_p += copy;
656
657 if (new_bucket_size > f->bsize)
658 new_p += new_bucket_size - f->bsize;
659 else
660 old_p += f->bsize - new_bucket_size;
661 }
662 }
663
664mt:
665 new_mt = kvmalloc(rules * sizeof(*new_mt), GFP_KERNEL);
666 if (!new_mt) {
667 kvfree(new_lt);
668 return -ENOMEM;
669 }
670
671 memcpy(new_mt, f->mt, min(old_rules, rules) * sizeof(*new_mt));
672 if (rules > old_rules) {
673 memset(new_mt + old_rules, 0,
674 (rules - old_rules) * sizeof(*new_mt));
675 }
676
677 if (new_lt) {
678 f->bsize = new_bucket_size;
679 NFT_PIPAPO_LT_ASSIGN(f, new_lt);
680 kvfree(old_lt);
681 }
682
683 f->mt = new_mt;
684 kvfree(old_mt);
685
686 return 0;
687}
688
689
690
691
692
693
694
695
696static void pipapo_bucket_set(struct nft_pipapo_field *f, int rule, int group,
697 int v)
698{
699 unsigned long *pos;
700
701 pos = NFT_PIPAPO_LT_ALIGN(f->lt);
702 pos += f->bsize * NFT_PIPAPO_BUCKETS(f->bb) * group;
703 pos += f->bsize * v;
704
705 __set_bit(rule, pos);
706}
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743static void pipapo_lt_4b_to_8b(int old_groups, int bsize,
744 unsigned long *old_lt, unsigned long *new_lt)
745{
746 int g, b, i;
747
748 for (g = 0; g < old_groups / 2; g++) {
749 int src_g0 = g * 2, src_g1 = g * 2 + 1;
750
751 for (b = 0; b < NFT_PIPAPO_BUCKETS(8); b++) {
752 int src_b0 = b / NFT_PIPAPO_BUCKETS(4);
753 int src_b1 = b % NFT_PIPAPO_BUCKETS(4);
754 int src_i0 = src_g0 * NFT_PIPAPO_BUCKETS(4) + src_b0;
755 int src_i1 = src_g1 * NFT_PIPAPO_BUCKETS(4) + src_b1;
756
757 for (i = 0; i < bsize; i++) {
758 *new_lt = old_lt[src_i0 * bsize + i] &
759 old_lt[src_i1 * bsize + i];
760 new_lt++;
761 }
762 }
763 }
764}
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789static void pipapo_lt_8b_to_4b(int old_groups, int bsize,
790 unsigned long *old_lt, unsigned long *new_lt)
791{
792 int g, b, bsrc, i;
793
794 memset(new_lt, 0, old_groups * 2 * NFT_PIPAPO_BUCKETS(4) * bsize *
795 sizeof(unsigned long));
796
797 for (g = 0; g < old_groups * 2; g += 2) {
798 int src_g = g / 2;
799
800 for (b = 0; b < NFT_PIPAPO_BUCKETS(4); b++) {
801 for (bsrc = NFT_PIPAPO_BUCKETS(8) * src_g;
802 bsrc < NFT_PIPAPO_BUCKETS(8) * (src_g + 1);
803 bsrc++) {
804 if (((bsrc & 0xf0) >> 4) != b)
805 continue;
806
807 for (i = 0; i < bsize; i++)
808 new_lt[i] |= old_lt[bsrc * bsize + i];
809 }
810
811 new_lt += bsize;
812 }
813
814 for (b = 0; b < NFT_PIPAPO_BUCKETS(4); b++) {
815 for (bsrc = NFT_PIPAPO_BUCKETS(8) * src_g;
816 bsrc < NFT_PIPAPO_BUCKETS(8) * (src_g + 1);
817 bsrc++) {
818 if ((bsrc & 0x0f) != b)
819 continue;
820
821 for (i = 0; i < bsize; i++)
822 new_lt[i] |= old_lt[bsrc * bsize + i];
823 }
824
825 new_lt += bsize;
826 }
827 }
828}
829
830
831
832
833
834static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f)
835{
836 unsigned long *new_lt;
837 int groups, bb;
838 size_t lt_size;
839
840 lt_size = f->groups * NFT_PIPAPO_BUCKETS(f->bb) * f->bsize *
841 sizeof(*f->lt);
842
843 if (f->bb == NFT_PIPAPO_GROUP_BITS_SMALL_SET &&
844 lt_size > NFT_PIPAPO_LT_SIZE_HIGH) {
845 groups = f->groups * 2;
846 bb = NFT_PIPAPO_GROUP_BITS_LARGE_SET;
847
848 lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
849 sizeof(*f->lt);
850 } else if (f->bb == NFT_PIPAPO_GROUP_BITS_LARGE_SET &&
851 lt_size < NFT_PIPAPO_LT_SIZE_LOW) {
852 groups = f->groups / 2;
853 bb = NFT_PIPAPO_GROUP_BITS_SMALL_SET;
854
855 lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
856 sizeof(*f->lt);
857
858
859
860
861 if (lt_size > NFT_PIPAPO_LT_SIZE_HIGH)
862 return;
863 } else {
864 return;
865 }
866
867 new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL);
868 if (!new_lt)
869 return;
870
871 NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
872 if (f->bb == 4 && bb == 8) {
873 pipapo_lt_4b_to_8b(f->groups, f->bsize,
874 NFT_PIPAPO_LT_ALIGN(f->lt),
875 NFT_PIPAPO_LT_ALIGN(new_lt));
876 } else if (f->bb == 8 && bb == 4) {
877 pipapo_lt_8b_to_4b(f->groups, f->bsize,
878 NFT_PIPAPO_LT_ALIGN(f->lt),
879 NFT_PIPAPO_LT_ALIGN(new_lt));
880 } else {
881 BUG();
882 }
883
884 f->groups = groups;
885 f->bb = bb;
886 kvfree(f->lt);
887 NFT_PIPAPO_LT_ASSIGN(f, new_lt);
888}
889
890
891
892
893
894
895
896
897
898
899
900
901static int pipapo_insert(struct nft_pipapo_field *f, const uint8_t *k,
902 int mask_bits)
903{
904 int rule = f->rules++, group, ret, bit_offset = 0;
905
906 ret = pipapo_resize(f, f->rules - 1, f->rules);
907 if (ret)
908 return ret;
909
910 for (group = 0; group < f->groups; group++) {
911 int i, v;
912 u8 mask;
913
914 v = k[group / (BITS_PER_BYTE / f->bb)];
915 v &= GENMASK(BITS_PER_BYTE - bit_offset - 1, 0);
916 v >>= (BITS_PER_BYTE - bit_offset) - f->bb;
917
918 bit_offset += f->bb;
919 bit_offset %= BITS_PER_BYTE;
920
921 if (mask_bits >= (group + 1) * f->bb) {
922
923 pipapo_bucket_set(f, rule, group, v);
924 } else if (mask_bits <= group * f->bb) {
925
926 for (i = 0; i < NFT_PIPAPO_BUCKETS(f->bb); i++)
927 pipapo_bucket_set(f, rule, group, i);
928 } else {
929
930 mask = GENMASK(f->bb - 1, 0);
931 mask >>= mask_bits - group * f->bb;
932 for (i = 0; i < NFT_PIPAPO_BUCKETS(f->bb); i++) {
933 if ((i & ~mask) == (v & ~mask))
934 pipapo_bucket_set(f, rule, group, i);
935 }
936 }
937 }
938
939 pipapo_lt_bits_adjust(f);
940
941 return 1;
942}
943
944
945
946
947
948
949
950
951
952
953
954static bool pipapo_step_diff(u8 *base, int step, int len)
955{
956
957#ifdef __BIG_ENDIAN__
958 return !(BIT(step % BITS_PER_BYTE) & base[step / BITS_PER_BYTE]);
959#else
960 return !(BIT(step % BITS_PER_BYTE) &
961 base[len - 1 - step / BITS_PER_BYTE]);
962#endif
963}
964
965
966
967
968
969
970
971
972
973
974
975
976static bool pipapo_step_after_end(const u8 *base, const u8 *end, int step,
977 int len)
978{
979 u8 tmp[NFT_PIPAPO_MAX_BYTES];
980 int i;
981
982 memcpy(tmp, base, len);
983
984
985 for (i = 0; i <= step; i++)
986#ifdef __BIG_ENDIAN__
987 tmp[i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);
988#else
989 tmp[len - 1 - i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);
990#endif
991
992 return memcmp(tmp, end, len) > 0;
993}
994
995
996
997
998
999
1000
1001static 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
1036static 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 }
1069out:
1070 return masks;
1071}
1072
1073
1074
1075
1076
1077
1078
1079
1080static 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
1106static 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
1153static 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
1270static 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
1334out_mt:
1335 kvfree(dst->lt);
1336out_lt:
1337 for (dst--; i > 0; i--) {
1338 kvfree(dst->mt);
1339 kvfree(dst->lt);
1340 dst--;
1341 }
1342out_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
1348out_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
1384static 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
1440static 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
1492static 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
1536static 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
1591static 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
1606static 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
1637static 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
1674static 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
1703static 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
1725static 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
1752static 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
1808static 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
1863static 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
1888static 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
1951static 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
1988cont:
1989 iter->count++;
1990 }
1991
1992out:
1993 rcu_read_unlock();
1994}
1995
1996
1997
1998
1999
2000
2001
2002
2003static 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
2017static 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
2047static 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
2116out_free:
2117#ifdef NFT_PIPAPO_ALIGN
2118 free_percpu(m->scratch_aligned);
2119#endif
2120 free_percpu(m->scratch);
2121out_scratch:
2122 kfree(m);
2123
2124 return err;
2125}
2126
2127
2128
2129
2130
2131static void nft_pipapo_destroy(const struct nft_set *set)
2132{
2133 struct nft_pipapo *priv = nft_set_priv(set);
2134 struct nft_pipapo_match *m;
2135 struct nft_pipapo_field *f;
2136 int i, r, cpu;
2137
2138 m = rcu_dereference_protected(priv->match, true);
2139 if (m) {
2140 rcu_barrier();
2141
2142 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
2143 ;
2144
2145 for (r = 0; r < f->rules; r++) {
2146 struct nft_pipapo_elem *e;
2147
2148 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
2149 continue;
2150
2151 e = f->mt[r].e;
2152
2153 nft_set_elem_destroy(set, e, true);
2154 }
2155
2156#ifdef NFT_PIPAPO_ALIGN
2157 free_percpu(m->scratch_aligned);
2158#endif
2159 for_each_possible_cpu(cpu)
2160 kfree(*per_cpu_ptr(m->scratch, cpu));
2161 free_percpu(m->scratch);
2162 pipapo_free_fields(m);
2163 kfree(m);
2164 priv->match = NULL;
2165 }
2166
2167 if (priv->clone) {
2168#ifdef NFT_PIPAPO_ALIGN
2169 free_percpu(priv->clone->scratch_aligned);
2170#endif
2171 for_each_possible_cpu(cpu)
2172 kfree(*per_cpu_ptr(priv->clone->scratch, cpu));
2173 free_percpu(priv->clone->scratch);
2174
2175 pipapo_free_fields(priv->clone);
2176 kfree(priv->clone);
2177 priv->clone = NULL;
2178 }
2179}
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190static void nft_pipapo_gc_init(const struct nft_set *set)
2191{
2192 struct nft_pipapo *priv = nft_set_priv(set);
2193
2194 priv->last_gc = jiffies;
2195}
2196
2197const struct nft_set_type nft_set_pipapo_type = {
2198 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2199 NFT_SET_TIMEOUT,
2200 .ops = {
2201 .lookup = nft_pipapo_lookup,
2202 .insert = nft_pipapo_insert,
2203 .activate = nft_pipapo_activate,
2204 .deactivate = nft_pipapo_deactivate,
2205 .flush = nft_pipapo_flush,
2206 .remove = nft_pipapo_remove,
2207 .walk = nft_pipapo_walk,
2208 .get = nft_pipapo_get,
2209 .privsize = nft_pipapo_privsize,
2210 .estimate = nft_pipapo_estimate,
2211 .init = nft_pipapo_init,
2212 .destroy = nft_pipapo_destroy,
2213 .gc_init = nft_pipapo_gc_init,
2214 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2215 },
2216};
2217
2218#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
2219const struct nft_set_type nft_set_pipapo_avx2_type = {
2220 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2221 NFT_SET_TIMEOUT,
2222 .ops = {
2223 .lookup = nft_pipapo_avx2_lookup,
2224 .insert = nft_pipapo_insert,
2225 .activate = nft_pipapo_activate,
2226 .deactivate = nft_pipapo_deactivate,
2227 .flush = nft_pipapo_flush,
2228 .remove = nft_pipapo_remove,
2229 .walk = nft_pipapo_walk,
2230 .get = nft_pipapo_get,
2231 .privsize = nft_pipapo_privsize,
2232 .estimate = nft_pipapo_avx2_estimate,
2233 .init = nft_pipapo_init,
2234 .destroy = nft_pipapo_destroy,
2235 .gc_init = nft_pipapo_gc_init,
2236 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2237 },
2238};
2239#endif
2240