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
411static bool 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
1533 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1534 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1535 struct nft_pipapo_field *f;
1536 struct nft_pipapo_elem *e;
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 priv->last_gc = jiffies;
1573}
1574
1575
1576
1577
1578
1579static void pipapo_free_fields(struct nft_pipapo_match *m)
1580{
1581 struct nft_pipapo_field *f;
1582 int i;
1583
1584 nft_pipapo_for_each_field(f, i, m) {
1585 kvfree(f->lt);
1586 kvfree(f->mt);
1587 }
1588}
1589
1590
1591
1592
1593
1594static void pipapo_reclaim_match(struct rcu_head *rcu)
1595{
1596 struct nft_pipapo_match *m;
1597 int i;
1598
1599 m = container_of(rcu, struct nft_pipapo_match, rcu);
1600
1601 for_each_possible_cpu(i)
1602 kfree(*per_cpu_ptr(m->scratch, i));
1603
1604#ifdef NFT_PIPAPO_ALIGN
1605 free_percpu(m->scratch_aligned);
1606#endif
1607 free_percpu(m->scratch);
1608
1609 pipapo_free_fields(m);
1610
1611 kfree(m);
1612}
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625static void pipapo_commit(const struct nft_set *set)
1626{
1627 struct nft_pipapo *priv = nft_set_priv(set);
1628 struct nft_pipapo_match *new_clone, *old;
1629
1630 if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
1631 pipapo_gc(set, priv->clone);
1632
1633 if (!priv->dirty)
1634 return;
1635
1636 new_clone = pipapo_clone(priv->clone);
1637 if (IS_ERR(new_clone))
1638 return;
1639
1640 priv->dirty = false;
1641
1642 old = rcu_access_pointer(priv->match);
1643 rcu_assign_pointer(priv->match, priv->clone);
1644 if (old)
1645 call_rcu(&old->rcu, pipapo_reclaim_match);
1646
1647 priv->clone = new_clone;
1648}
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662static void nft_pipapo_activate(const struct net *net,
1663 const struct nft_set *set,
1664 const struct nft_set_elem *elem)
1665{
1666 struct nft_pipapo_elem *e;
1667
1668 e = pipapo_get(net, set, (const u8 *)elem->key.val.data, 0);
1669 if (IS_ERR(e))
1670 return;
1671
1672 nft_set_elem_change_active(net, set, &e->ext);
1673 nft_set_elem_clear_busy(&e->ext);
1674
1675 pipapo_commit(set);
1676}
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
1692 const u8 *data, const struct nft_set_ext *ext)
1693{
1694 struct nft_pipapo_elem *e;
1695
1696 e = pipapo_get(net, set, data, nft_genmask_next(net));
1697 if (IS_ERR(e))
1698 return NULL;
1699
1700 nft_set_elem_change_active(net, set, &e->ext);
1701
1702 return e;
1703}
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713static void *nft_pipapo_deactivate(const struct net *net,
1714 const struct nft_set *set,
1715 const struct nft_set_elem *elem)
1716{
1717 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
1718
1719 return pipapo_deactivate(net, set, (const u8 *)elem->key.val.data, ext);
1720}
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740static bool nft_pipapo_flush(const struct net *net, const struct nft_set *set,
1741 void *elem)
1742{
1743 struct nft_pipapo_elem *e = elem;
1744
1745 return pipapo_deactivate(net, set, (const u8 *)nft_set_ext_key(&e->ext),
1746 &e->ext);
1747}
1748
1749
1750
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
1796static int pipapo_get_boundaries(struct nft_pipapo_field *f, int first_rule,
1797 int rule_count, u8 *left, u8 *right)
1798{
1799 int g, mask_len = 0, bit_offset = 0;
1800 u8 *l = left, *r = right;
1801
1802 for (g = 0; g < f->groups; g++) {
1803 int b, x0, x1;
1804
1805 x0 = -1;
1806 x1 = -1;
1807 for (b = 0; b < NFT_PIPAPO_BUCKETS(f->bb); b++) {
1808 unsigned long *pos;
1809
1810 pos = NFT_PIPAPO_LT_ALIGN(f->lt) +
1811 (g * NFT_PIPAPO_BUCKETS(f->bb) + b) * f->bsize;
1812 if (test_bit(first_rule, pos) && x0 == -1)
1813 x0 = b;
1814 if (test_bit(first_rule + rule_count - 1, pos))
1815 x1 = b;
1816 }
1817
1818 *l |= x0 << (BITS_PER_BYTE - f->bb - bit_offset);
1819 *r |= x1 << (BITS_PER_BYTE - f->bb - bit_offset);
1820
1821 bit_offset += f->bb;
1822 if (bit_offset >= BITS_PER_BYTE) {
1823 bit_offset %= BITS_PER_BYTE;
1824 l++;
1825 r++;
1826 }
1827
1828 if (x1 - x0 == 0)
1829 mask_len += 4;
1830 else if (x1 - x0 == 1)
1831 mask_len += 3;
1832 else if (x1 - x0 == 3)
1833 mask_len += 2;
1834 else if (x1 - x0 == 7)
1835 mask_len += 1;
1836 }
1837
1838 return mask_len;
1839}
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851static bool pipapo_match_field(struct nft_pipapo_field *f,
1852 int first_rule, int rule_count,
1853 const u8 *start, const u8 *end)
1854{
1855 u8 right[NFT_PIPAPO_MAX_BYTES] = { 0 };
1856 u8 left[NFT_PIPAPO_MAX_BYTES] = { 0 };
1857
1858 pipapo_get_boundaries(f, first_rule, rule_count, left, right);
1859
1860 return !memcmp(start, left,
1861 f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f)) &&
1862 !memcmp(end, right, f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f));
1863}
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
1877 const struct nft_set_elem *elem)
1878{
1879 struct nft_pipapo *priv = nft_set_priv(set);
1880 struct nft_pipapo_match *m = priv->clone;
1881 struct nft_pipapo_elem *e = elem->priv;
1882 int rules_f0, first_rule = 0;
1883 const u8 *data;
1884
1885 data = (const u8 *)nft_set_ext_key(&e->ext);
1886
1887 e = pipapo_get(net, set, data, 0);
1888 if (IS_ERR(e))
1889 return;
1890
1891 while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
1892 union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
1893 const u8 *match_start, *match_end;
1894 struct nft_pipapo_field *f;
1895 int i, start, rules_fx;
1896
1897 match_start = data;
1898 match_end = (const u8 *)nft_set_ext_key_end(&e->ext)->data;
1899
1900 start = first_rule;
1901 rules_fx = rules_f0;
1902
1903 nft_pipapo_for_each_field(f, i, m) {
1904 if (!pipapo_match_field(f, start, rules_fx,
1905 match_start, match_end))
1906 break;
1907
1908 rulemap[i].to = start;
1909 rulemap[i].n = rules_fx;
1910
1911 rules_fx = f->mt[start].n;
1912 start = f->mt[start].to;
1913
1914 match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1915 match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
1916 }
1917
1918 if (i == m->field_count) {
1919 priv->dirty = true;
1920 pipapo_drop(m, rulemap);
1921 pipapo_commit(set);
1922 return;
1923 }
1924
1925 first_rule += rules_f0;
1926 }
1927}
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
1940 struct nft_set_iter *iter)
1941{
1942 struct nft_pipapo *priv = nft_set_priv(set);
1943 struct nft_pipapo_match *m;
1944 struct nft_pipapo_field *f;
1945 int i, r;
1946
1947 rcu_read_lock();
1948 m = rcu_dereference(priv->match);
1949
1950 if (unlikely(!m))
1951 goto out;
1952
1953 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
1954 ;
1955
1956 for (r = 0; r < f->rules; r++) {
1957 struct nft_pipapo_elem *e;
1958 struct nft_set_elem elem;
1959
1960 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
1961 continue;
1962
1963 if (iter->count < iter->skip)
1964 goto cont;
1965
1966 e = f->mt[r].e;
1967 if (nft_set_elem_expired(&e->ext))
1968 goto cont;
1969
1970 elem.priv = e;
1971
1972 iter->err = iter->fn(ctx, set, iter, &elem);
1973 if (iter->err < 0)
1974 goto out;
1975
1976cont:
1977 iter->count++;
1978 }
1979
1980out:
1981 rcu_read_unlock();
1982}
1983
1984
1985
1986
1987
1988
1989
1990
1991static u64 nft_pipapo_privsize(const struct nlattr * const nla[],
1992 const struct nft_set_desc *desc)
1993{
1994 return sizeof(struct nft_pipapo);
1995}
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005static bool nft_pipapo_estimate(const struct nft_set_desc *desc, u32 features,
2006 struct nft_set_estimate *est)
2007{
2008 if (!(features & NFT_SET_INTERVAL) ||
2009 desc->field_count < NFT_PIPAPO_MIN_FIELDS)
2010 return false;
2011
2012 est->size = pipapo_estimate_size(desc);
2013 if (!est->size)
2014 return false;
2015
2016 est->lookup = NFT_SET_CLASS_O_LOG_N;
2017
2018 est->space = NFT_SET_CLASS_O_N;
2019
2020 return true;
2021}
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035static int nft_pipapo_init(const struct nft_set *set,
2036 const struct nft_set_desc *desc,
2037 const struct nlattr * const nla[])
2038{
2039 struct nft_pipapo *priv = nft_set_priv(set);
2040 struct nft_pipapo_match *m;
2041 struct nft_pipapo_field *f;
2042 int err, i, field_count;
2043
2044 field_count = desc->field_count ? : 1;
2045
2046 if (field_count > NFT_PIPAPO_MAX_FIELDS)
2047 return -EINVAL;
2048
2049 m = kmalloc(sizeof(*priv->match) + sizeof(*f) * field_count,
2050 GFP_KERNEL);
2051 if (!m)
2052 return -ENOMEM;
2053
2054 m->field_count = field_count;
2055 m->bsize_max = 0;
2056
2057 m->scratch = alloc_percpu(unsigned long *);
2058 if (!m->scratch) {
2059 err = -ENOMEM;
2060 goto out_scratch;
2061 }
2062 for_each_possible_cpu(i)
2063 *per_cpu_ptr(m->scratch, i) = NULL;
2064
2065#ifdef NFT_PIPAPO_ALIGN
2066 m->scratch_aligned = alloc_percpu(unsigned long *);
2067 if (!m->scratch_aligned) {
2068 err = -ENOMEM;
2069 goto out_free;
2070 }
2071 for_each_possible_cpu(i)
2072 *per_cpu_ptr(m->scratch_aligned, i) = NULL;
2073#endif
2074
2075 rcu_head_init(&m->rcu);
2076
2077 nft_pipapo_for_each_field(f, i, m) {
2078 int len = desc->field_len[i] ? : set->klen;
2079
2080 f->bb = NFT_PIPAPO_GROUP_BITS_INIT;
2081 f->groups = len * NFT_PIPAPO_GROUPS_PER_BYTE(f);
2082
2083 priv->width += round_up(len, sizeof(u32));
2084
2085 f->bsize = 0;
2086 f->rules = 0;
2087 NFT_PIPAPO_LT_ASSIGN(f, NULL);
2088 f->mt = NULL;
2089 }
2090
2091
2092 priv->clone = pipapo_clone(m);
2093 if (IS_ERR(priv->clone)) {
2094 err = PTR_ERR(priv->clone);
2095 goto out_free;
2096 }
2097
2098 priv->dirty = false;
2099
2100 rcu_assign_pointer(priv->match, m);
2101
2102 return 0;
2103
2104out_free:
2105#ifdef NFT_PIPAPO_ALIGN
2106 free_percpu(m->scratch_aligned);
2107#endif
2108 free_percpu(m->scratch);
2109out_scratch:
2110 kfree(m);
2111
2112 return err;
2113}
2114
2115
2116
2117
2118
2119static void nft_pipapo_destroy(const struct nft_set *set)
2120{
2121 struct nft_pipapo *priv = nft_set_priv(set);
2122 struct nft_pipapo_match *m;
2123 struct nft_pipapo_field *f;
2124 int i, r, cpu;
2125
2126 m = rcu_dereference_protected(priv->match, true);
2127 if (m) {
2128 rcu_barrier();
2129
2130 for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
2131 ;
2132
2133 for (r = 0; r < f->rules; r++) {
2134 struct nft_pipapo_elem *e;
2135
2136 if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
2137 continue;
2138
2139 e = f->mt[r].e;
2140
2141 nft_set_elem_destroy(set, e, true);
2142 }
2143
2144#ifdef NFT_PIPAPO_ALIGN
2145 free_percpu(m->scratch_aligned);
2146#endif
2147 for_each_possible_cpu(cpu)
2148 kfree(*per_cpu_ptr(m->scratch, cpu));
2149 free_percpu(m->scratch);
2150 pipapo_free_fields(m);
2151 kfree(m);
2152 priv->match = NULL;
2153 }
2154
2155 if (priv->clone) {
2156#ifdef NFT_PIPAPO_ALIGN
2157 free_percpu(priv->clone->scratch_aligned);
2158#endif
2159 for_each_possible_cpu(cpu)
2160 kfree(*per_cpu_ptr(priv->clone->scratch, cpu));
2161 free_percpu(priv->clone->scratch);
2162
2163 pipapo_free_fields(priv->clone);
2164 kfree(priv->clone);
2165 priv->clone = NULL;
2166 }
2167}
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178static void nft_pipapo_gc_init(const struct nft_set *set)
2179{
2180 struct nft_pipapo *priv = nft_set_priv(set);
2181
2182 priv->last_gc = jiffies;
2183}
2184
2185const struct nft_set_type nft_set_pipapo_type = {
2186 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2187 NFT_SET_TIMEOUT,
2188 .ops = {
2189 .lookup = nft_pipapo_lookup,
2190 .insert = nft_pipapo_insert,
2191 .activate = nft_pipapo_activate,
2192 .deactivate = nft_pipapo_deactivate,
2193 .flush = nft_pipapo_flush,
2194 .remove = nft_pipapo_remove,
2195 .walk = nft_pipapo_walk,
2196 .get = nft_pipapo_get,
2197 .privsize = nft_pipapo_privsize,
2198 .estimate = nft_pipapo_estimate,
2199 .init = nft_pipapo_init,
2200 .destroy = nft_pipapo_destroy,
2201 .gc_init = nft_pipapo_gc_init,
2202 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2203 },
2204};
2205
2206#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
2207const struct nft_set_type nft_set_pipapo_avx2_type = {
2208 .features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
2209 NFT_SET_TIMEOUT,
2210 .ops = {
2211 .lookup = nft_pipapo_avx2_lookup,
2212 .insert = nft_pipapo_insert,
2213 .activate = nft_pipapo_activate,
2214 .deactivate = nft_pipapo_deactivate,
2215 .flush = nft_pipapo_flush,
2216 .remove = nft_pipapo_remove,
2217 .walk = nft_pipapo_walk,
2218 .get = nft_pipapo_get,
2219 .privsize = nft_pipapo_privsize,
2220 .estimate = nft_pipapo_avx2_estimate,
2221 .init = nft_pipapo_init,
2222 .destroy = nft_pipapo_destroy,
2223 .gc_init = nft_pipapo_gc_init,
2224 .elemsize = offsetof(struct nft_pipapo_elem, ext),
2225 },
2226};
2227#endif
2228