static struct bnxt_tc_l2_node * bnxt_tc_get_l2_node(struct bnxt *bp, struct rhashtable *l2_table, struct rhashtable_params ht_params, struct bnxt_tc_l2_key *l2_key) { struct bnxt_tc_l2_node *l2_node; int rc; l2_node = rhashtable_lookup_fast(l2_table, l2_key, ht_params); if (!l2_node) { l2_node = kzalloc(sizeof(*l2_node), GFP_KERNEL); if (!l2_node) { rc = -ENOMEM; return NULL; } l2_node->key = *l2_key; rc = rhashtable_insert_fast(l2_table, &l2_node->node, ht_params); if (rc) { kfree_rcu(l2_node, rcu); netdev_err(bp->dev, "Error: %s: rhashtable_insert_fast: %d", __func__, rc); return NULL; } INIT_LIST_HEAD(&l2_node->common_l2_flows); } return l2_node; }
/* Only called for SRC manip */ static int find_appropriate_src(struct net *net, const struct nf_conntrack_zone *zone, const struct nf_nat_l3proto *l3proto, const struct nf_nat_l4proto *l4proto, const struct nf_conntrack_tuple *tuple, struct nf_conntrack_tuple *result, const struct nf_nat_range *range) { const struct nf_conn *ct; struct nf_nat_conn_key key = { .net = net, .tuple = tuple, .zone = zone }; ct = rhashtable_lookup_fast(&nf_nat_bysource_table, &key, nf_nat_bysource_params); if (!ct) return 0; nf_ct_invert_tuplepr(result, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); result->dst = tuple->dst; return in_range(l3proto, l4proto, result, range); }
/* Must be called with either RTNL or rcu_read_lock */ struct nfp_fl_payload * nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie, struct net_device *netdev) { struct nfp_fl_flow_table_cmp_arg flower_cmp_arg; struct nfp_flower_priv *priv = app->priv; flower_cmp_arg.netdev = netdev; flower_cmp_arg.cookie = tc_flower_cookie; return rhashtable_lookup_fast(&priv->flow_table, &flower_cmp_arg, nfp_flower_table_params); }
/* returns -ve errno or +ve port */ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port) { int ret = -EADDRINUSE; u16 rover, last; u64 key; if (*port != 0) { rover = be16_to_cpu(*port); if (rover == RDS_FLAG_PROBE_PORT) return -EINVAL; last = rover; } else { rover = max_t(u16, prandom_u32(), 2); last = rover - 1; } do { if (rover == 0) rover++; if (rover == RDS_FLAG_PROBE_PORT) continue; key = ((u64)addr << 32) | cpu_to_be16(rover); if (rhashtable_lookup_fast(&bind_hash_table, &key, ht_parms)) continue; rs->rs_bound_key = key; rs->rs_bound_addr = addr; net_get_random_once(&rs->rs_hash_initval, sizeof(rs->rs_hash_initval)); rs->rs_bound_port = cpu_to_be16(rover); rs->rs_bound_node.next = NULL; rds_sock_addref(rs); if (!rhashtable_insert_fast(&bind_hash_table, &rs->rs_bound_node, ht_parms)) { *port = rs->rs_bound_port; ret = 0; rdsdebug("rs %p binding to %pI4:%d\n", rs, &addr, (int)ntohs(*port)); break; } else { rds_sock_put(rs); ret = -ENOMEM; break; } } while (rover++ != last); return ret; }
/* * Return the rds_sock bound at the given local address. * * The rx path can race with rds_release. We notice if rds_release() has * marked this socket and don't return a rs ref to the rx path. */ struct rds_sock *rds_find_bound(__be32 addr, __be16 port) { u64 key = ((u64)addr << 32) | port; struct rds_sock *rs; rs = rhashtable_lookup_fast(&bind_hash_table, &key, ht_parms); if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD)) rds_sock_addref(rs); else rs = NULL; rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr, ntohs(port)); return rs; }
/** * ipc_findkey - find a key in an ipc identifier set * @ids: ipc identifier set * @key: key to find * * Returns the locked pointer to the ipc structure if found or NULL * otherwise. If key is found ipc points to the owning ipc structure * * Called with writer ipc_ids.rwsem held. */ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) { struct kern_ipc_perm *ipcp = NULL; if (likely(ids->tables_initialized)) ipcp = rhashtable_lookup_fast(&ids->key_ht, &key, ipc_kht_params); if (ipcp) { rcu_read_lock(); ipc_lock_object(ipcp); return ipcp; } return NULL; }
static bool nft_hash_lookup(const struct net *net, const struct nft_set *set, const u32 *key, const struct nft_set_ext **ext) { struct nft_hash *priv = nft_set_priv(set); const struct nft_hash_elem *he; struct nft_hash_cmp_arg arg = { .genmask = nft_genmask_cur(net), .set = set, .key = key, }; he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params); if (he != NULL) *ext = &he->ext; return !!he; }
static int __init test_rht_lookup(struct rhashtable *ht, struct test_obj *array, unsigned int entries) { unsigned int i; for (i = 0; i < entries; i++) { struct test_obj *obj; bool expected = !(i % 2); struct test_obj_val key = { .id = i, }; if (array[i / 2].value.id == TEST_INSERT_FAIL) expected = false; obj = rhashtable_lookup_fast(ht, &key, test_rht_params); if (expected && !obj) { pr_warn("Test failed: Could not find key %u\n", key.id); return -ENOENT; } else if (!expected && obj) { pr_warn("Test failed: Unexpected entry found for key %u\n", key.id); return -EEXIST; } else if (expected && obj) { if (obj->value.id != i) { pr_warn("Test failed: Lookup value mismatch %u!=%u\n", obj->value.id, i); return -EINVAL; } } cond_resched_rcu(); } return 0; }
void *(*new)(struct nft_set *, const struct nft_expr *, struct nft_regs *regs), const struct nft_expr *expr, struct nft_regs *regs, const struct nft_set_ext **ext) { struct nft_hash *priv = nft_set_priv(set); struct nft_hash_elem *he; struct nft_hash_cmp_arg arg = { .genmask = NFT_GENMASK_ANY, .set = set, .key = key, }; he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params); if (he != NULL) goto out; he = new(set, expr, regs); if (he == NULL) goto err1; if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, nft_hash_params)) goto err2; out: *ext = &he->ext; return true; err2: nft_set_elem_destroy(set, he);
static s64 __init test_rhashtable(struct rhashtable *ht, struct test_obj *array, unsigned int entries) { struct test_obj *obj; int err; unsigned int i, insert_retries = 0; s64 start, end; /* * Insertion Test: * Insert entries into table with all keys even numbers */ pr_info(" Adding %d keys\n", entries); start = ktime_get_ns(); for (i = 0; i < entries; i++) { struct test_obj *obj = &array[i]; obj->value.id = i * 2; err = insert_retry(ht, obj, test_rht_params); if (err > 0) insert_retries += err; else if (err) return err; } if (insert_retries) pr_info(" %u insertions retried due to memory pressure\n", insert_retries); test_bucket_stats(ht, entries); rcu_read_lock(); test_rht_lookup(ht, array, entries); rcu_read_unlock(); test_bucket_stats(ht, entries); pr_info(" Deleting %d keys\n", entries); for (i = 0; i < entries; i++) { struct test_obj_val key = { .id = i * 2, }; if (array[i].value.id != TEST_INSERT_FAIL) { obj = rhashtable_lookup_fast(ht, &key, test_rht_params); BUG_ON(!obj); rhashtable_remove_fast(ht, &obj->node, test_rht_params); } cond_resched(); } end = ktime_get_ns(); pr_info(" Duration of test: %lld ns\n", end - start); return end - start; } static struct rhashtable ht; static struct rhltable rhlt; static int __init test_rhltable(unsigned int entries) { struct test_obj_rhl *rhl_test_objects; unsigned long *obj_in_table; unsigned int i, j, k; int ret, err; if (entries == 0) entries = 1; rhl_test_objects = vzalloc(sizeof(*rhl_test_objects) * entries); if (!rhl_test_objects) return -ENOMEM; ret = -ENOMEM; obj_in_table = vzalloc(BITS_TO_LONGS(entries) * sizeof(unsigned long)); if (!obj_in_table) goto out_free; /* nulls_base not supported in rhlist interface */ test_rht_params.nulls_base = 0; err = rhltable_init(&rhlt, &test_rht_params); if (WARN_ON(err)) goto out_free; k = prandom_u32(); ret = 0; for (i = 0; i < entries; i++) { rhl_test_objects[i].value.id = k; err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params); if (WARN(err, "error %d on element %d\n", err, i)) break; if (err == 0) set_bit(i, obj_in_table); } if (err) ret = err; pr_info("test %d add/delete pairs into rhlist\n", entries); for (i = 0; i < entries; i++) { struct rhlist_head *h, *pos; struct test_obj_rhl *obj; struct test_obj_val key = { .id = k, }; bool found; rcu_read_lock(); h = rhltable_lookup(&rhlt, &key, test_rht_params); if (WARN(!h, "key not found during iteration %d of %d", i, entries)) { rcu_read_unlock(); break; } if (i) { j = i - 1; rhl_for_each_entry_rcu(obj, pos, h, list_node) { if (WARN(pos == &rhl_test_objects[j].list_node, "old element found, should be gone")) break; } } cond_resched_rcu(); found = false; rhl_for_each_entry_rcu(obj, pos, h, list_node) { if (pos == &rhl_test_objects[i].list_node) { found = true; break; } } rcu_read_unlock(); if (WARN(!found, "element %d not found", i)) break; err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params); WARN(err, "rhltable_remove: err %d for iteration %d\n", err, i); if (err == 0) clear_bit(i, obj_in_table); } if (ret == 0 && err) ret = err; for (i = 0; i < entries; i++) { WARN(test_bit(i, obj_in_table), "elem %d allegedly still present", i); err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params); if (WARN(err, "error %d on element %d\n", err, i)) break; if (err == 0) set_bit(i, obj_in_table); } pr_info("test %d random rhlist add/delete operations\n", entries); for (j = 0; j < entries; j++) { u32 i = prandom_u32_max(entries); u32 prand = prandom_u32(); cond_resched(); if (prand == 0) prand = prandom_u32(); if (prand & 1) { prand >>= 1; continue; } err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params); if (test_bit(i, obj_in_table)) { clear_bit(i, obj_in_table); if (WARN(err, "cannot remove element at slot %d", i)) continue; } else { if (WARN(err != -ENOENT, "removed non-existant element %d, error %d not %d", i, err, -ENOENT)) continue; } if (prand & 1) { prand >>= 1; continue; } err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params); if (err == 0) { if (WARN(test_and_set_bit(i, obj_in_table), "succeeded to insert same object %d", i)) continue; } else { if (WARN(!test_bit(i, obj_in_table), "failed to insert object %d", i)) continue; } if (prand & 1) { prand >>= 1; continue; }
static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid) { return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params); }