/* 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 }; struct rhlist_head *hl; hl = rhltable_lookup(&nf_nat_bysource_table, &key, nf_nat_bysource_params); if (!hl) return 0; ct = container_of(hl, typeof(*ct), nat_bysource); nf_ct_invert_tuplepr(result, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); result->dst = tuple->dst; return in_range(l3proto, l4proto, result, range); }
/* 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 }; struct rhlist_head *hl, *h; hl = rhltable_lookup(&nf_nat_bysource_table, &key, nf_nat_bysource_params); rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) { nf_ct_invert_tuplepr(result, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); result->dst = tuple->dst; if (in_range(l3proto, l4proto, result, range)) return 1; }
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; }