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