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