GNU Linux-libre 4.19.264-gnu1
[releases.git] / net / netfilter / nft_set_hash.c
1 /*
2  * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Development of this code funded by Astaro AG (http://www.astaro.com/)
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/list.h>
15 #include <linux/log2.h>
16 #include <linux/jhash.h>
17 #include <linux/netlink.h>
18 #include <linux/workqueue.h>
19 #include <linux/rhashtable.h>
20 #include <linux/netfilter.h>
21 #include <linux/netfilter/nf_tables.h>
22 #include <net/netfilter/nf_tables.h>
23
24 /* We target a hash table size of 4, element hint is 75% of final size */
25 #define NFT_RHASH_ELEMENT_HINT 3
26
27 struct nft_rhash {
28         struct rhashtable               ht;
29         struct delayed_work             gc_work;
30 };
31
32 struct nft_rhash_elem {
33         struct rhash_head               node;
34         struct nft_set_ext              ext;
35 };
36
37 struct nft_rhash_cmp_arg {
38         const struct nft_set            *set;
39         const u32                       *key;
40         u8                              genmask;
41 };
42
43 static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
44 {
45         const struct nft_rhash_cmp_arg *arg = data;
46
47         return jhash(arg->key, len, seed);
48 }
49
50 static inline u32 nft_rhash_obj(const void *data, u32 len, u32 seed)
51 {
52         const struct nft_rhash_elem *he = data;
53
54         return jhash(nft_set_ext_key(&he->ext), len, seed);
55 }
56
57 static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg,
58                                 const void *ptr)
59 {
60         const struct nft_rhash_cmp_arg *x = arg->key;
61         const struct nft_rhash_elem *he = ptr;
62
63         if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
64                 return 1;
65         if (nft_set_elem_expired(&he->ext))
66                 return 1;
67         if (!nft_set_elem_active(&he->ext, x->genmask))
68                 return 1;
69         return 0;
70 }
71
72 static const struct rhashtable_params nft_rhash_params = {
73         .head_offset            = offsetof(struct nft_rhash_elem, node),
74         .hashfn                 = nft_rhash_key,
75         .obj_hashfn             = nft_rhash_obj,
76         .obj_cmpfn              = nft_rhash_cmp,
77         .automatic_shrinking    = true,
78 };
79
80 static bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
81                              const u32 *key, const struct nft_set_ext **ext)
82 {
83         struct nft_rhash *priv = nft_set_priv(set);
84         const struct nft_rhash_elem *he;
85         struct nft_rhash_cmp_arg arg = {
86                 .genmask = nft_genmask_cur(net),
87                 .set     = set,
88                 .key     = key,
89         };
90
91         he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params);
92         if (he != NULL)
93                 *ext = &he->ext;
94
95         return !!he;
96 }
97
98 static void *nft_rhash_get(const struct net *net, const struct nft_set *set,
99                            const struct nft_set_elem *elem, unsigned int flags)
100 {
101         struct nft_rhash *priv = nft_set_priv(set);
102         struct nft_rhash_elem *he;
103         struct nft_rhash_cmp_arg arg = {
104                 .genmask = nft_genmask_cur(net),
105                 .set     = set,
106                 .key     = elem->key.val.data,
107         };
108
109         he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params);
110         if (he != NULL)
111                 return he;
112
113         return ERR_PTR(-ENOENT);
114 }
115
116 static bool nft_rhash_update(struct nft_set *set, const u32 *key,
117                              void *(*new)(struct nft_set *,
118                                           const struct nft_expr *,
119                                           struct nft_regs *regs),
120                              const struct nft_expr *expr,
121                              struct nft_regs *regs,
122                              const struct nft_set_ext **ext)
123 {
124         struct nft_rhash *priv = nft_set_priv(set);
125         struct nft_rhash_elem *he, *prev;
126         struct nft_rhash_cmp_arg arg = {
127                 .genmask = NFT_GENMASK_ANY,
128                 .set     = set,
129                 .key     = key,
130         };
131
132         he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params);
133         if (he != NULL)
134                 goto out;
135
136         he = new(set, expr, regs);
137         if (he == NULL)
138                 goto err1;
139
140         prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
141                                                 nft_rhash_params);
142         if (IS_ERR(prev))
143                 goto err2;
144
145         /* Another cpu may race to insert the element with the same key */
146         if (prev) {
147                 nft_set_elem_destroy(set, he, true);
148                 atomic_dec(&set->nelems);
149                 he = prev;
150         }
151
152 out:
153         *ext = &he->ext;
154         return true;
155
156 err2:
157         nft_set_elem_destroy(set, he, true);
158         atomic_dec(&set->nelems);
159 err1:
160         return false;
161 }
162
163 static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
164                             const struct nft_set_elem *elem,
165                             struct nft_set_ext **ext)
166 {
167         struct nft_rhash *priv = nft_set_priv(set);
168         struct nft_rhash_elem *he = elem->priv;
169         struct nft_rhash_cmp_arg arg = {
170                 .genmask = nft_genmask_next(net),
171                 .set     = set,
172                 .key     = elem->key.val.data,
173         };
174         struct nft_rhash_elem *prev;
175
176         prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
177                                                 nft_rhash_params);
178         if (IS_ERR(prev))
179                 return PTR_ERR(prev);
180         if (prev) {
181                 *ext = &prev->ext;
182                 return -EEXIST;
183         }
184         return 0;
185 }
186
187 static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
188                                const struct nft_set_elem *elem)
189 {
190         struct nft_rhash_elem *he = elem->priv;
191
192         nft_set_elem_change_active(net, set, &he->ext);
193         nft_set_elem_clear_busy(&he->ext);
194 }
195
196 static bool nft_rhash_flush(const struct net *net,
197                             const struct nft_set *set, void *priv)
198 {
199         struct nft_rhash_elem *he = priv;
200
201         if (!nft_set_elem_mark_busy(&he->ext) ||
202             !nft_is_active(net, &he->ext)) {
203                 nft_set_elem_change_active(net, set, &he->ext);
204                 return true;
205         }
206         return false;
207 }
208
209 static void *nft_rhash_deactivate(const struct net *net,
210                                   const struct nft_set *set,
211                                   const struct nft_set_elem *elem)
212 {
213         struct nft_rhash *priv = nft_set_priv(set);
214         struct nft_rhash_elem *he;
215         struct nft_rhash_cmp_arg arg = {
216                 .genmask = nft_genmask_next(net),
217                 .set     = set,
218                 .key     = elem->key.val.data,
219         };
220
221         rcu_read_lock();
222         he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params);
223         if (he != NULL &&
224             !nft_rhash_flush(net, set, he))
225                 he = NULL;
226
227         rcu_read_unlock();
228
229         return he;
230 }
231
232 static void nft_rhash_remove(const struct net *net,
233                              const struct nft_set *set,
234                              const struct nft_set_elem *elem)
235 {
236         struct nft_rhash *priv = nft_set_priv(set);
237         struct nft_rhash_elem *he = elem->priv;
238
239         rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
240 }
241
242 static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
243                            struct nft_set_iter *iter)
244 {
245         struct nft_rhash *priv = nft_set_priv(set);
246         struct nft_rhash_elem *he;
247         struct rhashtable_iter hti;
248         struct nft_set_elem elem;
249         int err;
250
251         err = rhashtable_walk_init(&priv->ht, &hti, GFP_ATOMIC);
252         iter->err = err;
253         if (err)
254                 return;
255
256         rhashtable_walk_start(&hti);
257
258         while ((he = rhashtable_walk_next(&hti))) {
259                 if (IS_ERR(he)) {
260                         err = PTR_ERR(he);
261                         if (err != -EAGAIN) {
262                                 iter->err = err;
263                                 goto out;
264                         }
265
266                         continue;
267                 }
268
269                 if (iter->count < iter->skip)
270                         goto cont;
271                 if (nft_set_elem_expired(&he->ext))
272                         goto cont;
273                 if (!nft_set_elem_active(&he->ext, iter->genmask))
274                         goto cont;
275
276                 elem.priv = he;
277
278                 iter->err = iter->fn(ctx, set, iter, &elem);
279                 if (iter->err < 0)
280                         goto out;
281
282 cont:
283                 iter->count++;
284         }
285
286 out:
287         rhashtable_walk_stop(&hti);
288         rhashtable_walk_exit(&hti);
289 }
290
291 static void nft_rhash_gc(struct work_struct *work)
292 {
293         struct nft_set *set;
294         struct nft_rhash_elem *he;
295         struct nft_rhash *priv;
296         struct nft_set_gc_batch *gcb = NULL;
297         struct rhashtable_iter hti;
298         int err;
299
300         priv = container_of(work, struct nft_rhash, gc_work.work);
301         set  = nft_set_container_of(priv);
302
303         err = rhashtable_walk_init(&priv->ht, &hti, GFP_KERNEL);
304         if (err)
305                 goto schedule;
306
307         rhashtable_walk_start(&hti);
308
309         while ((he = rhashtable_walk_next(&hti))) {
310                 if (IS_ERR(he)) {
311                         if (PTR_ERR(he) != -EAGAIN)
312                                 goto out;
313                         continue;
314                 }
315
316                 if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPR)) {
317                         struct nft_expr *expr = nft_set_ext_expr(&he->ext);
318
319                         if (expr->ops->gc &&
320                             expr->ops->gc(read_pnet(&set->net), expr))
321                                 goto gc;
322                 }
323                 if (!nft_set_elem_expired(&he->ext))
324                         continue;
325 gc:
326                 if (nft_set_elem_mark_busy(&he->ext))
327                         continue;
328
329                 gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
330                 if (gcb == NULL)
331                         goto out;
332                 rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
333                 atomic_dec(&set->nelems);
334                 nft_set_gc_batch_add(gcb, he);
335         }
336 out:
337         rhashtable_walk_stop(&hti);
338         rhashtable_walk_exit(&hti);
339
340         nft_set_gc_batch_complete(gcb);
341 schedule:
342         queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
343                            nft_set_gc_interval(set));
344 }
345
346 static u64 nft_rhash_privsize(const struct nlattr * const nla[],
347                               const struct nft_set_desc *desc)
348 {
349         return sizeof(struct nft_rhash);
350 }
351
352 static void nft_rhash_gc_init(const struct nft_set *set)
353 {
354         struct nft_rhash *priv = nft_set_priv(set);
355
356         queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
357                            nft_set_gc_interval(set));
358 }
359
360 static int nft_rhash_init(const struct nft_set *set,
361                           const struct nft_set_desc *desc,
362                           const struct nlattr * const tb[])
363 {
364         struct nft_rhash *priv = nft_set_priv(set);
365         struct rhashtable_params params = nft_rhash_params;
366         int err;
367
368         params.nelem_hint = desc->size ?: NFT_RHASH_ELEMENT_HINT;
369         params.key_len    = set->klen;
370
371         err = rhashtable_init(&priv->ht, &params);
372         if (err < 0)
373                 return err;
374
375         INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc);
376         if (set->flags & NFT_SET_TIMEOUT)
377                 nft_rhash_gc_init(set);
378
379         return 0;
380 }
381
382 static void nft_rhash_elem_destroy(void *ptr, void *arg)
383 {
384         nft_set_elem_destroy(arg, ptr, true);
385 }
386
387 static void nft_rhash_destroy(const struct nft_set *set)
388 {
389         struct nft_rhash *priv = nft_set_priv(set);
390
391         cancel_delayed_work_sync(&priv->gc_work);
392         rcu_barrier();
393         rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
394                                     (void *)set);
395 }
396
397 /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
398 #define NFT_MAX_BUCKETS (1U << 31)
399
400 static u32 nft_hash_buckets(u32 size)
401 {
402         u64 val = div_u64((u64)size * 4, 3);
403
404         if (val >= NFT_MAX_BUCKETS)
405                 return NFT_MAX_BUCKETS;
406
407         return roundup_pow_of_two(val);
408 }
409
410 static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
411                                struct nft_set_estimate *est)
412 {
413         est->size   = ~0;
414         est->lookup = NFT_SET_CLASS_O_1;
415         est->space  = NFT_SET_CLASS_O_N;
416
417         return true;
418 }
419
420 struct nft_hash {
421         u32                             seed;
422         u32                             buckets;
423         struct hlist_head               table[];
424 };
425
426 struct nft_hash_elem {
427         struct hlist_node               node;
428         struct nft_set_ext              ext;
429 };
430
431 static bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
432                             const u32 *key, const struct nft_set_ext **ext)
433 {
434         struct nft_hash *priv = nft_set_priv(set);
435         u8 genmask = nft_genmask_cur(net);
436         const struct nft_hash_elem *he;
437         u32 hash;
438
439         hash = jhash(key, set->klen, priv->seed);
440         hash = reciprocal_scale(hash, priv->buckets);
441         hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
442                 if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
443                     nft_set_elem_active(&he->ext, genmask)) {
444                         *ext = &he->ext;
445                         return true;
446                 }
447         }
448         return false;
449 }
450
451 static void *nft_hash_get(const struct net *net, const struct nft_set *set,
452                           const struct nft_set_elem *elem, unsigned int flags)
453 {
454         struct nft_hash *priv = nft_set_priv(set);
455         u8 genmask = nft_genmask_cur(net);
456         struct nft_hash_elem *he;
457         u32 hash;
458
459         hash = jhash(elem->key.val.data, set->klen, priv->seed);
460         hash = reciprocal_scale(hash, priv->buckets);
461         hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
462                 if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) &&
463                     nft_set_elem_active(&he->ext, genmask))
464                         return he;
465         }
466         return ERR_PTR(-ENOENT);
467 }
468
469 /* nft_hash_select_ops() makes sure key size can be either 2 or 4 bytes . */
470 static inline u32 nft_hash_key(const u32 *key, u32 klen)
471 {
472         if (klen == 4)
473                 return *key;
474
475         return *(u16 *)key;
476 }
477
478 static bool nft_hash_lookup_fast(const struct net *net,
479                                  const struct nft_set *set,
480                                  const u32 *key, const struct nft_set_ext **ext)
481 {
482         struct nft_hash *priv = nft_set_priv(set);
483         u8 genmask = nft_genmask_cur(net);
484         const struct nft_hash_elem *he;
485         u32 hash, k1, k2;
486
487         k1 = nft_hash_key(key, set->klen);
488         hash = jhash_1word(k1, priv->seed);
489         hash = reciprocal_scale(hash, priv->buckets);
490         hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
491                 k2 = nft_hash_key(nft_set_ext_key(&he->ext)->data, set->klen);
492                 if (k1 == k2 &&
493                     nft_set_elem_active(&he->ext, genmask)) {
494                         *ext = &he->ext;
495                         return true;
496                 }
497         }
498         return false;
499 }
500
501 static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv,
502                      const struct nft_set_ext *ext)
503 {
504         const struct nft_data *key = nft_set_ext_key(ext);
505         u32 hash, k1;
506
507         if (set->klen == 4) {
508                 k1 = *(u32 *)key;
509                 hash = jhash_1word(k1, priv->seed);
510         } else {
511                 hash = jhash(key, set->klen, priv->seed);
512         }
513         hash = reciprocal_scale(hash, priv->buckets);
514
515         return hash;
516 }
517
518 static int nft_hash_insert(const struct net *net, const struct nft_set *set,
519                            const struct nft_set_elem *elem,
520                            struct nft_set_ext **ext)
521 {
522         struct nft_hash_elem *this = elem->priv, *he;
523         struct nft_hash *priv = nft_set_priv(set);
524         u8 genmask = nft_genmask_next(net);
525         u32 hash;
526
527         hash = nft_jhash(set, priv, &this->ext);
528         hlist_for_each_entry(he, &priv->table[hash], node) {
529                 if (!memcmp(nft_set_ext_key(&this->ext),
530                             nft_set_ext_key(&he->ext), set->klen) &&
531                     nft_set_elem_active(&he->ext, genmask)) {
532                         *ext = &he->ext;
533                         return -EEXIST;
534                 }
535         }
536         hlist_add_head_rcu(&this->node, &priv->table[hash]);
537         return 0;
538 }
539
540 static void nft_hash_activate(const struct net *net, const struct nft_set *set,
541                               const struct nft_set_elem *elem)
542 {
543         struct nft_hash_elem *he = elem->priv;
544
545         nft_set_elem_change_active(net, set, &he->ext);
546 }
547
548 static bool nft_hash_flush(const struct net *net,
549                            const struct nft_set *set, void *priv)
550 {
551         struct nft_hash_elem *he = priv;
552
553         nft_set_elem_change_active(net, set, &he->ext);
554         return true;
555 }
556
557 static void *nft_hash_deactivate(const struct net *net,
558                                  const struct nft_set *set,
559                                  const struct nft_set_elem *elem)
560 {
561         struct nft_hash *priv = nft_set_priv(set);
562         struct nft_hash_elem *this = elem->priv, *he;
563         u8 genmask = nft_genmask_next(net);
564         u32 hash;
565
566         hash = nft_jhash(set, priv, &this->ext);
567         hlist_for_each_entry(he, &priv->table[hash], node) {
568                 if (!memcmp(nft_set_ext_key(&he->ext), &elem->key.val,
569                             set->klen) &&
570                     nft_set_elem_active(&he->ext, genmask)) {
571                         nft_set_elem_change_active(net, set, &he->ext);
572                         return he;
573                 }
574         }
575         return NULL;
576 }
577
578 static void nft_hash_remove(const struct net *net,
579                             const struct nft_set *set,
580                             const struct nft_set_elem *elem)
581 {
582         struct nft_hash_elem *he = elem->priv;
583
584         hlist_del_rcu(&he->node);
585 }
586
587 static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
588                           struct nft_set_iter *iter)
589 {
590         struct nft_hash *priv = nft_set_priv(set);
591         struct nft_hash_elem *he;
592         struct nft_set_elem elem;
593         int i;
594
595         for (i = 0; i < priv->buckets; i++) {
596                 hlist_for_each_entry_rcu(he, &priv->table[i], node) {
597                         if (iter->count < iter->skip)
598                                 goto cont;
599                         if (!nft_set_elem_active(&he->ext, iter->genmask))
600                                 goto cont;
601
602                         elem.priv = he;
603
604                         iter->err = iter->fn(ctx, set, iter, &elem);
605                         if (iter->err < 0)
606                                 return;
607 cont:
608                         iter->count++;
609                 }
610         }
611 }
612
613 static u64 nft_hash_privsize(const struct nlattr * const nla[],
614                              const struct nft_set_desc *desc)
615 {
616         return sizeof(struct nft_hash) +
617                nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
618 }
619
620 static int nft_hash_init(const struct nft_set *set,
621                          const struct nft_set_desc *desc,
622                          const struct nlattr * const tb[])
623 {
624         struct nft_hash *priv = nft_set_priv(set);
625
626         priv->buckets = nft_hash_buckets(desc->size);
627         get_random_bytes(&priv->seed, sizeof(priv->seed));
628
629         return 0;
630 }
631
632 static void nft_hash_destroy(const struct nft_set *set)
633 {
634         struct nft_hash *priv = nft_set_priv(set);
635         struct nft_hash_elem *he;
636         struct hlist_node *next;
637         int i;
638
639         for (i = 0; i < priv->buckets; i++) {
640                 hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
641                         hlist_del_rcu(&he->node);
642                         nft_set_elem_destroy(set, he, true);
643                 }
644         }
645 }
646
647 static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
648                               struct nft_set_estimate *est)
649 {
650         if (!desc->size)
651                 return false;
652
653         if (desc->klen == 4)
654                 return false;
655
656         est->size   = sizeof(struct nft_hash) +
657                       nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
658                       desc->size * sizeof(struct nft_hash_elem);
659         est->lookup = NFT_SET_CLASS_O_1;
660         est->space  = NFT_SET_CLASS_O_N;
661
662         return true;
663 }
664
665 static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features,
666                               struct nft_set_estimate *est)
667 {
668         if (!desc->size)
669                 return false;
670
671         if (desc->klen != 4)
672                 return false;
673
674         est->size   = sizeof(struct nft_hash) +
675                       nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
676                       desc->size * sizeof(struct nft_hash_elem);
677         est->lookup = NFT_SET_CLASS_O_1;
678         est->space  = NFT_SET_CLASS_O_N;
679
680         return true;
681 }
682
683 struct nft_set_type nft_set_rhash_type __read_mostly = {
684         .owner          = THIS_MODULE,
685         .features       = NFT_SET_MAP | NFT_SET_OBJECT |
686                           NFT_SET_TIMEOUT | NFT_SET_EVAL,
687         .ops            = {
688                 .privsize       = nft_rhash_privsize,
689                 .elemsize       = offsetof(struct nft_rhash_elem, ext),
690                 .estimate       = nft_rhash_estimate,
691                 .init           = nft_rhash_init,
692                 .gc_init        = nft_rhash_gc_init,
693                 .destroy        = nft_rhash_destroy,
694                 .insert         = nft_rhash_insert,
695                 .activate       = nft_rhash_activate,
696                 .deactivate     = nft_rhash_deactivate,
697                 .flush          = nft_rhash_flush,
698                 .remove         = nft_rhash_remove,
699                 .lookup         = nft_rhash_lookup,
700                 .update         = nft_rhash_update,
701                 .walk           = nft_rhash_walk,
702                 .get            = nft_rhash_get,
703         },
704 };
705
706 struct nft_set_type nft_set_hash_type __read_mostly = {
707         .owner          = THIS_MODULE,
708         .features       = NFT_SET_MAP | NFT_SET_OBJECT,
709         .ops            = {
710                 .privsize       = nft_hash_privsize,
711                 .elemsize       = offsetof(struct nft_hash_elem, ext),
712                 .estimate       = nft_hash_estimate,
713                 .init           = nft_hash_init,
714                 .destroy        = nft_hash_destroy,
715                 .insert         = nft_hash_insert,
716                 .activate       = nft_hash_activate,
717                 .deactivate     = nft_hash_deactivate,
718                 .flush          = nft_hash_flush,
719                 .remove         = nft_hash_remove,
720                 .lookup         = nft_hash_lookup,
721                 .walk           = nft_hash_walk,
722                 .get            = nft_hash_get,
723         },
724 };
725
726 struct nft_set_type nft_set_hash_fast_type __read_mostly = {
727         .owner          = THIS_MODULE,
728         .features       = NFT_SET_MAP | NFT_SET_OBJECT,
729         .ops            = {
730                 .privsize       = nft_hash_privsize,
731                 .elemsize       = offsetof(struct nft_hash_elem, ext),
732                 .estimate       = nft_hash_fast_estimate,
733                 .init           = nft_hash_init,
734                 .destroy        = nft_hash_destroy,
735                 .insert         = nft_hash_insert,
736                 .activate       = nft_hash_activate,
737                 .deactivate     = nft_hash_deactivate,
738                 .flush          = nft_hash_flush,
739                 .remove         = nft_hash_remove,
740                 .lookup         = nft_hash_lookup_fast,
741                 .walk           = nft_hash_walk,
742                 .get            = nft_hash_get,
743         },
744 };