mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 14:35:26 +00:00
add semantics to name trees to support counters
name trees can now also hold trees of counters. each time a name dns_nametree_add() is called with a given name, the counter for that name is incremented; the name is not deleted until dns_nametree_delete() is called the same number of times. this is meant to be used for synth-from-dnssec, which is incremented for each key defined at a name, and decremented when a key is removed, the name must continue to exist until the number of keys has reached zero.
This commit is contained in:
@@ -40,7 +40,11 @@
|
||||
/* Define to 1 for detailed reference tracing */
|
||||
#undef DNS_NAMETREE_TRACE
|
||||
|
||||
typedef enum { DNS_NAMETREE_BOOL, DNS_NAMETREE_BITS } dns_nametree_type_t;
|
||||
typedef enum {
|
||||
DNS_NAMETREE_BOOL,
|
||||
DNS_NAMETREE_BITS,
|
||||
DNS_NAMETREE_COUNT
|
||||
} dns_nametree_type_t;
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
@@ -54,7 +58,8 @@ dns_nametree_create(isc_mem_t *mctx, dns_nametree_type_t type, const char *name,
|
||||
* for debugging purposes.
|
||||
*
|
||||
* 'type' indicates whether the tree will be used for storing boolean
|
||||
* values (DNS_NAMETREE_BOOL) or bitfields (DNS_NAMETREE_BITS).
|
||||
* values (DNS_NAMETREE_BOOL), bitfields (DNS_NAMETREE_BITS), or counters
|
||||
* (DNS_NAMETREE_COUNT).
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
@@ -72,6 +77,12 @@ dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
* represents a single boolean value, true or false. If the name already
|
||||
* exists within the tree, then return ISC_R_EXISTS.
|
||||
*
|
||||
* If the nametree type was set to DNS_NAMETREE_COUNT, then 'value'
|
||||
* can only be true. Each time the same name is added to the tree,
|
||||
* ISC_R_SUCCESS is returned and a counter is incremented.
|
||||
* dns_nametree_delete() must be deleted the same number of times
|
||||
* as dns_nametree_add() before the name is removed from the tree.
|
||||
*
|
||||
* If the nametree type was set to DNS_NAMETREE_BITS, then 'value' is
|
||||
* a bit number within a bit field, which is sized to accomodate at least
|
||||
* 'value' bits. If the name already exists, then that bit will be set
|
||||
@@ -96,6 +107,10 @@ dns_nametree_delete(dns_nametree_t *nametree, const dns_name_t *name);
|
||||
/*%<
|
||||
* Delete 'name' from 'nametree'.
|
||||
*
|
||||
* If the nametree type was set to DNS_NAMETREE_COUNT, then this must
|
||||
* be called for each name the same number of times as dns_nametree_add()
|
||||
* was called before the name is removed.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'nametree' points to a valid nametree.
|
||||
|
@@ -67,7 +67,8 @@ static void
|
||||
destroy_ntnode(dns_ntnode_t *node) {
|
||||
isc_refcount_destroy(&node->references);
|
||||
if (node->bits != NULL) {
|
||||
isc_mem_cput(node->mctx, node->bits, 8, sizeof(uint32_t));
|
||||
isc_mem_cput(node->mctx, node->bits, node->bits[0],
|
||||
sizeof(char));
|
||||
}
|
||||
isc_mem_putanddetach(&node->mctx, node, sizeof(dns_ntnode_t));
|
||||
}
|
||||
@@ -103,8 +104,20 @@ dns_nametree_create(isc_mem_t *mctx, dns_nametree_type_t type, const char *name,
|
||||
|
||||
static void
|
||||
destroy_nametree(dns_nametree_t *nametree) {
|
||||
/* dns_qpread_t qpr; */
|
||||
/* dns_qpiter_t iter; */
|
||||
/* void *pval = NULL; */
|
||||
|
||||
nametree->magic = 0;
|
||||
|
||||
/* dns_qpmulti_query(nametree->table, &qpr); */
|
||||
/* dns_qpiter_init(&qpr, &iter); */
|
||||
/* while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) { */
|
||||
/* dns_ntnode_t *n = pval; */
|
||||
/* dns_ntnode_detach(&n); */
|
||||
/* } */
|
||||
/* dns_qpread_destroy(nametree->table, &qpr); */
|
||||
|
||||
dns_qpmulti_destroy(&nametree->table);
|
||||
isc_refcount_destroy(&nametree->references);
|
||||
|
||||
@@ -132,10 +145,10 @@ newnode(isc_mem_t *mctx, const dns_name_t *name) {
|
||||
|
||||
static bool
|
||||
matchbit(unsigned char *bits, uint32_t val) {
|
||||
unsigned int len = val / 8;
|
||||
unsigned int len = val / 8 + 2;
|
||||
unsigned int mask = 1 << (val % 8);
|
||||
|
||||
if ((bits[len] & mask) != 0) {
|
||||
if (len <= bits[0] && (bits[len - 1] & mask) != 0) {
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
@@ -146,7 +159,7 @@ dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
uint32_t value) {
|
||||
isc_result_t result;
|
||||
dns_qp_t *qp = NULL;
|
||||
unsigned int len, mask;
|
||||
uint32_t size, pos, mask, count = 0;
|
||||
dns_ntnode_t *old = NULL, *new = NULL;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
@@ -160,32 +173,44 @@ dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
new->set = value;
|
||||
break;
|
||||
|
||||
case DNS_NAMETREE_COUNT:
|
||||
new = newnode(nametree->mctx, name);
|
||||
new->set = true;
|
||||
result = dns_qp_deletename(qp, name, (void **)&old, &count);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
count += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_NAMETREE_BITS:
|
||||
result = dns_qp_getname(qp, name, (void **)&old, NULL);
|
||||
if (result == ISC_R_SUCCESS && matchbit(old->bits, value)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = value / 8;
|
||||
size = pos = value / 8 + 2;
|
||||
mask = 1 << (value % 8);
|
||||
|
||||
if (old != NULL && old->bits[0] > pos) {
|
||||
size = old->bits[0];
|
||||
}
|
||||
|
||||
new = newnode(nametree->mctx, name);
|
||||
new->bits = isc_mem_cget(nametree->mctx, 8, sizeof(value));
|
||||
new->bits = isc_mem_cget(nametree->mctx, size, sizeof(char));
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
INSIST(old != NULL);
|
||||
memmove(new->bits, old->bits, old->bits[0]);
|
||||
result = dns_qp_deletename(qp, name, NULL, NULL);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
new->bits[len] |= mask;
|
||||
new->bits[pos - 1] |= mask;
|
||||
new->bits[0] = size;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
result = dns_qp_insert(qp, new, 0);
|
||||
|
||||
result = dns_qp_insert(qp, new, count);
|
||||
/*
|
||||
* We detach the node here, so any dns_qp_deletename() will
|
||||
* destroy the node directly.
|
||||
@@ -202,16 +227,30 @@ isc_result_t
|
||||
dns_nametree_delete(dns_nametree_t *nametree, const dns_name_t *name) {
|
||||
isc_result_t result;
|
||||
dns_qp_t *qp = NULL;
|
||||
void *pval = NULL;
|
||||
dns_ntnode_t *old = NULL;
|
||||
uint32_t count;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
REQUIRE(name != NULL);
|
||||
|
||||
dns_qpmulti_write(nametree->table, &qp);
|
||||
result = dns_qp_deletename(qp, name, &pval, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_ntnode_t *n = pval;
|
||||
dns_ntnode_detach(&n);
|
||||
result = dns_qp_deletename(qp, name, (void **)&old, &count);
|
||||
switch (nametree->type) {
|
||||
case DNS_NAMETREE_BOOL:
|
||||
case DNS_NAMETREE_BITS:
|
||||
break;
|
||||
|
||||
case DNS_NAMETREE_COUNT:
|
||||
if (result == ISC_R_SUCCESS && count-- != 0) {
|
||||
dns_ntnode_t *new = newnode(nametree->mctx, name);
|
||||
new->set = true;
|
||||
result = dns_qp_insert(qp, new, count);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_ntnode_detach(&new);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
||||
dns_qpmulti_commit(nametree->table, &qp);
|
||||
@@ -223,18 +262,17 @@ isc_result_t
|
||||
dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_ntnode_t **ntnodep) {
|
||||
isc_result_t result;
|
||||
dns_ntnode_t *node = NULL;
|
||||
dns_qpread_t qpr;
|
||||
void *pval = NULL;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(ntnodep != NULL && *ntnodep == NULL);
|
||||
|
||||
dns_qpmulti_query(nametree->table, &qpr);
|
||||
result = dns_qp_getname(&qpr, name, &pval, NULL);
|
||||
result = dns_qp_getname(&qpr, name, (void **)&node, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_ntnode_t *knode = pval;
|
||||
dns_ntnode_attach(knode, ntnodep);
|
||||
dns_ntnode_attach(node, ntnodep);
|
||||
}
|
||||
dns_qpread_destroy(nametree->table, &qpr);
|
||||
|
||||
@@ -258,10 +296,16 @@ dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_qpmulti_query(nametree->table, &qpr);
|
||||
result = dns_qp_findname_ancestor(&qpr, name, 0, (void **)&node, NULL);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
if (nametree->type == DNS_NAMETREE_BOOL) {
|
||||
switch (nametree->type) {
|
||||
case DNS_NAMETREE_BOOL:
|
||||
ret = node->set;
|
||||
} else {
|
||||
break;
|
||||
case DNS_NAMETREE_COUNT:
|
||||
ret = true;
|
||||
break;
|
||||
case DNS_NAMETREE_BITS:
|
||||
ret = matchbit(node->bits, bit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,7 @@
|
||||
|
||||
dns_nametree_t *booltree = NULL;
|
||||
dns_nametree_t *bitstree = NULL;
|
||||
dns_nametree_t *counttree = NULL;
|
||||
|
||||
/*
|
||||
* Test utilities. In general, these assume input parameters are valid
|
||||
@@ -55,6 +56,7 @@ create_tables(void) {
|
||||
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_BOOL, "bool test", &booltree);
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_BITS, "bits test", &bitstree);
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_COUNT, "count test", &counttree);
|
||||
|
||||
/* Add a positive boolean node */
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
@@ -73,7 +75,7 @@ create_tables(void) {
|
||||
assert_int_equal(dns_nametree_add(booltree, name, false),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
/* Add a bitfield nodes under a parent */
|
||||
/* Add a bitfield node under a parent */
|
||||
dns_test_namefromstring("sub.example.com.", &fn);
|
||||
assert_int_equal(dns_nametree_add(bitstree, name, 2), ISC_R_SUCCESS);
|
||||
}
|
||||
@@ -86,6 +88,9 @@ destroy_tables(void) {
|
||||
if (bitstree != NULL) {
|
||||
dns_nametree_detach(&bitstree);
|
||||
}
|
||||
if (counttree != NULL) {
|
||||
dns_nametree_detach(&counttree);
|
||||
}
|
||||
rcu_barrier();
|
||||
}
|
||||
|
||||
@@ -161,6 +166,42 @@ ISC_RUN_TEST_IMPL(add_bits) {
|
||||
destroy_tables();
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(add_count) {
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
|
||||
create_tables();
|
||||
|
||||
/* add a counter node five times */
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
|
||||
/* delete it five times, checking coverage each time */
|
||||
assert_true(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_true(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_true(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_true(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_true(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_false(dns_nametree_covered(counttree, name, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_NOTFOUND);
|
||||
|
||||
destroy_tables();
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(covered_bool) {
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
@@ -301,6 +342,7 @@ ISC_RUN_TEST_IMPL(find) {
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY(add_bool)
|
||||
ISC_TEST_ENTRY(add_bits)
|
||||
ISC_TEST_ENTRY(add_count)
|
||||
ISC_TEST_ENTRY(covered_bool)
|
||||
ISC_TEST_ENTRY(covered_bits)
|
||||
ISC_TEST_ENTRY(delete)
|
||||
|
Reference in New Issue
Block a user