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
1294 rcu_head_init(&new->rcu);
1295
1296 src = old->f;
1297 dst = new->f;
1298
1299 for (i = 0; i < old->field_count; i++) {
1300 unsigned long *new_lt;
1301
1302 memcpy(dst, src, offsetof(struct nft_pipapo_field, lt));
1303
1304 new_lt = kvzalloc(src->groups * NFT_PIPAPO_BUCKETS(src->bb) *
1305 src->bsize * sizeof(*dst->lt) +
1306 NFT_PIPAPO_ALIGN_HEADROOM,
1307 GFP_KERNEL);
1308 if (!new_lt)
1309 goto out_lt;
1310
1311 NFT_PIPAPO_LT_ASSIGN(dst, new_lt);
1312
1313 memcpy(NFT_PIPAPO_LT_ALIGN(new_lt),
1314 NFT_PIPAPO_LT_ALIGN(src->lt),
1315 src->bsize * sizeof(*dst->lt) *
1316 src->groups * NFT_PIPAPO_BUCKETS(src->bb));
1317
1318 dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL);
1319 if (!dst->mt)
1320 goto out_mt;
1321
1322 memcpy(dst->mt, src->mt, src->rules * sizeof(*src->mt));
1323 src++;
1324 dst++;
1325 }
1326
1327 return new;
1328
1329out_mt:
1330 kvfree(dst->lt);
1331out_lt:
1332 for (dst--; i > 0; i--) {
1333 kvfree(dst->mt);
1334 kvfree(dst->lt);
1335 dst--;
1336 }
1337#ifdef NFT_PIPAPO_ALIGN
1338 free_percpu(new->scratch_aligned);
1339#endif
1340out_scratch:
1341 free_percpu(new->scratch);
1342 kfree(new);
1343
1344 return ERR_PTR(-ENOMEM);
1345}
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376static int pipapo_rules_same_key(struct nft_pipapo_field *f, int first)
1377{
1378 struct nft_pipapo_elem *e = NULL;
1379 int r;
1380
1381 for (r = first; r < f->rules; r++) {
1382 if (r != first && e != f->mt[r].e)
1383 return r - first;
1384
1385 e = f->mt[r].e;
1386 }
1387
1388 if (r != first)
1389 return r - first;
1390
1391 return 0;
1392}
1393
1394
1395
1396
1397
1398
1399
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
1432static void pipapo_unmap(union nft_pipapo_map_bucket *mt, int rules,
1433 int start, int n, int to_offset, bool is_last)
1434{
1435 int i;
1436
1437 memmove(mt + start, mt + start + n, (rules - start - n) * sizeof(*mt));
1438 memset(mt + rules - n, 0, n * sizeof(*mt));
1439
1440 if (is_last)
1441 return;
1442
1443 for (i = start; i < rules - n; i++)
1444 mt[i].to -= to_offset;
1445}
1446
1447
1448
1449
1450
1451
1452
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
1484static void pipapo_drop(struct nft_pipapo_match *m,
1485 union nft_pipapo_map_bucket rulemap[])
1486{
1487 struct nft_pipapo_field *f;
1488 int i;
1489
1490 nft_pipapo_for_each_field(f, i, m) {
1491 int g;
1492
1493 for (g = 0; g < f->groups; g++) {
1494 unsigned long *pos;
1495 int b;
1496
1497 pos = NFT_PIPAPO_LT_ALIGN(f->lt) + g *
1498 NFT_PIPAPO_BUCKETS(f->bb) * f->bsize;
1499
1500 for (b = 0; b < NFT_PIPAPO_BUCKETS(f->bb); b++) {
1501 bitmap_cut(pos, pos, rulemap[i].to,
1502 rulemap[i].n,
1503 f->bsize * BITS_PER_LONG);
1504
1505 pos += f->bsize;
1506 }
1507 }
1508
1509 pipapo_unmap(f->mt, f->rules, rulemap[i].to, rulemap[i].n,
1510 rulemap[i + 1].n, i == m->field_count - 1);
1511 if (pipapo_resize(f, f->rules, f->rules - rulemap[i].n)) {
1512
1513
1514
1515 ;
1516 }
1517 f->rules -= rulemap[i].n;
1518
1519 pipapo_lt_bits_adjust(f);
1520 }
1521}
1522
1523
1524
1525
1526
1527
1528static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
1529{
1530 struct nft_pipapo *priv = nft_set_priv(set);
1531 int rules_f0, first_rule = 0;
1532 struct nft_pipapo_elem *e;
1533
1534 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1535 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1536 struct nft_pipapo_field *f;
1537 int i, start, rules_fx;
1538
1539 start = first_rule;
1540 rules_fx = rules_f0;
1541
1542 nft_pipapo_for_each_field(f, i, m) {
1543 rulemap[i].to = start;
1544 rulemap[i].n = rules_fx;
1545
1546 if (i < m->field_count - 1) {
1547 rules_fx = f->mt[start].n;
1548 start = f->mt[start].to;
1549 }
1550 }
1551
1552
1553 f--;
1554 i--;
1555 e = f->mt[rulemap[i].to].e;
1556 if (nft_set_elem_expired(&e->ext) &&
1557 !nft_set_elem_mark_busy(&e->ext)) {
1558 priv->dirty = true;
1559 pipapo_drop(m, rulemap);
1560
1561 rcu_barrier();
1562 nft_set_elem_destroy(set, e, true);
1563
1564
1565
1566
1567 } else {
1568 first_rule += rules_f0;
1569 }
1570 }
1571
1572 e = nft_set_catchall_gc(set);
1573 if (e)
1574 nft_set_elem_destroy(set, e, true);
1575
1576 priv->last_gc = jiffies;
1577}
1578
1579
1580
1581
1582
1583static void pipapo_free_fields(struct nft_pipapo_match *m)
1584{
1585 struct nft_pipapo_field *f;
1586 int i;
1587
1588 nft_pipapo_for_each_field(f, i, m) {
1589 kvfree(f->lt);
1590 kvfree(f->mt);
1591 }
1592}
1593
1594
1595
1596
1597
1598static void pipapo_reclaim_match(struct rcu_head *rcu)
1599{
1600 struct nft_pipapo_match *m;
1601 int i;
1602
1603 m = container_of(rcu, struct nft_pipapo_match, rcu);
1604
1605 for_each_possible_cpu(i)
1606 kfree(*per_cpu_ptr(m->scratch, i));
1607
1608#ifdef NFT_PIPAPO_ALIGN
1609 free_percpu(m->scratch_aligned);
1610#endif
1611 free_percpu(m->scratch);
1612
1613 pipapo_free_fields(m);
1614
1615 kfree(m);
1616}
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629static void pipapo_commit(const struct nft_set *set)
1630{
1631 struct nft_pipapo *priv = nft_set_priv(set);
1632 struct nft_pipapo_match *new_clone, *old;
1633
1634 if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
1635 pipapo_gc(set, priv->clone);
1636
1637 if (!priv->dirty)
1638 return;
1639
1640 new_clone = pipapo_clone(priv->clone);
1641 if (IS_ERR(new_clone))
1642 return;
1643
1644 priv->dirty = false;
1645
1646 old = rcu_access_pointer(priv->match);
1647 rcu_assign_pointer(priv->match, priv->clone);
1648 if (old)
1649 call_rcu(&old->rcu, pipapo_reclaim_match);
1650
1651 priv->clone = new_clone;
1652}
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666static void nft_pipapo_activate(const struct net *net,
1667 const struct nft_set *set,
1668 const struct nft_set_elem *elem)
1669{
1670 struct nft_pipapo_elem *e;
1671
1672 e = pipapo_get(net, set, (const u8 *)elem->key.val.data, 0);
1673 if (IS_ERR(e))
1674 return;
1675
1676 nft_set_elem_change_active(net, set, &e->ext);
1677 nft_set_elem_clear_busy(&e->ext);
1678
1679 pipapo_commit(set);
1680}
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
1696 const u8 *data, const struct nft_set_ext *ext)
1697{
1698 struct nft_pipapo_elem *e;
1699
1700 e = pipapo_get(net, set, data, nft_genmask_next(net));
1701 if (IS_ERR(e))
1702 return NULL;
1703
1704 nft_set_elem_change_active(net, set, &e->ext);
1705
1706 return e;
1707}
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717static void *nft_pipapo_deactivate(const struct net *net,
1718 const struct nft_set *set,
1719 const struct nft_set_elem *elem)
1720{
1721 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
1722
1723 return pipapo_deactivate(net, set, (const u8 *)elem->key.val.data, ext);
1724}
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744static bool nft_pipapo_flush(const struct net *net, const struct nft_set *set,
1745 void *elem)
1746{
1747 struct nft_pipapo_elem *e = elem;
1748
1749 return pipapo_deactivate(net, set, (const u8 *)nft_set_ext_key(&e->ext),
1750 &e->ext);
1751}
1752
1753
1754
1755
1756
1757
1758
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
1800static int pipapo_get_boundaries(struct nft_pipapo_field *f, int first_rule,
1801 int rule_count, u8 *left, u8 *right)
1802{
1803 int g, mask_len = 0, bit_offset = 0;
1804 u8 *l = left, *r = right;
1805
1806 for (g = 0; g < f->groups; g++) {
1807 int b, x0, x1;
1808
1809 x0 = -1;
1810 x1 = -1;
1811 for (b = 0; b < NFT_PIPAPO_BUCKETS(f->bb); b++) {
1812 unsigned long *pos;
1813
1814 pos = NFT_PIPAPO_LT_ALIGN(f->lt) +
1815 (g * NFT_PIPAPO_BUCKETS(f->bb) + b) * f->bsize;
1816 if (test_bit(first_rule, pos) && x0 == -1)
1817 x0 = b;
1818 if (test_bit(first_rule + rule_count - 1, pos))
1819 x1 = b;
1820 }
1821
1822 *l |= x0 << (BITS_PER_BYTE - f->bb - bit_offset);
1823 *r |= x1 << (BITS_PER_BYTE - f->bb - bit_offset);
1824
1825 bit_offset += f->bb;
1826 if (bit_offset >= BITS_PER_BYTE) {
1827 bit_offset %= BITS_PER_BYTE;
1828 l++;
1829 r++;
1830 }
1831
1832 if (x1 - x0 == 0)
1833 mask_len += 4;
1834 else if (x1 - x0 == 1)
1835 mask_len += 3;
1836 else if (x1 - x0 == 3)
1837 mask_len += 2;
1838 else if (x1 - x0 == 7)
1839 mask_len += 1;
1840 }
1841
1842 return mask_len;
1843}
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855static bool pipapo_match_field(struct nft_pipapo_field *f,
1856 int first_rule, int rule_count,
1857 const u8 *start, const u8 *end)
1858{
1859 u8 right[NFT_PIPAPO_MAX_BYTES] = { 0 };
1860 u8 left[NFT_PIPAPO_MAX_BYTES] = { 0 };
1861
1862 pipapo_get_boundaries(f, first_rule, rule_count, left, right);
1863
1864 return !memcmp(start, left,
1865 f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f)) &&
1866 !memcmp(end, right, f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f));
1867}
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
1881 const struct nft_set_elem *elem)
1882{
1883 struct nft_pipapo *priv = nft_set_priv(set);
1884 struct nft_pipapo_match *m = priv->clone;
1885 struct nft_pipapo_elem *e = elem->priv;
1886 int rules_f0, first_rule = 0;
1887 const u8 *data;
1888
1889 data = (const u8 *)nft_set_ext_key(&e->ext);
1890
1891 e = pipapo_get(net, set, data, 0);
1892 if (IS_ERR(e))
1893 return;
1894
1895 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1896 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1897 const u8 *match_start, *match_end;
1898 struct nft_pipapo_field *f;
1899 int i, start, rules_fx;
1900
1901 match_start = data;
1902 match_end = (const u8 *)nft_set_ext_key_end(&e->ext)->data;
1903
1904 start = first_rule;
1905 rules_fx = rules_f0;
1906
1907 nft_pipapo_for_each_field(f, i, m) {
1908 if (!pipapo_match_field(f, start, rules_fx,
1909 match_start, match_end))
1910 break;
1911
1912 rulemap[i].to = start;
1913 rulemap[i].n = rules_fx;
1914
1915 rules_fx = f->mt[start].n;
1916 start = f->mt[start].to;
1917
1918 match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1919 match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1920 }
1921
1922 if (i == m->field_count) {
1923 priv->dirty = true;
1924 pipapo_drop(m, rulemap);
1925 pipapo_commit(set);
1926 return;
1927 }
1928
1929 first_rule += rules_f0;
1930 }
1931}
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
1944 struct nft_set_iter *iter)
1945{
1946 struct nft_pipapo *priv = nft_set_priv(set);
1947 struct nft_pipapo_match *m;
1948 struct nft_pipapo_field *f;
1949 int i, r;
1950
1951 rcu_read_lock();
1952 m = rcu_dereference(priv->match);
1953
1954 if (unlikely(!m))
1955 goto out;
1956
1957 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
1958 ;
1959
1960 for (r = 0; r < f->rules; r++) {
1961 struct nft_pipapo_elem *e;
1962 struct nft_set_elem elem;
1963
1964 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
1965 continue;
1966
1967 if (iter->count < iter->skip)
1968 goto cont;
1969
1970 e = f->mt[r].e;
1971 if (nft_set_elem_expired(&e->ext))
1972 goto cont;
1973
1974 elem.priv = e;
1975
1976 iter->err = iter->fn(ctx, set, iter, &elem);
1977 if (iter->err < 0)
1978 goto out;
1979
1980cont:
1981 iter->count++;
1982 }
1983
1984out:
1985 rcu_read_unlock();
1986}
1987
1988
1989
1990
1991
1992
1993
1994
1995static u64 nft_pipapo_privsize(const struct nlattr * const nla[],
1996 const struct nft_set_desc *desc)
1997{
1998 return sizeof(struct nft_pipapo);
1999}
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009static bool nft_pipapo_estimate(const struct nft_set_desc *desc, u32 features,
2010 struct nft_set_estimate *est)
2011{
2012 if (!(features & NFT_SET_INTERVAL) ||
2013 desc->field_count < NFT_PIPAPO_MIN_FIELDS)
2014 return false;
2015
2016 est->size = pipapo_estimate_size(desc);
2017 if (!est->size)
2018 return false;
2019
2020 est->lookup = NFT_SET_CLASS_O_LOG_N;
2021
2022 est->space = NFT_SET_CLASS_O_N;
2023
2024 return true;
2025}
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039static int nft_pipapo_init(const struct nft_set *set,
2040 const struct nft_set_desc *desc,
2041 const struct nlattr * const nla[])
2042{
2043 struct nft_pipapo *priv = nft_set_priv(set);
2044 struct nft_pipapo_match *m;
2045 struct nft_pipapo_field *f;
2046 int err, i, field_count;
2047
2048 field_count = desc->field_count ? : 1;
2049
2050 if (field_count > NFT_PIPAPO_MAX_FIELDS)
2051 return -EINVAL;
2052
2053 m = kmalloc(sizeof(*priv->match) + sizeof(*f) * field_count,
2054 GFP_KERNEL);
2055 if (!m)
2056 return -ENOMEM;
2057
2058 m->field_count = field_count;
2059 m->bsize_max = 0;
2060
2061 m->scratch = alloc_percpu(unsigned long *);
2062 if (!m->scratch) {
2063 err = -ENOMEM;
2064 goto out_scratch;
2065 }
2066 for_each_possible_cpu(i)
2067 *per_cpu_ptr(m->scratch, i) = NULL;
2068
2069#ifdef NFT_PIPAPO_ALIGN
2070 m->scratch_aligned = alloc_percpu(unsigned long *);
2071 if (!m->scratch_aligned) {
2072 err = -ENOMEM;
2073 goto out_free;
2074 }
2075 for_each_possible_cpu(i)
2076 *per_cpu_ptr(m->scratch_aligned, i) = NULL;
2077#endif
2078
2079 rcu_head_init(&m->rcu);
2080
2081 nft_pipapo_for_each_field(f, i, m) {
2082 int len = desc->field_len[i] ? : set->klen;
2083
2084 f->bb = NFT_PIPAPO_GROUP_BITS_INIT;
2085 f->groups = len * NFT_PIPAPO_GROUPS_PER_BYTE(f);
2086
2087 priv->width += round_up(len, sizeof(u32));
2088
2089 f->bsize = 0;
2090 f->rules = 0;
2091 NFT_PIPAPO_LT_ASSIGN(f, NULL);
2092 f->mt = NULL;
2093 }
2094
2095
2096 priv->clone = pipapo_clone(m);
2097 if (IS_ERR(priv->clone)) {
2098 err = PTR_ERR(priv->clone);
2099 goto out_free;
2100 }
2101
2102 priv->dirty = false;
2103
2104 rcu_assign_pointer(priv->match, m);
2105
2106 return 0;
2107
2108out_free:
2109#ifdef NFT_PIPAPO_ALIGN
2110 free_percpu(m->scratch_aligned);
2111#endif
2112 free_percpu(m->scratch);
2113out_scratch:
2114 kfree(m);
2115
2116 return err;
2117}
2118
2119
2120
2121
2122
2123static void nft_pipapo_destroy(const struct nft_set *set)
2124{
2125 struct nft_pipapo *priv = nft_set_priv(set);
2126 struct nft_pipapo_match *m;
2127 struct nft_pipapo_field *f;
2128 int i, r, cpu;
2129
2130 m = rcu_dereference_protected(priv->match, true);
2131 if (m) {
2132 rcu_barrier();
2133
2134 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
2135 ;
2136
2137 for (r = 0; r < f->rules; r++) {
2138 struct nft_pipapo_elem *e;
2139
2140 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
2141 continue;
2142
2143 e = f->mt[r].e;
2144
2145 nft_set_elem_destroy(set, e, true);
2146 }
2147
2148#ifdef NFT_PIPAPO_ALIGN
2149 free_percpu(m->scratch_aligned);
2150#endif
2151 for_each_possible_cpu(cpu)
2152 kfree(*per_cpu_ptr(m->scratch, cpu));
2153 free_percpu(m->scratch);
2154 pipapo_free_fields(m);
2155 kfree(m);
2156 priv->match = NULL;
2157 }
2158
2159 if (priv->clone) {
2160#ifdef NFT_PIPAPO_ALIGN
2161 free_percpu(priv->clone->scratch_aligned);
2162#endif
2163 for_each_possible_cpu(cpu)
2164 kfree(*per_cpu_ptr(priv->clone->scratch, cpu));
2165 free_percpu(priv->clone->scratch);
2166
2167 pipapo_free_fields(priv->clone);
2168 kfree(priv->clone);
2169 priv->clone = NULL;
2170 }
2171}
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182static void nft_pipapo_gc_init(const struct nft_set *set)
2183{
2184 struct nft_pipapo *priv = nft_set_priv(set);
2185
2186 priv->last_gc = jiffies;
2187}
2188
2189const struct nft_set_type nft_set_pipapo_type = {
2190 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2191 NFT_SET_TIMEOUT,
2192 .ops = {
2193 .lookup = nft_pipapo_lookup,
2194 .insert = nft_pipapo_insert,
2195 .activate = nft_pipapo_activate,
2196 .deactivate = nft_pipapo_deactivate,
2197 .flush = nft_pipapo_flush,
2198 .remove = nft_pipapo_remove,
2199 .walk = nft_pipapo_walk,
2200 .get = nft_pipapo_get,
2201 .privsize = nft_pipapo_privsize,
2202 .estimate = nft_pipapo_estimate,
2203 .init = nft_pipapo_init,
2204 .destroy = nft_pipapo_destroy,
2205 .gc_init = nft_pipapo_gc_init,
2206 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2207 },
2208};
2209
2210#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
2211const struct nft_set_type nft_set_pipapo_avx2_type = {
2212 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2213 NFT_SET_TIMEOUT,
2214 .ops = {
2215 .lookup = nft_pipapo_avx2_lookup,
2216 .insert = nft_pipapo_insert,
2217 .activate = nft_pipapo_activate,
2218 .deactivate = nft_pipapo_deactivate,
2219 .flush = nft_pipapo_flush,
2220 .remove = nft_pipapo_remove,
2221 .walk = nft_pipapo_walk,
2222 .get = nft_pipapo_get,
2223 .privsize = nft_pipapo_privsize,
2224 .estimate = nft_pipapo_avx2_estimate,
2225 .init = nft_pipapo_init,
2226 .destroy = nft_pipapo_destroy,
2227 .gc_init = nft_pipapo_gc_init,
2228 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2229 },
2230};
2231#endif
2232