linux/net/netfilter/nft_set_hash.c
<<
>>
Prefs
   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
  27struct nft_rhash {
  28        struct rhashtable               ht;
  29        struct delayed_work             gc_work;
  30};
  31
  32struct nft_rhash_elem {
  33        struct rhash_head               node;
  34        struct nft_set_ext              ext;
  35};
  36
  37struct nft_rhash_cmp_arg {
  38        const struct nft_set            *set;
  39        const u32                       *key;
  40        u8                              genmask;
  41};
  42
  43static 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
  50static 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
  57static 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
  72static 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
  80static 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
  98static 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
 116static 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                he = prev;
 149        }
 150
 151out:
 152        *ext = &he->ext;
 153        return true;
 154
 155err2:
 156        nft_set_elem_destroy(set, he, true);
 157err1:
 158        return false;
 159}
 160
 161static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
 162                            const struct nft_set_elem *elem,
 163                            struct nft_set_ext **ext)
 164{
 165        struct nft_rhash *priv = nft_set_priv(set);
 166        struct nft_rhash_elem *he = elem->priv;
 167        struct nft_rhash_cmp_arg arg = {
 168                .genmask = nft_genmask_next(net),
 169                .set     = set,
 170                .key     = elem->key.val.data,
 171        };
 172        struct nft_rhash_elem *prev;
 173
 174        prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
 175                                                nft_rhash_params);
 176        if (IS_ERR(prev))
 177                return PTR_ERR(prev);
 178        if (prev) {
 179                *ext = &prev->ext;
 180                return -EEXIST;
 181        }
 182        return 0;
 183}
 184
 185static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
 186                               const struct nft_set_elem *elem)
 187{
 188        struct nft_rhash_elem *he = elem->priv;
 189
 190        nft_set_elem_change_active(net, set, &he->ext);
 191        nft_set_elem_clear_busy(&he->ext);
 192}
 193
 194static bool nft_rhash_flush(const struct net *net,
 195                            const struct nft_set *set, void *priv)
 196{
 197        struct nft_rhash_elem *he = priv;
 198
 199        if (!nft_set_elem_mark_busy(&he->ext) ||
 200            !nft_is_active(net, &he->ext)) {
 201                nft_set_elem_change_active(net, set, &he->ext);
 202                return true;
 203        }
 204        return false;
 205}
 206
 207static void *nft_rhash_deactivate(const struct net *net,
 208                                  const struct nft_set *set,
 209                                  const struct nft_set_elem *elem)
 210{
 211        struct nft_rhash *priv = nft_set_priv(set);
 212        struct nft_rhash_elem *he;
 213        struct nft_rhash_cmp_arg arg = {
 214                .genmask = nft_genmask_next(net),
 215                .set     = set,
 216                .key     = elem->key.val.data,
 217        };
 218
 219        rcu_read_lock();
 220        he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params);
 221        if (he != NULL &&
 222            !nft_rhash_flush(net, set, he))
 223                he = NULL;
 224
 225        rcu_read_unlock();
 226
 227        return he;
 228}
 229
 230static void nft_rhash_remove(const struct net *net,
 231                             const struct nft_set *set,
 232                             const struct nft_set_elem *elem)
 233{
 234        struct nft_rhash *priv = nft_set_priv(set);
 235        struct nft_rhash_elem *he = elem->priv;
 236
 237        rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
 238}
 239
 240static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
 241                           struct nft_set_iter *iter)
 242{
 243        struct nft_rhash *priv = nft_set_priv(set);
 244        struct nft_rhash_elem *he;
 245        struct rhashtable_iter hti;
 246        struct nft_set_elem elem;
 247        int err;
 248
 249        err = rhashtable_walk_init(&priv->ht, &hti, GFP_ATOMIC);
 250        iter->err = err;
 251        if (err)
 252                return;
 253
 254        rhashtable_walk_start(&hti);
 255
 256        while ((he = rhashtable_walk_next(&hti))) {
 257                if (IS_ERR(he)) {
 258                        err = PTR_ERR(he);
 259                        if (err != -EAGAIN) {
 260                                iter->err = err;
 261                                goto out;
 262                        }
 263
 264                        continue;
 265                }
 266
 267                if (iter->count < iter->skip)
 268                        goto cont;
 269                if (nft_set_elem_expired(&he->ext))
 270                        goto cont;
 271                if (!nft_set_elem_active(&he->ext, iter->genmask))
 272                        goto cont;
 273
 274                elem.priv = he;
 275
 276                iter->err = iter->fn(ctx, set, iter, &elem);
 277                if (iter->err < 0)
 278                        goto out;
 279
 280cont:
 281                iter->count++;
 282        }
 283
 284out:
 285        rhashtable_walk_stop(&hti);
 286        rhashtable_walk_exit(&hti);
 287}
 288
 289static void nft_rhash_gc(struct work_struct *work)
 290{
 291        struct nft_set *set;
 292        struct nft_rhash_elem *he;
 293        struct nft_rhash *priv;
 294        struct nft_set_gc_batch *gcb = NULL;
 295        struct rhashtable_iter hti;
 296        int err;
 297
 298        priv = container_of(work, struct nft_rhash, gc_work.work);
 299        set  = nft_set_container_of(priv);
 300
 301        err = rhashtable_walk_init(&priv->ht, &hti, GFP_KERNEL);
 302        if (err)
 303                goto schedule;
 304
 305        rhashtable_walk_start(&hti);
 306
 307        while ((he = rhashtable_walk_next(&hti))) {
 308                if (IS_ERR(he)) {
 309                        if (PTR_ERR(he) != -EAGAIN)
 310                                goto out;
 311                        continue;
 312                }
 313
 314                if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPR)) {
 315                        struct nft_expr *expr = nft_set_ext_expr(&he->ext);
 316
 317                        if (expr->ops->gc &&
 318                            expr->ops->gc(read_pnet(&set->net), expr))
 319                                goto gc;
 320                }
 321                if (!nft_set_elem_expired(&he->ext))
 322                        continue;
 323gc:
 324                if (nft_set_elem_mark_busy(&he->ext))
 325                        continue;
 326
 327                gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
 328                if (gcb == NULL)
 329                        goto out;
 330                rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
 331                atomic_dec(&set->nelems);
 332                nft_set_gc_batch_add(gcb, he);
 333        }
 334out:
 335        rhashtable_walk_stop(&hti);
 336        rhashtable_walk_exit(&hti);
 337
 338        nft_set_gc_batch_complete(gcb);
 339schedule:
 340        queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
 341                           nft_set_gc_interval(set));
 342}
 343
 344static u64 nft_rhash_privsize(const struct nlattr * const nla[],
 345                              const struct nft_set_desc *desc)
 346{
 347        return sizeof(struct nft_rhash);
 348}
 349
 350static void nft_rhash_gc_init(const struct nft_set *set)
 351{
 352        struct nft_rhash *priv = nft_set_priv(set);
 353
 354        queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
 355                           nft_set_gc_interval(set));
 356}
 357
 358static int nft_rhash_init(const struct nft_set *set,
 359                          const struct nft_set_desc *desc,
 360                          const struct nlattr * const tb[])
 361{
 362        struct nft_rhash *priv = nft_set_priv(set);
 363        struct rhashtable_params params = nft_rhash_params;
 364        int err;
 365
 366        params.nelem_hint = desc->size ?: NFT_RHASH_ELEMENT_HINT;
 367        params.key_len    = set->klen;
 368
 369        err = rhashtable_init(&priv->ht, &params);
 370        if (err < 0)
 371                return err;
 372
 373        INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc);
 374        if (set->flags & NFT_SET_TIMEOUT)
 375                nft_rhash_gc_init(set);
 376
 377        return 0;
 378}
 379
 380static void nft_rhash_elem_destroy(void *ptr, void *arg)
 381{
 382        nft_set_elem_destroy(arg, ptr, true);
 383}
 384
 385static void nft_rhash_destroy(const struct nft_set *set)
 386{
 387        struct nft_rhash *priv = nft_set_priv(set);
 388
 389        cancel_delayed_work_sync(&priv->gc_work);
 390        rcu_barrier();
 391        rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
 392                                    (void *)set);
 393}
 394
 395static u32 nft_hash_buckets(u32 size)
 396{
 397        return roundup_pow_of_two(size * 4 / 3);
 398}
 399
 400static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
 401                               struct nft_set_estimate *est)
 402{
 403        est->size   = ~0;
 404        est->lookup = NFT_SET_CLASS_O_1;
 405        est->space  = NFT_SET_CLASS_O_N;
 406
 407        return true;
 408}
 409
 410struct nft_hash {
 411        u32                             seed;
 412        u32                             buckets;
 413        struct hlist_head               table[];
 414};
 415
 416struct nft_hash_elem {
 417        struct hlist_node               node;
 418        struct nft_set_ext              ext;
 419};
 420
 421static bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
 422                            const u32 *key, const struct nft_set_ext **ext)
 423{
 424        struct nft_hash *priv = nft_set_priv(set);
 425        u8 genmask = nft_genmask_cur(net);
 426        const struct nft_hash_elem *he;
 427        u32 hash;
 428
 429        hash = jhash(key, set->klen, priv->seed);
 430        hash = reciprocal_scale(hash, priv->buckets);
 431        hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
 432                if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
 433                    nft_set_elem_active(&he->ext, genmask)) {
 434                        *ext = &he->ext;
 435                        return true;
 436                }
 437        }
 438        return false;
 439}
 440
 441static void *nft_hash_get(const struct net *net, const struct nft_set *set,
 442                          const struct nft_set_elem *elem, unsigned int flags)
 443{
 444        struct nft_hash *priv = nft_set_priv(set);
 445        u8 genmask = nft_genmask_cur(net);
 446        struct nft_hash_elem *he;
 447        u32 hash;
 448
 449        hash = jhash(elem->key.val.data, set->klen, priv->seed);
 450        hash = reciprocal_scale(hash, priv->buckets);
 451        hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
 452                if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) &&
 453                    nft_set_elem_active(&he->ext, genmask))
 454                        return he;
 455        }
 456        return ERR_PTR(-ENOENT);
 457}
 458
 459/* nft_hash_select_ops() makes sure key size can be either 2 or 4 bytes . */
 460static inline u32 nft_hash_key(const u32 *key, u32 klen)
 461{
 462        if (klen == 4)
 463                return *key;
 464
 465        return *(u16 *)key;
 466}
 467
 468static bool nft_hash_lookup_fast(const struct net *net,
 469                                 const struct nft_set *set,
 470                                 const u32 *key, const struct nft_set_ext **ext)
 471{
 472        struct nft_hash *priv = nft_set_priv(set);
 473        u8 genmask = nft_genmask_cur(net);
 474        const struct nft_hash_elem *he;
 475        u32 hash, k1, k2;
 476
 477        k1 = nft_hash_key(key, set->klen);
 478        hash = jhash_1word(k1, priv->seed);
 479        hash = reciprocal_scale(hash, priv->buckets);
 480        hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
 481                k2 = nft_hash_key(nft_set_ext_key(&he->ext)->data, set->klen);
 482                if (k1 == k2 &&
 483                    nft_set_elem_active(&he->ext, genmask)) {
 484                        *ext = &he->ext;
 485                        return true;
 486                }
 487        }
 488        return false;
 489}
 490
 491static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv,
 492                     const struct nft_set_ext *ext)
 493{
 494        const struct nft_data *key = nft_set_ext_key(ext);
 495        u32 hash, k1;
 496
 497        if (set->klen == 4) {
 498                k1 = *(u32 *)key;
 499                hash = jhash_1word(k1, priv->seed);
 500        } else {
 501                hash = jhash(key, set->klen, priv->seed);
 502        }
 503        hash = reciprocal_scale(hash, priv->buckets);
 504
 505        return hash;
 506}
 507
 508static int nft_hash_insert(const struct net *net, const struct nft_set *set,
 509                           const struct nft_set_elem *elem,
 510                           struct nft_set_ext **ext)
 511{
 512        struct nft_hash_elem *this = elem->priv, *he;
 513        struct nft_hash *priv = nft_set_priv(set);
 514        u8 genmask = nft_genmask_next(net);
 515        u32 hash;
 516
 517        hash = nft_jhash(set, priv, &this->ext);
 518        hlist_for_each_entry(he, &priv->table[hash], node) {
 519                if (!memcmp(nft_set_ext_key(&this->ext),
 520                            nft_set_ext_key(&he->ext), set->klen) &&
 521                    nft_set_elem_active(&he->ext, genmask)) {
 522                        *ext = &he->ext;
 523                        return -EEXIST;
 524                }
 525        }
 526        hlist_add_head_rcu(&this->node, &priv->table[hash]);
 527        return 0;
 528}
 529
 530static void nft_hash_activate(const struct net *net, const struct nft_set *set,
 531                              const struct nft_set_elem *elem)
 532{
 533        struct nft_hash_elem *he = elem->priv;
 534
 535        nft_set_elem_change_active(net, set, &he->ext);
 536}
 537
 538static bool nft_hash_flush(const struct net *net,
 539                           const struct nft_set *set, void *priv)
 540{
 541        struct nft_hash_elem *he = priv;
 542
 543        nft_set_elem_change_active(net, set, &he->ext);
 544        return true;
 545}
 546
 547static void *nft_hash_deactivate(const struct net *net,
 548                                 const struct nft_set *set,
 549                                 const struct nft_set_elem *elem)
 550{
 551        struct nft_hash *priv = nft_set_priv(set);
 552        struct nft_hash_elem *this = elem->priv, *he;
 553        u8 genmask = nft_genmask_next(net);
 554        u32 hash;
 555
 556        hash = nft_jhash(set, priv, &this->ext);
 557        hlist_for_each_entry(he, &priv->table[hash], node) {
 558                if (!memcmp(nft_set_ext_key(&he->ext), &elem->key.val,
 559                            set->klen) &&
 560                    nft_set_elem_active(&he->ext, genmask)) {
 561                        nft_set_elem_change_active(net, set, &he->ext);
 562                        return he;
 563                }
 564        }
 565        return NULL;
 566}
 567
 568static void nft_hash_remove(const struct net *net,
 569                            const struct nft_set *set,
 570                            const struct nft_set_elem *elem)
 571{
 572        struct nft_hash_elem *he = elem->priv;
 573
 574        hlist_del_rcu(&he->node);
 575}
 576
 577static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
 578                          struct nft_set_iter *iter)
 579{
 580        struct nft_hash *priv = nft_set_priv(set);
 581        struct nft_hash_elem *he;
 582        struct nft_set_elem elem;
 583        int i;
 584
 585        for (i = 0; i < priv->buckets; i++) {
 586                hlist_for_each_entry_rcu(he, &priv->table[i], node) {
 587                        if (iter->count < iter->skip)
 588                                goto cont;
 589                        if (!nft_set_elem_active(&he->ext, iter->genmask))
 590                                goto cont;
 591
 592                        elem.priv = he;
 593
 594                        iter->err = iter->fn(ctx, set, iter, &elem);
 595                        if (iter->err < 0)
 596                                return;
 597cont:
 598                        iter->count++;
 599                }
 600        }
 601}
 602
 603static u64 nft_hash_privsize(const struct nlattr * const nla[],
 604                             const struct nft_set_desc *desc)
 605{
 606        return sizeof(struct nft_hash) +
 607               nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
 608}
 609
 610static int nft_hash_init(const struct nft_set *set,
 611                         const struct nft_set_desc *desc,
 612                         const struct nlattr * const tb[])
 613{
 614        struct nft_hash *priv = nft_set_priv(set);
 615
 616        priv->buckets = nft_hash_buckets(desc->size);
 617        get_random_bytes(&priv->seed, sizeof(priv->seed));
 618
 619        return 0;
 620}
 621
 622static void nft_hash_destroy(const struct nft_set *set)
 623{
 624        struct nft_hash *priv = nft_set_priv(set);
 625        struct nft_hash_elem *he;
 626        struct hlist_node *next;
 627        int i;
 628
 629        for (i = 0; i < priv->buckets; i++) {
 630                hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
 631                        hlist_del_rcu(&he->node);
 632                        nft_set_elem_destroy(set, he, true);
 633                }
 634        }
 635}
 636
 637static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
 638                              struct nft_set_estimate *est)
 639{
 640        if (!desc->size)
 641                return false;
 642
 643        if (desc->klen == 4)
 644                return false;
 645
 646        est->size   = sizeof(struct nft_hash) +
 647                      nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
 648                      desc->size * sizeof(struct nft_hash_elem);
 649        est->lookup = NFT_SET_CLASS_O_1;
 650        est->space  = NFT_SET_CLASS_O_N;
 651
 652        return true;
 653}
 654
 655static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features,
 656                              struct nft_set_estimate *est)
 657{
 658        if (!desc->size)
 659                return false;
 660
 661        if (desc->klen != 4)
 662                return false;
 663
 664        est->size   = sizeof(struct nft_hash) +
 665                      nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
 666                      desc->size * sizeof(struct nft_hash_elem);
 667        est->lookup = NFT_SET_CLASS_O_1;
 668        est->space  = NFT_SET_CLASS_O_N;
 669
 670        return true;
 671}
 672
 673struct nft_set_type nft_set_rhash_type __read_mostly = {
 674        .owner          = THIS_MODULE,
 675        .features       = NFT_SET_MAP | NFT_SET_OBJECT |
 676                          NFT_SET_TIMEOUT | NFT_SET_EVAL,
 677        .ops            = {
 678                .privsize       = nft_rhash_privsize,
 679                .elemsize       = offsetof(struct nft_rhash_elem, ext),
 680                .estimate       = nft_rhash_estimate,
 681                .init           = nft_rhash_init,
 682                .gc_init        = nft_rhash_gc_init,
 683                .destroy        = nft_rhash_destroy,
 684                .insert         = nft_rhash_insert,
 685                .activate       = nft_rhash_activate,
 686                .deactivate     = nft_rhash_deactivate,
 687                .flush          = nft_rhash_flush,
 688                .remove         = nft_rhash_remove,
 689                .lookup         = nft_rhash_lookup,
 690                .update         = nft_rhash_update,
 691                .walk           = nft_rhash_walk,
 692                .get            = nft_rhash_get,
 693        },
 694};
 695
 696struct nft_set_type nft_set_hash_type __read_mostly = {
 697        .owner          = THIS_MODULE,
 698        .features       = NFT_SET_MAP | NFT_SET_OBJECT,
 699        .ops            = {
 700                .privsize       = nft_hash_privsize,
 701                .elemsize       = offsetof(struct nft_hash_elem, ext),
 702                .estimate       = nft_hash_estimate,
 703                .init           = nft_hash_init,
 704                .destroy        = nft_hash_destroy,
 705                .insert         = nft_hash_insert,
 706                .activate       = nft_hash_activate,
 707                .deactivate     = nft_hash_deactivate,
 708                .flush          = nft_hash_flush,
 709                .remove         = nft_hash_remove,
 710                .lookup         = nft_hash_lookup,
 711                .walk           = nft_hash_walk,
 712                .get            = nft_hash_get,
 713        },
 714};
 715
 716struct nft_set_type nft_set_hash_fast_type __read_mostly = {
 717        .owner          = THIS_MODULE,
 718        .features       = NFT_SET_MAP | NFT_SET_OBJECT,
 719        .ops            = {
 720                .privsize       = nft_hash_privsize,
 721                .elemsize       = offsetof(struct nft_hash_elem, ext),
 722                .estimate       = nft_hash_fast_estimate,
 723                .init           = nft_hash_init,
 724                .destroy        = nft_hash_destroy,
 725                .insert         = nft_hash_insert,
 726                .activate       = nft_hash_activate,
 727                .deactivate     = nft_hash_deactivate,
 728                .flush          = nft_hash_flush,
 729                .remove         = nft_hash_remove,
 730                .lookup         = nft_hash_lookup_fast,
 731                .walk           = nft_hash_walk,
 732                .get            = nft_hash_get,
 733        },
 734};
 735