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