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_elem_priv **elem_priv) 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 *elem_priv = &prev->priv; 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, ¶ms); 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_elem_priv **elem_priv) 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 *elem_priv = &he->priv; 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 }; 792