1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
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>
21 /* We target a hash table size of 4, element hint is 75% of final size */
22 #define NFT_RHASH_ELEMENT_HINT 3
26 struct delayed_work gc_work
;
30 struct nft_rhash_elem
{
31 struct nft_elem_priv priv
;
32 struct rhash_head node
;
34 struct nft_set_ext ext
;
37 struct nft_rhash_cmp_arg
{
38 const struct nft_set
*set
;
44 static inline u32
nft_rhash_key(const void *data
, u32 len
, u32 seed
)
46 const struct nft_rhash_cmp_arg
*arg
= data
;
48 return jhash(arg
->key
, len
, seed
);
51 static inline u32
nft_rhash_obj(const void *data
, u32 len
, u32 seed
)
53 const struct nft_rhash_elem
*he
= data
;
55 return jhash(nft_set_ext_key(&he
->ext
), len
, seed
);
58 static inline int nft_rhash_cmp(struct rhashtable_compare_arg
*arg
,
61 const struct nft_rhash_cmp_arg
*x
= arg
->key
;
62 const struct nft_rhash_elem
*he
= ptr
;
64 if (memcmp(nft_set_ext_key(&he
->ext
), x
->key
, x
->set
->klen
))
66 if (nft_set_elem_is_dead(&he
->ext
))
68 if (__nft_set_elem_expired(&he
->ext
, x
->tstamp
))
70 if (!nft_set_elem_active(&he
->ext
, x
->genmask
))
75 static const struct rhashtable_params nft_rhash_params
= {
76 .head_offset
= offsetof(struct nft_rhash_elem
, node
),
77 .hashfn
= nft_rhash_key
,
78 .obj_hashfn
= nft_rhash_obj
,
79 .obj_cmpfn
= nft_rhash_cmp
,
80 .automatic_shrinking
= true,
83 INDIRECT_CALLABLE_SCOPE
84 bool nft_rhash_lookup(const struct net
*net
, const struct nft_set
*set
,
85 const u32
*key
, const struct nft_set_ext
**ext
)
87 struct nft_rhash
*priv
= nft_set_priv(set
);
88 const struct nft_rhash_elem
*he
;
89 struct nft_rhash_cmp_arg arg
= {
90 .genmask
= nft_genmask_cur(net
),
93 .tstamp
= get_jiffies_64(),
96 he
= rhashtable_lookup(&priv
->ht
, &arg
, nft_rhash_params
);
103 static struct nft_elem_priv
*
104 nft_rhash_get(const struct net
*net
, const struct nft_set
*set
,
105 const struct nft_set_elem
*elem
, unsigned int flags
)
107 struct nft_rhash
*priv
= nft_set_priv(set
);
108 struct nft_rhash_elem
*he
;
109 struct nft_rhash_cmp_arg arg
= {
110 .genmask
= nft_genmask_cur(net
),
112 .key
= elem
->key
.val
.data
,
113 .tstamp
= get_jiffies_64(),
116 he
= rhashtable_lookup(&priv
->ht
, &arg
, nft_rhash_params
);
120 return ERR_PTR(-ENOENT
);
123 static bool nft_rhash_update(struct nft_set
*set
, const u32
*key
,
124 struct nft_elem_priv
*
125 (*new)(struct nft_set
*,
126 const struct nft_expr
*,
127 struct nft_regs
*regs
),
128 const struct nft_expr
*expr
,
129 struct nft_regs
*regs
,
130 const struct nft_set_ext
**ext
)
132 struct nft_rhash
*priv
= nft_set_priv(set
);
133 struct nft_rhash_elem
*he
, *prev
;
134 struct nft_elem_priv
*elem_priv
;
135 struct nft_rhash_cmp_arg arg
= {
136 .genmask
= NFT_GENMASK_ANY
,
139 .tstamp
= get_jiffies_64(),
142 he
= rhashtable_lookup(&priv
->ht
, &arg
, nft_rhash_params
);
146 elem_priv
= new(set
, expr
, regs
);
150 he
= nft_elem_priv_cast(elem_priv
);
151 prev
= rhashtable_lookup_get_insert_key(&priv
->ht
, &arg
, &he
->node
,
156 /* Another cpu may race to insert the element with the same key */
158 nft_set_elem_destroy(set
, &he
->priv
, true);
159 atomic_dec(&set
->nelems
);
168 nft_set_elem_destroy(set
, &he
->priv
, true);
169 atomic_dec(&set
->nelems
);
174 static int nft_rhash_insert(const struct net
*net
, const struct nft_set
*set
,
175 const struct nft_set_elem
*elem
,
176 struct nft_elem_priv
**elem_priv
)
178 struct nft_rhash_elem
*he
= nft_elem_priv_cast(elem
->priv
);
179 struct nft_rhash
*priv
= nft_set_priv(set
);
180 struct nft_rhash_cmp_arg arg
= {
181 .genmask
= nft_genmask_next(net
),
183 .key
= elem
->key
.val
.data
,
184 .tstamp
= nft_net_tstamp(net
),
186 struct nft_rhash_elem
*prev
;
188 prev
= rhashtable_lookup_get_insert_key(&priv
->ht
, &arg
, &he
->node
,
191 return PTR_ERR(prev
);
193 *elem_priv
= &prev
->priv
;
199 static void nft_rhash_activate(const struct net
*net
, const struct nft_set
*set
,
200 struct nft_elem_priv
*elem_priv
)
202 struct nft_rhash_elem
*he
= nft_elem_priv_cast(elem_priv
);
204 nft_clear(net
, &he
->ext
);
207 static void nft_rhash_flush(const struct net
*net
,
208 const struct nft_set
*set
,
209 struct nft_elem_priv
*elem_priv
)
211 struct nft_rhash_elem
*he
= nft_elem_priv_cast(elem_priv
);
213 nft_set_elem_change_active(net
, set
, &he
->ext
);
216 static struct nft_elem_priv
*
217 nft_rhash_deactivate(const struct net
*net
, const struct nft_set
*set
,
218 const struct nft_set_elem
*elem
)
220 struct nft_rhash
*priv
= nft_set_priv(set
);
221 struct nft_rhash_elem
*he
;
222 struct nft_rhash_cmp_arg arg
= {
223 .genmask
= nft_genmask_next(net
),
225 .key
= elem
->key
.val
.data
,
226 .tstamp
= nft_net_tstamp(net
),
230 he
= rhashtable_lookup(&priv
->ht
, &arg
, nft_rhash_params
);
232 nft_set_elem_change_active(net
, set
, &he
->ext
);
239 static void nft_rhash_remove(const struct net
*net
,
240 const struct nft_set
*set
,
241 struct nft_elem_priv
*elem_priv
)
243 struct nft_rhash_elem
*he
= nft_elem_priv_cast(elem_priv
);
244 struct nft_rhash
*priv
= nft_set_priv(set
);
246 rhashtable_remove_fast(&priv
->ht
, &he
->node
, nft_rhash_params
);
249 static bool nft_rhash_delete(const struct nft_set
*set
,
252 struct nft_rhash
*priv
= nft_set_priv(set
);
253 struct nft_rhash_cmp_arg arg
= {
254 .genmask
= NFT_GENMASK_ANY
,
258 struct nft_rhash_elem
*he
;
260 he
= rhashtable_lookup(&priv
->ht
, &arg
, nft_rhash_params
);
264 nft_set_elem_dead(&he
->ext
);
269 static void nft_rhash_walk(const struct nft_ctx
*ctx
, struct nft_set
*set
,
270 struct nft_set_iter
*iter
)
272 struct nft_rhash
*priv
= nft_set_priv(set
);
273 struct nft_rhash_elem
*he
;
274 struct rhashtable_iter hti
;
276 rhashtable_walk_enter(&priv
->ht
, &hti
);
277 rhashtable_walk_start(&hti
);
279 while ((he
= rhashtable_walk_next(&hti
))) {
281 if (PTR_ERR(he
) != -EAGAIN
) {
282 iter
->err
= PTR_ERR(he
);
289 if (iter
->count
< iter
->skip
)
292 iter
->err
= iter
->fn(ctx
, set
, iter
, &he
->priv
);
299 rhashtable_walk_stop(&hti
);
300 rhashtable_walk_exit(&hti
);
303 static bool nft_rhash_expr_needs_gc_run(const struct nft_set
*set
,
304 struct nft_set_ext
*ext
)
306 struct nft_set_elem_expr
*elem_expr
= nft_set_ext_expr(ext
);
307 struct nft_expr
*expr
;
310 nft_setelem_expr_foreach(expr
, elem_expr
, size
) {
312 expr
->ops
->gc(read_pnet(&set
->net
), expr
))
319 static void nft_rhash_gc(struct work_struct
*work
)
321 struct nftables_pernet
*nft_net
;
323 struct nft_rhash_elem
*he
;
324 struct nft_rhash
*priv
;
325 struct rhashtable_iter hti
;
326 struct nft_trans_gc
*gc
;
330 priv
= container_of(work
, struct nft_rhash
, gc_work
.work
);
331 set
= nft_set_container_of(priv
);
332 net
= read_pnet(&set
->net
);
333 nft_net
= nft_pernet(net
);
334 gc_seq
= READ_ONCE(nft_net
->gc_seq
);
336 if (nft_set_gc_is_pending(set
))
339 gc
= nft_trans_gc_alloc(set
, gc_seq
, GFP_KERNEL
);
343 /* Elements never collected use a zero gc worker sequence number. */
344 if (unlikely(++priv
->wq_gc_seq
== 0))
347 rhashtable_walk_enter(&priv
->ht
, &hti
);
348 rhashtable_walk_start(&hti
);
350 while ((he
= rhashtable_walk_next(&hti
))) {
352 nft_trans_gc_destroy(gc
);
357 /* Ruleset has been updated, try later. */
358 if (READ_ONCE(nft_net
->gc_seq
) != gc_seq
) {
359 nft_trans_gc_destroy(gc
);
364 /* rhashtable walk is unstable, already seen in this gc run?
365 * Then, skip this element. In case of (unlikely) sequence
366 * wraparound and stale element wq_gc_seq, next gc run will
367 * just find this expired element.
369 if (he
->wq_gc_seq
== priv
->wq_gc_seq
)
372 if (nft_set_elem_is_dead(&he
->ext
))
375 if (nft_set_ext_exists(&he
->ext
, NFT_SET_EXT_EXPRESSIONS
) &&
376 nft_rhash_expr_needs_gc_run(set
, &he
->ext
))
379 if (!nft_set_elem_expired(&he
->ext
))
382 nft_set_elem_dead(&he
->ext
);
384 gc
= nft_trans_gc_queue_async(gc
, gc_seq
, GFP_ATOMIC
);
388 /* annotate gc sequence for this attempt. */
389 he
->wq_gc_seq
= priv
->wq_gc_seq
;
390 nft_trans_gc_elem_add(gc
, he
);
393 gc
= nft_trans_gc_catchall_async(gc
, gc_seq
);
396 /* catchall list iteration requires rcu read side lock. */
397 rhashtable_walk_stop(&hti
);
398 rhashtable_walk_exit(&hti
);
401 nft_trans_gc_queue_async_done(gc
);
404 queue_delayed_work(system_power_efficient_wq
, &priv
->gc_work
,
405 nft_set_gc_interval(set
));
408 static u64
nft_rhash_privsize(const struct nlattr
* const nla
[],
409 const struct nft_set_desc
*desc
)
411 return sizeof(struct nft_rhash
);
414 static void nft_rhash_gc_init(const struct nft_set
*set
)
416 struct nft_rhash
*priv
= nft_set_priv(set
);
418 queue_delayed_work(system_power_efficient_wq
, &priv
->gc_work
,
419 nft_set_gc_interval(set
));
422 static int nft_rhash_init(const struct nft_set
*set
,
423 const struct nft_set_desc
*desc
,
424 const struct nlattr
* const tb
[])
426 struct nft_rhash
*priv
= nft_set_priv(set
);
427 struct rhashtable_params params
= nft_rhash_params
;
430 BUILD_BUG_ON(offsetof(struct nft_rhash_elem
, priv
) != 0);
432 params
.nelem_hint
= desc
->size
?: NFT_RHASH_ELEMENT_HINT
;
433 params
.key_len
= set
->klen
;
435 err
= rhashtable_init(&priv
->ht
, ¶ms
);
439 INIT_DEFERRABLE_WORK(&priv
->gc_work
, nft_rhash_gc
);
440 if (set
->flags
& (NFT_SET_TIMEOUT
| NFT_SET_EVAL
))
441 nft_rhash_gc_init(set
);
446 struct nft_rhash_ctx
{
447 const struct nft_ctx ctx
;
448 const struct nft_set
*set
;
451 static void nft_rhash_elem_destroy(void *ptr
, void *arg
)
453 struct nft_rhash_ctx
*rhash_ctx
= arg
;
454 struct nft_rhash_elem
*he
= ptr
;
456 nf_tables_set_elem_destroy(&rhash_ctx
->ctx
, rhash_ctx
->set
, &he
->priv
);
459 static void nft_rhash_destroy(const struct nft_ctx
*ctx
,
460 const struct nft_set
*set
)
462 struct nft_rhash
*priv
= nft_set_priv(set
);
463 struct nft_rhash_ctx rhash_ctx
= {
468 cancel_delayed_work_sync(&priv
->gc_work
);
469 rhashtable_free_and_destroy(&priv
->ht
, nft_rhash_elem_destroy
,
473 /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
474 #define NFT_MAX_BUCKETS (1U << 31)
476 static u32
nft_hash_buckets(u32 size
)
478 u64 val
= div_u64((u64
)size
* 4, 3);
480 if (val
>= NFT_MAX_BUCKETS
)
481 return NFT_MAX_BUCKETS
;
483 return roundup_pow_of_two(val
);
486 static bool nft_rhash_estimate(const struct nft_set_desc
*desc
, u32 features
,
487 struct nft_set_estimate
*est
)
490 est
->lookup
= NFT_SET_CLASS_O_1
;
491 est
->space
= NFT_SET_CLASS_O_N
;
499 struct hlist_head table
[];
502 struct nft_hash_elem
{
503 struct nft_elem_priv priv
;
504 struct hlist_node node
;
505 struct nft_set_ext ext
;
508 INDIRECT_CALLABLE_SCOPE
509 bool nft_hash_lookup(const struct net
*net
, const struct nft_set
*set
,
510 const u32
*key
, const struct nft_set_ext
**ext
)
512 struct nft_hash
*priv
= nft_set_priv(set
);
513 u8 genmask
= nft_genmask_cur(net
);
514 const struct nft_hash_elem
*he
;
517 hash
= jhash(key
, set
->klen
, priv
->seed
);
518 hash
= reciprocal_scale(hash
, priv
->buckets
);
519 hlist_for_each_entry_rcu(he
, &priv
->table
[hash
], node
) {
520 if (!memcmp(nft_set_ext_key(&he
->ext
), key
, set
->klen
) &&
521 nft_set_elem_active(&he
->ext
, genmask
)) {
529 static struct nft_elem_priv
*
530 nft_hash_get(const struct net
*net
, const struct nft_set
*set
,
531 const struct nft_set_elem
*elem
, unsigned int flags
)
533 struct nft_hash
*priv
= nft_set_priv(set
);
534 u8 genmask
= nft_genmask_cur(net
);
535 struct nft_hash_elem
*he
;
538 hash
= jhash(elem
->key
.val
.data
, set
->klen
, priv
->seed
);
539 hash
= reciprocal_scale(hash
, priv
->buckets
);
540 hlist_for_each_entry_rcu(he
, &priv
->table
[hash
], node
) {
541 if (!memcmp(nft_set_ext_key(&he
->ext
), elem
->key
.val
.data
, set
->klen
) &&
542 nft_set_elem_active(&he
->ext
, genmask
))
545 return ERR_PTR(-ENOENT
);
548 INDIRECT_CALLABLE_SCOPE
549 bool nft_hash_lookup_fast(const struct net
*net
,
550 const struct nft_set
*set
,
551 const u32
*key
, const struct nft_set_ext
**ext
)
553 struct nft_hash
*priv
= nft_set_priv(set
);
554 u8 genmask
= nft_genmask_cur(net
);
555 const struct nft_hash_elem
*he
;
559 hash
= jhash_1word(k1
, priv
->seed
);
560 hash
= reciprocal_scale(hash
, priv
->buckets
);
561 hlist_for_each_entry_rcu(he
, &priv
->table
[hash
], node
) {
562 k2
= *(u32
*)nft_set_ext_key(&he
->ext
)->data
;
564 nft_set_elem_active(&he
->ext
, genmask
)) {
572 static u32
nft_jhash(const struct nft_set
*set
, const struct nft_hash
*priv
,
573 const struct nft_set_ext
*ext
)
575 const struct nft_data
*key
= nft_set_ext_key(ext
);
578 if (set
->klen
== 4) {
580 hash
= jhash_1word(k1
, priv
->seed
);
582 hash
= jhash(key
, set
->klen
, priv
->seed
);
584 hash
= reciprocal_scale(hash
, priv
->buckets
);
589 static int nft_hash_insert(const struct net
*net
, const struct nft_set
*set
,
590 const struct nft_set_elem
*elem
,
591 struct nft_elem_priv
**elem_priv
)
593 struct nft_hash_elem
*this = nft_elem_priv_cast(elem
->priv
), *he
;
594 struct nft_hash
*priv
= nft_set_priv(set
);
595 u8 genmask
= nft_genmask_next(net
);
598 hash
= nft_jhash(set
, priv
, &this->ext
);
599 hlist_for_each_entry(he
, &priv
->table
[hash
], node
) {
600 if (!memcmp(nft_set_ext_key(&this->ext
),
601 nft_set_ext_key(&he
->ext
), set
->klen
) &&
602 nft_set_elem_active(&he
->ext
, genmask
)) {
603 *elem_priv
= &he
->priv
;
607 hlist_add_head_rcu(&this->node
, &priv
->table
[hash
]);
611 static void nft_hash_activate(const struct net
*net
, const struct nft_set
*set
,
612 struct nft_elem_priv
*elem_priv
)
614 struct nft_hash_elem
*he
= nft_elem_priv_cast(elem_priv
);
616 nft_clear(net
, &he
->ext
);
619 static void nft_hash_flush(const struct net
*net
,
620 const struct nft_set
*set
,
621 struct nft_elem_priv
*elem_priv
)
623 struct nft_hash_elem
*he
= nft_elem_priv_cast(elem_priv
);
625 nft_set_elem_change_active(net
, set
, &he
->ext
);
628 static struct nft_elem_priv
*
629 nft_hash_deactivate(const struct net
*net
, const struct nft_set
*set
,
630 const struct nft_set_elem
*elem
)
632 struct nft_hash_elem
*this = nft_elem_priv_cast(elem
->priv
), *he
;
633 struct nft_hash
*priv
= nft_set_priv(set
);
634 u8 genmask
= nft_genmask_next(net
);
637 hash
= nft_jhash(set
, priv
, &this->ext
);
638 hlist_for_each_entry(he
, &priv
->table
[hash
], node
) {
639 if (!memcmp(nft_set_ext_key(&he
->ext
), &elem
->key
.val
,
641 nft_set_elem_active(&he
->ext
, genmask
)) {
642 nft_set_elem_change_active(net
, set
, &he
->ext
);
649 static void nft_hash_remove(const struct net
*net
,
650 const struct nft_set
*set
,
651 struct nft_elem_priv
*elem_priv
)
653 struct nft_hash_elem
*he
= nft_elem_priv_cast(elem_priv
);
655 hlist_del_rcu(&he
->node
);
658 static void nft_hash_walk(const struct nft_ctx
*ctx
, struct nft_set
*set
,
659 struct nft_set_iter
*iter
)
661 struct nft_hash
*priv
= nft_set_priv(set
);
662 struct nft_hash_elem
*he
;
665 for (i
= 0; i
< priv
->buckets
; i
++) {
666 hlist_for_each_entry_rcu(he
, &priv
->table
[i
], node
,
667 lockdep_is_held(&nft_pernet(ctx
->net
)->commit_mutex
)) {
668 if (iter
->count
< iter
->skip
)
671 iter
->err
= iter
->fn(ctx
, set
, iter
, &he
->priv
);
680 static u64
nft_hash_privsize(const struct nlattr
* const nla
[],
681 const struct nft_set_desc
*desc
)
683 return sizeof(struct nft_hash
) +
684 (u64
)nft_hash_buckets(desc
->size
) * sizeof(struct hlist_head
);
687 static int nft_hash_init(const struct nft_set
*set
,
688 const struct nft_set_desc
*desc
,
689 const struct nlattr
* const tb
[])
691 struct nft_hash
*priv
= nft_set_priv(set
);
693 priv
->buckets
= nft_hash_buckets(desc
->size
);
694 get_random_bytes(&priv
->seed
, sizeof(priv
->seed
));
699 static void nft_hash_destroy(const struct nft_ctx
*ctx
,
700 const struct nft_set
*set
)
702 struct nft_hash
*priv
= nft_set_priv(set
);
703 struct nft_hash_elem
*he
;
704 struct hlist_node
*next
;
707 for (i
= 0; i
< priv
->buckets
; i
++) {
708 hlist_for_each_entry_safe(he
, next
, &priv
->table
[i
], node
) {
709 hlist_del_rcu(&he
->node
);
710 nf_tables_set_elem_destroy(ctx
, set
, &he
->priv
);
715 static bool nft_hash_estimate(const struct nft_set_desc
*desc
, u32 features
,
716 struct nft_set_estimate
*est
)
724 est
->size
= sizeof(struct nft_hash
) +
725 (u64
)nft_hash_buckets(desc
->size
) * sizeof(struct hlist_head
) +
726 (u64
)desc
->size
* sizeof(struct nft_hash_elem
);
727 est
->lookup
= NFT_SET_CLASS_O_1
;
728 est
->space
= NFT_SET_CLASS_O_N
;
733 static bool nft_hash_fast_estimate(const struct nft_set_desc
*desc
, u32 features
,
734 struct nft_set_estimate
*est
)
742 est
->size
= sizeof(struct nft_hash
) +
743 (u64
)nft_hash_buckets(desc
->size
) * sizeof(struct hlist_head
) +
744 (u64
)desc
->size
* sizeof(struct nft_hash_elem
);
745 est
->lookup
= NFT_SET_CLASS_O_1
;
746 est
->space
= NFT_SET_CLASS_O_N
;
751 const struct nft_set_type nft_set_rhash_type
= {
752 .features
= NFT_SET_MAP
| NFT_SET_OBJECT
|
753 NFT_SET_TIMEOUT
| NFT_SET_EVAL
,
755 .privsize
= nft_rhash_privsize
,
756 .elemsize
= offsetof(struct nft_rhash_elem
, ext
),
757 .estimate
= nft_rhash_estimate
,
758 .init
= nft_rhash_init
,
759 .gc_init
= nft_rhash_gc_init
,
760 .destroy
= nft_rhash_destroy
,
761 .insert
= nft_rhash_insert
,
762 .activate
= nft_rhash_activate
,
763 .deactivate
= nft_rhash_deactivate
,
764 .flush
= nft_rhash_flush
,
765 .remove
= nft_rhash_remove
,
766 .lookup
= nft_rhash_lookup
,
767 .update
= nft_rhash_update
,
768 .delete = nft_rhash_delete
,
769 .walk
= nft_rhash_walk
,
770 .get
= nft_rhash_get
,
774 const struct nft_set_type nft_set_hash_type
= {
775 .features
= NFT_SET_MAP
| NFT_SET_OBJECT
,
777 .privsize
= nft_hash_privsize
,
778 .elemsize
= offsetof(struct nft_hash_elem
, ext
),
779 .estimate
= nft_hash_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
,
788 .walk
= nft_hash_walk
,
793 const struct nft_set_type nft_set_hash_fast_type
= {
794 .features
= NFT_SET_MAP
| NFT_SET_OBJECT
,
796 .privsize
= nft_hash_privsize
,
797 .elemsize
= offsetof(struct nft_hash_elem
, ext
),
798 .estimate
= nft_hash_fast_estimate
,
799 .init
= nft_hash_init
,
800 .destroy
= nft_hash_destroy
,
801 .insert
= nft_hash_insert
,
802 .activate
= nft_hash_activate
,
803 .deactivate
= nft_hash_deactivate
,
804 .flush
= nft_hash_flush
,
805 .remove
= nft_hash_remove
,
806 .lookup
= nft_hash_lookup_fast
,
807 .walk
= nft_hash_walk
,