xref: /freebsd/contrib/unbound/edns-subnet/addrtree.c (revision 865f46b255599c4a645e84a4cbb5ea7abdc0e207)
165b390aaSDag-Erling Smørgrav /*
265b390aaSDag-Erling Smørgrav  * edns-subnet/addrtree.c -- radix tree for edns subnet cache.
365b390aaSDag-Erling Smørgrav  *
465b390aaSDag-Erling Smørgrav  * Copyright (c) 2013, NLnet Labs. All rights reserved.
565b390aaSDag-Erling Smørgrav  *
665b390aaSDag-Erling Smørgrav  * This software is open source.
765b390aaSDag-Erling Smørgrav  *
865b390aaSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
965b390aaSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
1065b390aaSDag-Erling Smørgrav  * are met:
1165b390aaSDag-Erling Smørgrav  *
1265b390aaSDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
1365b390aaSDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
1465b390aaSDag-Erling Smørgrav  *
1565b390aaSDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
1665b390aaSDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
1765b390aaSDag-Erling Smørgrav  * and/or other materials provided with the distribution.
1865b390aaSDag-Erling Smørgrav  *
1965b390aaSDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
2065b390aaSDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
2165b390aaSDag-Erling Smørgrav  * specific prior written permission.
2265b390aaSDag-Erling Smørgrav  *
2365b390aaSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2465b390aaSDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2565b390aaSDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2665b390aaSDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2765b390aaSDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2865b390aaSDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2965b390aaSDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3065b390aaSDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3165b390aaSDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3265b390aaSDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3365b390aaSDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3465b390aaSDag-Erling Smørgrav  */
3565b390aaSDag-Erling Smørgrav /** \file
3665b390aaSDag-Erling Smørgrav  * addrtree -- radix tree for edns subnet cache.
3765b390aaSDag-Erling Smørgrav  */
3865b390aaSDag-Erling Smørgrav 
3965b390aaSDag-Erling Smørgrav #include "config.h"
4065b390aaSDag-Erling Smørgrav #include "util/log.h"
4165b390aaSDag-Erling Smørgrav #include "util/data/msgreply.h"
4265b390aaSDag-Erling Smørgrav #include "util/module.h"
4365b390aaSDag-Erling Smørgrav #include "addrtree.h"
4465b390aaSDag-Erling Smørgrav 
4565b390aaSDag-Erling Smørgrav /**
4665b390aaSDag-Erling Smørgrav  * Create a new edge
4765b390aaSDag-Erling Smørgrav  * @param node: Child node this edge will connect to.
4865b390aaSDag-Erling Smørgrav  * @param addr: full key to this edge.
4965b390aaSDag-Erling Smørgrav  * @param addrlen: length of relevant part of key for this node
5065b390aaSDag-Erling Smørgrav  * @param parent_node: Parent node for node
5165b390aaSDag-Erling Smørgrav  * @param parent_index: Index of child node at parent node
5265b390aaSDag-Erling Smørgrav  * @return new addredge or NULL on failure
5365b390aaSDag-Erling Smørgrav  */
5465b390aaSDag-Erling Smørgrav static struct addredge *
edge_create(struct addrnode * node,const addrkey_t * addr,addrlen_t addrlen,struct addrnode * parent_node,int parent_index)5565b390aaSDag-Erling Smørgrav edge_create(struct addrnode *node, const addrkey_t *addr,
5665b390aaSDag-Erling Smørgrav 	addrlen_t addrlen, struct addrnode *parent_node, int parent_index)
5765b390aaSDag-Erling Smørgrav {
5865b390aaSDag-Erling Smørgrav 	size_t n;
5965b390aaSDag-Erling Smørgrav 	struct addredge *edge = (struct addredge *)malloc( sizeof (*edge) );
6065b390aaSDag-Erling Smørgrav 	if (!edge)
6165b390aaSDag-Erling Smørgrav 		return NULL;
6265b390aaSDag-Erling Smørgrav 	edge->node = node;
6365b390aaSDag-Erling Smørgrav 	edge->len = addrlen;
6465b390aaSDag-Erling Smørgrav 	edge->parent_index = parent_index;
6565b390aaSDag-Erling Smørgrav 	edge->parent_node = parent_node;
6665b390aaSDag-Erling Smørgrav 	/* ceil() */
6765b390aaSDag-Erling Smørgrav 	n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0));
6865b390aaSDag-Erling Smørgrav 	edge->str = (addrkey_t *)calloc(n, sizeof (addrkey_t));
6965b390aaSDag-Erling Smørgrav 	if (!edge->str) {
7065b390aaSDag-Erling Smørgrav 		free(edge);
7165b390aaSDag-Erling Smørgrav 		return NULL;
7265b390aaSDag-Erling Smørgrav 	}
7365b390aaSDag-Erling Smørgrav 	memcpy(edge->str, addr, n * sizeof (addrkey_t));
7465b390aaSDag-Erling Smørgrav 	/* Only manipulate other objects after successful alloc */
7565b390aaSDag-Erling Smørgrav 	node->parent_edge = edge;
7665b390aaSDag-Erling Smørgrav 	log_assert(parent_node->edge[parent_index] == NULL);
7765b390aaSDag-Erling Smørgrav 	parent_node->edge[parent_index] = edge;
7865b390aaSDag-Erling Smørgrav 	return edge;
7965b390aaSDag-Erling Smørgrav }
8065b390aaSDag-Erling Smørgrav 
8165b390aaSDag-Erling Smørgrav /**
8265b390aaSDag-Erling Smørgrav  * Create a new node
8365b390aaSDag-Erling Smørgrav  * @param tree: Tree the node lives in.
8465b390aaSDag-Erling Smørgrav  * @param elem: Element to store at this node
8565b390aaSDag-Erling Smørgrav  * @param scope: Scopemask from server reply
8665b390aaSDag-Erling Smørgrav  * @param ttl: Element is valid up to this time. Absolute, seconds
8765b390aaSDag-Erling Smørgrav  * @return new addrnode or NULL on failure
8865b390aaSDag-Erling Smørgrav  */
8965b390aaSDag-Erling Smørgrav static struct addrnode *
node_create(struct addrtree * tree,void * elem,addrlen_t scope,time_t ttl)9065b390aaSDag-Erling Smørgrav node_create(struct addrtree *tree, void *elem, addrlen_t scope,
9165b390aaSDag-Erling Smørgrav 	time_t ttl)
9265b390aaSDag-Erling Smørgrav {
9365b390aaSDag-Erling Smørgrav 	struct addrnode* node = (struct addrnode *)malloc( sizeof (*node) );
9465b390aaSDag-Erling Smørgrav 	if (!node)
9565b390aaSDag-Erling Smørgrav 		return NULL;
9665b390aaSDag-Erling Smørgrav 	node->elem = elem;
9765b390aaSDag-Erling Smørgrav 	tree->node_count++;
9865b390aaSDag-Erling Smørgrav 	node->scope = scope;
9965b390aaSDag-Erling Smørgrav 	node->ttl = ttl;
100*865f46b2SCy Schubert 	node->only_match_scope_zero = 0;
10165b390aaSDag-Erling Smørgrav 	node->edge[0] = NULL;
10265b390aaSDag-Erling Smørgrav 	node->edge[1] = NULL;
10365b390aaSDag-Erling Smørgrav 	node->parent_edge = NULL;
10465b390aaSDag-Erling Smørgrav 	node->next = NULL;
10565b390aaSDag-Erling Smørgrav 	node->prev = NULL;
10665b390aaSDag-Erling Smørgrav 	return node;
10765b390aaSDag-Erling Smørgrav }
10865b390aaSDag-Erling Smørgrav 
10965b390aaSDag-Erling Smørgrav /** Size in bytes of node and parent edge
11065b390aaSDag-Erling Smørgrav  * @param tree: tree the node lives in
11165b390aaSDag-Erling Smørgrav  * @param n: node which size must be calculated
11265b390aaSDag-Erling Smørgrav  * @return size in bytes.
11365b390aaSDag-Erling Smørgrav  **/
11465b390aaSDag-Erling Smørgrav static inline size_t
node_size(const struct addrtree * tree,const struct addrnode * n)11565b390aaSDag-Erling Smørgrav node_size(const struct addrtree *tree, const struct addrnode *n)
11665b390aaSDag-Erling Smørgrav {
11765b390aaSDag-Erling Smørgrav 	return sizeof *n + sizeof *n->parent_edge + n->parent_edge->len +
11865b390aaSDag-Erling Smørgrav 		(n->elem?tree->sizefunc(n->elem):0);
11965b390aaSDag-Erling Smørgrav }
12065b390aaSDag-Erling Smørgrav 
12165b390aaSDag-Erling Smørgrav struct addrtree *
addrtree_create(addrlen_t max_depth,void (* delfunc)(void *,void *),size_t (* sizefunc)(void *),void * env,uint32_t max_node_count)12265b390aaSDag-Erling Smørgrav addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *),
123e86b9096SDag-Erling Smørgrav 	size_t (*sizefunc)(void *), void *env, uint32_t max_node_count)
12465b390aaSDag-Erling Smørgrav {
12565b390aaSDag-Erling Smørgrav 	struct addrtree *tree;
12665b390aaSDag-Erling Smørgrav 	log_assert(delfunc != NULL);
12765b390aaSDag-Erling Smørgrav 	log_assert(sizefunc != NULL);
12865b390aaSDag-Erling Smørgrav 	tree = (struct addrtree *)calloc(1, sizeof(*tree));
12965b390aaSDag-Erling Smørgrav 	if (!tree)
13065b390aaSDag-Erling Smørgrav 		return NULL;
13165b390aaSDag-Erling Smørgrav 	tree->root = node_create(tree, NULL, 0, 0);
13265b390aaSDag-Erling Smørgrav 	if (!tree->root) {
13365b390aaSDag-Erling Smørgrav 		free(tree);
13465b390aaSDag-Erling Smørgrav 		return NULL;
13565b390aaSDag-Erling Smørgrav 	}
13665b390aaSDag-Erling Smørgrav 	tree->size_bytes = sizeof *tree + sizeof *tree->root;
13765b390aaSDag-Erling Smørgrav 	tree->first = NULL;
13865b390aaSDag-Erling Smørgrav 	tree->last = NULL;
13965b390aaSDag-Erling Smørgrav 	tree->max_depth = max_depth;
14065b390aaSDag-Erling Smørgrav 	tree->delfunc = delfunc;
14165b390aaSDag-Erling Smørgrav 	tree->sizefunc = sizefunc;
14265b390aaSDag-Erling Smørgrav 	tree->env = env;
14365b390aaSDag-Erling Smørgrav 	tree->node_count = 0;
14465b390aaSDag-Erling Smørgrav 	tree->max_node_count = max_node_count;
14565b390aaSDag-Erling Smørgrav 	return tree;
14665b390aaSDag-Erling Smørgrav }
14765b390aaSDag-Erling Smørgrav 
14865b390aaSDag-Erling Smørgrav /**
14965b390aaSDag-Erling Smørgrav  * Scrub a node clean of elem
15065b390aaSDag-Erling Smørgrav  * @param tree: tree the node lives in.
15165b390aaSDag-Erling Smørgrav  * @param node: node to be cleaned.
15265b390aaSDag-Erling Smørgrav  */
15365b390aaSDag-Erling Smørgrav static void
clean_node(struct addrtree * tree,struct addrnode * node)15465b390aaSDag-Erling Smørgrav clean_node(struct addrtree *tree, struct addrnode *node)
15565b390aaSDag-Erling Smørgrav {
15665b390aaSDag-Erling Smørgrav 	if (!node->elem) return;
15765b390aaSDag-Erling Smørgrav 	tree->size_bytes -= tree->sizefunc(node->elem);
15865b390aaSDag-Erling Smørgrav 	tree->delfunc(tree->env, node->elem);
159*865f46b2SCy Schubert 	node->only_match_scope_zero = 0;
16065b390aaSDag-Erling Smørgrav 	node->elem = NULL;
16165b390aaSDag-Erling Smørgrav }
16265b390aaSDag-Erling Smørgrav 
16365b390aaSDag-Erling Smørgrav /** Remove specified node from LRU list */
16465b390aaSDag-Erling Smørgrav static void
lru_pop(struct addrtree * tree,struct addrnode * node)16565b390aaSDag-Erling Smørgrav lru_pop(struct addrtree *tree, struct addrnode *node)
16665b390aaSDag-Erling Smørgrav {
16765b390aaSDag-Erling Smørgrav 	if (node == tree->first) {
16865b390aaSDag-Erling Smørgrav 		if (!node->next) { /* it is the last as well */
16965b390aaSDag-Erling Smørgrav 			tree->first = NULL;
17065b390aaSDag-Erling Smørgrav 			tree->last = NULL;
17165b390aaSDag-Erling Smørgrav 		} else {
17265b390aaSDag-Erling Smørgrav 			tree->first = node->next;
17365b390aaSDag-Erling Smørgrav 			tree->first->prev = NULL;
17465b390aaSDag-Erling Smørgrav 		}
17565b390aaSDag-Erling Smørgrav 	} else if (node == tree->last) { /* but not the first */
17665b390aaSDag-Erling Smørgrav 		tree->last = node->prev;
17765b390aaSDag-Erling Smørgrav 		tree->last->next = NULL;
17865b390aaSDag-Erling Smørgrav 	} else {
17965b390aaSDag-Erling Smørgrav 		node->prev->next = node->next;
18065b390aaSDag-Erling Smørgrav 		node->next->prev = node->prev;
18165b390aaSDag-Erling Smørgrav 	}
18265b390aaSDag-Erling Smørgrav }
18365b390aaSDag-Erling Smørgrav 
18465b390aaSDag-Erling Smørgrav /** Add node to LRU list as most recently used. */
18565b390aaSDag-Erling Smørgrav static void
lru_push(struct addrtree * tree,struct addrnode * node)18665b390aaSDag-Erling Smørgrav lru_push(struct addrtree *tree, struct addrnode *node)
18765b390aaSDag-Erling Smørgrav {
18865b390aaSDag-Erling Smørgrav 	if (!tree->first) {
18965b390aaSDag-Erling Smørgrav 		tree->first = node;
19065b390aaSDag-Erling Smørgrav 		node->prev = NULL;
19165b390aaSDag-Erling Smørgrav 	} else {
19265b390aaSDag-Erling Smørgrav 		tree->last->next = node;
19365b390aaSDag-Erling Smørgrav 		node->prev = tree->last;
19465b390aaSDag-Erling Smørgrav 	}
19565b390aaSDag-Erling Smørgrav 	tree->last = node;
19665b390aaSDag-Erling Smørgrav 	node->next = NULL;
19765b390aaSDag-Erling Smørgrav }
19865b390aaSDag-Erling Smørgrav 
19965b390aaSDag-Erling Smørgrav /** Move node to the end of LRU list */
20065b390aaSDag-Erling Smørgrav static void
lru_update(struct addrtree * tree,struct addrnode * node)20165b390aaSDag-Erling Smørgrav lru_update(struct addrtree *tree, struct addrnode *node)
20265b390aaSDag-Erling Smørgrav {
20365b390aaSDag-Erling Smørgrav 	if (tree->root == node) return;
20465b390aaSDag-Erling Smørgrav 	lru_pop(tree, node);
20565b390aaSDag-Erling Smørgrav 	lru_push(tree, node);
20665b390aaSDag-Erling Smørgrav }
20765b390aaSDag-Erling Smørgrav 
20865b390aaSDag-Erling Smørgrav /**
20965b390aaSDag-Erling Smørgrav  * Purge a node from the tree. Node and parentedge are cleaned and
21065b390aaSDag-Erling Smørgrav  * free'd.
21165b390aaSDag-Erling Smørgrav  * @param tree: Tree the node lives in.
21265b390aaSDag-Erling Smørgrav  * @param node: Node to be freed
21365b390aaSDag-Erling Smørgrav  */
21465b390aaSDag-Erling Smørgrav static void
purge_node(struct addrtree * tree,struct addrnode * node)21565b390aaSDag-Erling Smørgrav purge_node(struct addrtree *tree, struct addrnode *node)
21665b390aaSDag-Erling Smørgrav {
21765b390aaSDag-Erling Smørgrav 	struct addredge *parent_edge, *child_edge = NULL;
21865b390aaSDag-Erling Smørgrav 	int index;
21965b390aaSDag-Erling Smørgrav 	int keep = node->edge[0] && node->edge[1];
22065b390aaSDag-Erling Smørgrav 
22165b390aaSDag-Erling Smørgrav 	clean_node(tree, node);
22265b390aaSDag-Erling Smørgrav 	parent_edge = node->parent_edge;
22365b390aaSDag-Erling Smørgrav 	if (keep || !parent_edge) return;
22465b390aaSDag-Erling Smørgrav 	tree->node_count--;
22565b390aaSDag-Erling Smørgrav 	index = parent_edge->parent_index;
22665b390aaSDag-Erling Smørgrav 	child_edge = node->edge[!node->edge[0]];
22765b390aaSDag-Erling Smørgrav 	if (child_edge) {
22865b390aaSDag-Erling Smørgrav 		child_edge->parent_node  = parent_edge->parent_node;
22965b390aaSDag-Erling Smørgrav 		child_edge->parent_index = index;
23065b390aaSDag-Erling Smørgrav 	}
23165b390aaSDag-Erling Smørgrav 	parent_edge->parent_node->edge[index] = child_edge;
23265b390aaSDag-Erling Smørgrav 	tree->size_bytes -= node_size(tree, node);
23365b390aaSDag-Erling Smørgrav 	free(parent_edge->str);
23465b390aaSDag-Erling Smørgrav 	free(parent_edge);
23565b390aaSDag-Erling Smørgrav 	lru_pop(tree, node);
23665b390aaSDag-Erling Smørgrav 	free(node);
23765b390aaSDag-Erling Smørgrav }
23865b390aaSDag-Erling Smørgrav 
23965b390aaSDag-Erling Smørgrav /**
24065b390aaSDag-Erling Smørgrav  * If a limit is set remove old nodes while above that limit.
24165b390aaSDag-Erling Smørgrav  * @param tree: Tree to be cleaned up.
24265b390aaSDag-Erling Smørgrav  */
24365b390aaSDag-Erling Smørgrav static void
lru_cleanup(struct addrtree * tree)24465b390aaSDag-Erling Smørgrav lru_cleanup(struct addrtree *tree)
24565b390aaSDag-Erling Smørgrav {
24665b390aaSDag-Erling Smørgrav 	struct addrnode *n, *p;
24765b390aaSDag-Erling Smørgrav 	int children;
24865b390aaSDag-Erling Smørgrav 	if (tree->max_node_count == 0) return;
24965b390aaSDag-Erling Smørgrav 	while (tree->node_count > tree->max_node_count) {
25065b390aaSDag-Erling Smørgrav 		n = tree->first;
25165b390aaSDag-Erling Smørgrav 		if (!n) break;
25265b390aaSDag-Erling Smørgrav 		children = (n->edge[0] != NULL) + (n->edge[1] != NULL);
25365b390aaSDag-Erling Smørgrav 		/** Don't remove this node, it is either the root or we can't
25465b390aaSDag-Erling Smørgrav 		 * do without it because it has 2 children */
25565b390aaSDag-Erling Smørgrav 		if (children == 2 || !n->parent_edge) {
25665b390aaSDag-Erling Smørgrav 			lru_update(tree, n);
25765b390aaSDag-Erling Smørgrav 			continue;
25865b390aaSDag-Erling Smørgrav 		}
25965b390aaSDag-Erling Smørgrav 		p = n->parent_edge->parent_node;
26065b390aaSDag-Erling Smørgrav 		purge_node(tree, n);
26165b390aaSDag-Erling Smørgrav 		/** Since we removed n, n's parent p is eligible for deletion
26265b390aaSDag-Erling Smørgrav 		 * if it is not the root node, caries no data and has only 1
26365b390aaSDag-Erling Smørgrav 		 * child */
26465b390aaSDag-Erling Smørgrav 		children = (p->edge[0] != NULL) + (p->edge[1] != NULL);
26565b390aaSDag-Erling Smørgrav 		if (!p->elem && children == 1 && p->parent_edge) {
26665b390aaSDag-Erling Smørgrav 			purge_node(tree, p);
26765b390aaSDag-Erling Smørgrav 		}
26865b390aaSDag-Erling Smørgrav 	}
26965b390aaSDag-Erling Smørgrav }
27065b390aaSDag-Erling Smørgrav 
27165b390aaSDag-Erling Smørgrav inline size_t
addrtree_size(const struct addrtree * tree)27265b390aaSDag-Erling Smørgrav addrtree_size(const struct addrtree *tree)
27365b390aaSDag-Erling Smørgrav {
27465b390aaSDag-Erling Smørgrav 	return tree?tree->size_bytes:0;
27565b390aaSDag-Erling Smørgrav }
27665b390aaSDag-Erling Smørgrav 
addrtree_delete(struct addrtree * tree)27765b390aaSDag-Erling Smørgrav void addrtree_delete(struct addrtree *tree)
27865b390aaSDag-Erling Smørgrav {
27965b390aaSDag-Erling Smørgrav 	struct addrnode *n;
28065b390aaSDag-Erling Smørgrav 	if (!tree) return;
28165b390aaSDag-Erling Smørgrav 	clean_node(tree, tree->root);
28265b390aaSDag-Erling Smørgrav 	free(tree->root);
28365b390aaSDag-Erling Smørgrav 	tree->size_bytes -= sizeof(struct addrnode);
28465b390aaSDag-Erling Smørgrav 	while ((n = tree->first)) {
28565b390aaSDag-Erling Smørgrav 		tree->first = n->next;
28665b390aaSDag-Erling Smørgrav 		clean_node(tree, n);
28765b390aaSDag-Erling Smørgrav 		tree->size_bytes -= node_size(tree, n);
28865b390aaSDag-Erling Smørgrav 		free(n->parent_edge->str);
28965b390aaSDag-Erling Smørgrav 		free(n->parent_edge);
29065b390aaSDag-Erling Smørgrav 		free(n);
29165b390aaSDag-Erling Smørgrav 	}
29265b390aaSDag-Erling Smørgrav 	log_assert(sizeof *tree == addrtree_size(tree));
29365b390aaSDag-Erling Smørgrav 	free(tree);
29465b390aaSDag-Erling Smørgrav }
29565b390aaSDag-Erling Smørgrav 
29665b390aaSDag-Erling Smørgrav /**
29765b390aaSDag-Erling Smørgrav  * Get N'th bit from address
29865b390aaSDag-Erling Smørgrav  * @param addr: address to inspect
29965b390aaSDag-Erling Smørgrav  * @param addrlen: length of addr in bits
30065b390aaSDag-Erling Smørgrav  * @param n: index of bit to test. Must be in range [0, addrlen)
30165b390aaSDag-Erling Smørgrav  * @return 0 or 1
30265b390aaSDag-Erling Smørgrav  */
30365b390aaSDag-Erling Smørgrav static int
getbit(const addrkey_t * addr,addrlen_t addrlen,addrlen_t n)30465b390aaSDag-Erling Smørgrav getbit(const addrkey_t *addr, addrlen_t addrlen, addrlen_t n)
30565b390aaSDag-Erling Smørgrav {
30665b390aaSDag-Erling Smørgrav 	log_assert(addrlen > n);
307c7f4d7adSDag-Erling Smørgrav 	(void)addrlen;
30865b390aaSDag-Erling Smørgrav 	return (int)(addr[n/KEYWIDTH]>>((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
30965b390aaSDag-Erling Smørgrav }
31065b390aaSDag-Erling Smørgrav 
31165b390aaSDag-Erling Smørgrav /**
31265b390aaSDag-Erling Smørgrav  * Test for equality on N'th bit.
31365b390aaSDag-Erling Smørgrav  * @return 0 for equal, 1 otherwise
31465b390aaSDag-Erling Smørgrav  */
31565b390aaSDag-Erling Smørgrav static inline int
cmpbit(const addrkey_t * key1,const addrkey_t * key2,addrlen_t n)31665b390aaSDag-Erling Smørgrav cmpbit(const addrkey_t *key1, const addrkey_t *key2, addrlen_t n)
31765b390aaSDag-Erling Smørgrav {
31865b390aaSDag-Erling Smørgrav 	addrkey_t c = key1[n/KEYWIDTH] ^ key2[n/KEYWIDTH];
31965b390aaSDag-Erling Smørgrav 	return (int)(c >> ((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
32065b390aaSDag-Erling Smørgrav }
32165b390aaSDag-Erling Smørgrav 
32265b390aaSDag-Erling Smørgrav /**
32365b390aaSDag-Erling Smørgrav  * Common number of bits in prefix.
32465b390aaSDag-Erling Smørgrav  * @param s1: first prefix.
32565b390aaSDag-Erling Smørgrav  * @param l1: length of s1 in bits.
32665b390aaSDag-Erling Smørgrav  * @param s2: second prefix.
32765b390aaSDag-Erling Smørgrav  * @param l2: length of s2 in bits.
32865b390aaSDag-Erling Smørgrav  * @param skip: nr of bits already checked.
32965b390aaSDag-Erling Smørgrav  * @return common number of bits.
33065b390aaSDag-Erling Smørgrav  */
33165b390aaSDag-Erling Smørgrav static addrlen_t
bits_common(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)33265b390aaSDag-Erling Smørgrav bits_common(const addrkey_t *s1, addrlen_t l1,
33365b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2, addrlen_t skip)
33465b390aaSDag-Erling Smørgrav {
33565b390aaSDag-Erling Smørgrav 	addrlen_t len, i;
33665b390aaSDag-Erling Smørgrav 	len = (l1 > l2) ? l2 : l1;
33765b390aaSDag-Erling Smørgrav 	log_assert(skip < len);
33865b390aaSDag-Erling Smørgrav 	for (i = skip; i < len; i++) {
33965b390aaSDag-Erling Smørgrav 		if (cmpbit(s1, s2, i)) return i;
34065b390aaSDag-Erling Smørgrav 	}
34165b390aaSDag-Erling Smørgrav 	return len;
34265b390aaSDag-Erling Smørgrav }
34365b390aaSDag-Erling Smørgrav 
34465b390aaSDag-Erling Smørgrav /**
34565b390aaSDag-Erling Smørgrav  * Tests if s1 is a substring of s2
34665b390aaSDag-Erling Smørgrav  * @param s1: first prefix.
34765b390aaSDag-Erling Smørgrav  * @param l1: length of s1 in bits.
34865b390aaSDag-Erling Smørgrav  * @param s2: second prefix.
34965b390aaSDag-Erling Smørgrav  * @param l2: length of s2 in bits.
35065b390aaSDag-Erling Smørgrav  * @param skip: nr of bits already checked.
35165b390aaSDag-Erling Smørgrav  * @return 1 for substring, 0 otherwise
35265b390aaSDag-Erling Smørgrav  */
35365b390aaSDag-Erling Smørgrav static int
issub(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)35465b390aaSDag-Erling Smørgrav issub(const addrkey_t *s1, addrlen_t l1,
35565b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2,  addrlen_t skip)
35665b390aaSDag-Erling Smørgrav {
35765b390aaSDag-Erling Smørgrav 	return bits_common(s1, l1, s2, l2, skip) == l1;
35865b390aaSDag-Erling Smørgrav }
35965b390aaSDag-Erling Smørgrav 
36065b390aaSDag-Erling Smørgrav void
addrtree_insert(struct addrtree * tree,const addrkey_t * addr,addrlen_t sourcemask,addrlen_t scope,void * elem,time_t ttl,time_t now,int only_match_scope_zero)36165b390aaSDag-Erling Smørgrav addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
36265b390aaSDag-Erling Smørgrav 	addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
363*865f46b2SCy Schubert 	time_t now, int only_match_scope_zero)
36465b390aaSDag-Erling Smørgrav {
36565b390aaSDag-Erling Smørgrav 	struct addrnode *newnode, *node;
36665b390aaSDag-Erling Smørgrav 	struct addredge *edge;
36765b390aaSDag-Erling Smørgrav 	int index;
36865b390aaSDag-Erling Smørgrav 	addrlen_t common, depth;
36965b390aaSDag-Erling Smørgrav 
37065b390aaSDag-Erling Smørgrav 	node = tree->root;
37165b390aaSDag-Erling Smørgrav 	log_assert(node != NULL);
37265b390aaSDag-Erling Smørgrav 
37365b390aaSDag-Erling Smørgrav 	/* Protect our cache against too much fine-grained data */
37465b390aaSDag-Erling Smørgrav 	if (tree->max_depth < scope) scope = tree->max_depth;
37565b390aaSDag-Erling Smørgrav 	/* Server answer was less specific than question */
37665b390aaSDag-Erling Smørgrav 	if (scope < sourcemask) sourcemask = scope;
37765b390aaSDag-Erling Smørgrav 
37865b390aaSDag-Erling Smørgrav 	depth = 0;
37965b390aaSDag-Erling Smørgrav 	while (1) {
38065b390aaSDag-Erling Smørgrav 		log_assert(depth <= sourcemask);
38165b390aaSDag-Erling Smørgrav 		/* Case 1: update existing node */
38265b390aaSDag-Erling Smørgrav 		if (depth == sourcemask) {
38365b390aaSDag-Erling Smørgrav 			/* update this node's scope and data */
38465b390aaSDag-Erling Smørgrav 			clean_node(tree, node);
38565b390aaSDag-Erling Smørgrav 			node->ttl = ttl;
386*865f46b2SCy Schubert 			node->only_match_scope_zero = only_match_scope_zero;
38765b390aaSDag-Erling Smørgrav 			node->elem = elem;
38865b390aaSDag-Erling Smørgrav 			node->scope = scope;
38965b390aaSDag-Erling Smørgrav 			tree->size_bytes += tree->sizefunc(elem);
39065b390aaSDag-Erling Smørgrav 			return;
39165b390aaSDag-Erling Smørgrav 		}
39265b390aaSDag-Erling Smørgrav 		index = getbit(addr, sourcemask, depth);
39365b390aaSDag-Erling Smørgrav 		/* Get an edge to an unexpired node */
39465b390aaSDag-Erling Smørgrav 		edge = node->edge[index];
39565b390aaSDag-Erling Smørgrav 		while (edge) {
39665b390aaSDag-Erling Smørgrav 			/* Purge all expired nodes on path */
39765b390aaSDag-Erling Smørgrav 			if (!edge->node->elem || edge->node->ttl >= now)
39865b390aaSDag-Erling Smørgrav 				break;
39965b390aaSDag-Erling Smørgrav 			purge_node(tree, edge->node);
40065b390aaSDag-Erling Smørgrav 			edge = node->edge[index];
40165b390aaSDag-Erling Smørgrav 		}
40265b390aaSDag-Erling Smørgrav 		/* Case 2: New leafnode */
40365b390aaSDag-Erling Smørgrav 		if (!edge) {
40465b390aaSDag-Erling Smørgrav 			newnode = node_create(tree, elem, scope, ttl);
40565b390aaSDag-Erling Smørgrav 			if (!newnode) return;
40665b390aaSDag-Erling Smørgrav 			if (!edge_create(newnode, addr, sourcemask, node,
40765b390aaSDag-Erling Smørgrav 				index)) {
40865b390aaSDag-Erling Smørgrav 				clean_node(tree, newnode);
40965b390aaSDag-Erling Smørgrav 				tree->node_count--;
41065b390aaSDag-Erling Smørgrav 				free(newnode);
41165b390aaSDag-Erling Smørgrav 				return;
41265b390aaSDag-Erling Smørgrav 			}
41365b390aaSDag-Erling Smørgrav 			tree->size_bytes += node_size(tree, newnode);
41465b390aaSDag-Erling Smørgrav 			lru_push(tree, newnode);
41565b390aaSDag-Erling Smørgrav 			lru_cleanup(tree);
41665b390aaSDag-Erling Smørgrav 			return;
41765b390aaSDag-Erling Smørgrav 		}
41865b390aaSDag-Erling Smørgrav 		/* Case 3: Traverse edge */
41965b390aaSDag-Erling Smørgrav 		common = bits_common(edge->str, edge->len, addr, sourcemask,
42065b390aaSDag-Erling Smørgrav 			depth);
42165b390aaSDag-Erling Smørgrav 		if (common == edge->len) {
42265b390aaSDag-Erling Smørgrav 			/* We update the scope of intermediate nodes. Apparently
42365b390aaSDag-Erling Smørgrav 			 * the * authority changed its mind. If we would not do
42465b390aaSDag-Erling Smørgrav 			 * this we might not be able to reach our new node. */
42565b390aaSDag-Erling Smørgrav 			node->scope = scope;
42665b390aaSDag-Erling Smørgrav 			depth = edge->len;
42765b390aaSDag-Erling Smørgrav 			node = edge->node;
42865b390aaSDag-Erling Smørgrav 			continue;
42965b390aaSDag-Erling Smørgrav 		}
43065b390aaSDag-Erling Smørgrav 		/* Case 4: split. */
43165b390aaSDag-Erling Smørgrav 		if (!(newnode = node_create(tree, NULL, 0, 0)))
43265b390aaSDag-Erling Smørgrav 			return;
43365b390aaSDag-Erling Smørgrav 		node->edge[index] = NULL;
43465b390aaSDag-Erling Smørgrav 		if (!edge_create(newnode, addr, common, node, index)) {
43565b390aaSDag-Erling Smørgrav 			node->edge[index] = edge;
43665b390aaSDag-Erling Smørgrav 			clean_node(tree, newnode);
43765b390aaSDag-Erling Smørgrav 			tree->node_count--;
43865b390aaSDag-Erling Smørgrav 			free(newnode);
43965b390aaSDag-Erling Smørgrav 			return;
44065b390aaSDag-Erling Smørgrav 		}
44165b390aaSDag-Erling Smørgrav 		lru_push(tree, newnode);
44265b390aaSDag-Erling Smørgrav 		/* connect existing child to our new node */
44365b390aaSDag-Erling Smørgrav 		index = getbit(edge->str, edge->len, common);
44465b390aaSDag-Erling Smørgrav 		newnode->edge[index] = edge;
44565b390aaSDag-Erling Smørgrav 		edge->parent_node = newnode;
44665b390aaSDag-Erling Smørgrav 		edge->parent_index = (int)index;
44765b390aaSDag-Erling Smørgrav 
44865b390aaSDag-Erling Smørgrav 		if (common == sourcemask) {
44965b390aaSDag-Erling Smørgrav 			/* Data is stored in the node */
45065b390aaSDag-Erling Smørgrav 			newnode->elem = elem;
45165b390aaSDag-Erling Smørgrav 			newnode->scope = scope;
45265b390aaSDag-Erling Smørgrav 			newnode->ttl = ttl;
453*865f46b2SCy Schubert 			newnode->only_match_scope_zero = only_match_scope_zero;
45465b390aaSDag-Erling Smørgrav 		}
45565b390aaSDag-Erling Smørgrav 
45665b390aaSDag-Erling Smørgrav 		tree->size_bytes += node_size(tree, newnode);
45765b390aaSDag-Erling Smørgrav 
45865b390aaSDag-Erling Smørgrav 		if (common != sourcemask) {
45965b390aaSDag-Erling Smørgrav 			/* Data is stored in other leafnode */
46065b390aaSDag-Erling Smørgrav 			node = newnode;
46165b390aaSDag-Erling Smørgrav 			newnode = node_create(tree, elem, scope, ttl);
46265b390aaSDag-Erling Smørgrav 			if (!edge_create(newnode, addr, sourcemask, node,
46365b390aaSDag-Erling Smørgrav 				index^1)) {
46465b390aaSDag-Erling Smørgrav 				clean_node(tree, newnode);
46565b390aaSDag-Erling Smørgrav 				tree->node_count--;
46665b390aaSDag-Erling Smørgrav 				free(newnode);
46765b390aaSDag-Erling Smørgrav 				return;
46865b390aaSDag-Erling Smørgrav 			}
46965b390aaSDag-Erling Smørgrav 			tree->size_bytes += node_size(tree, newnode);
47065b390aaSDag-Erling Smørgrav 			lru_push(tree, newnode);
47165b390aaSDag-Erling Smørgrav 		}
47265b390aaSDag-Erling Smørgrav 		lru_cleanup(tree);
47365b390aaSDag-Erling Smørgrav 		return;
47465b390aaSDag-Erling Smørgrav 	}
47565b390aaSDag-Erling Smørgrav }
47665b390aaSDag-Erling Smørgrav 
47765b390aaSDag-Erling Smørgrav struct addrnode *
addrtree_find(struct addrtree * tree,const addrkey_t * addr,addrlen_t sourcemask,time_t now)47865b390aaSDag-Erling Smørgrav addrtree_find(struct addrtree *tree, const addrkey_t *addr,
47965b390aaSDag-Erling Smørgrav 	addrlen_t sourcemask, time_t now)
48065b390aaSDag-Erling Smørgrav {
48165b390aaSDag-Erling Smørgrav 	struct addrnode *node = tree->root;
48265b390aaSDag-Erling Smørgrav 	struct addredge *edge = NULL;
48365b390aaSDag-Erling Smørgrav 	addrlen_t depth = 0;
48465b390aaSDag-Erling Smørgrav 
48565b390aaSDag-Erling Smørgrav 	log_assert(node != NULL);
48665b390aaSDag-Erling Smørgrav 	while (1) {
48765b390aaSDag-Erling Smørgrav 		/* Current node more specific then question. */
48865b390aaSDag-Erling Smørgrav 		log_assert(depth <= sourcemask);
48965b390aaSDag-Erling Smørgrav 		/* does this node have data? if yes, see if we have a match */
490*865f46b2SCy Schubert 		if (node->elem && node->ttl >= now &&
491*865f46b2SCy Schubert 			!(sourcemask != 0 && node->only_match_scope_zero)) {
49265b390aaSDag-Erling Smørgrav 			/* saved at wrong depth */;
49357bddd21SDag-Erling Smørgrav 			log_assert(node->scope >= depth);
49465b390aaSDag-Erling Smørgrav 			if (depth == node->scope ||
49565b390aaSDag-Erling Smørgrav 				(node->scope > sourcemask &&
49665b390aaSDag-Erling Smørgrav 				 depth == sourcemask)) {
49765b390aaSDag-Erling Smørgrav 				/* Authority indicates it does not have a more
49865b390aaSDag-Erling Smørgrav 				 * precise answer or we cannot ask a more
49965b390aaSDag-Erling Smørgrav 				 * specific question. */
50065b390aaSDag-Erling Smørgrav 				lru_update(tree, node);
50165b390aaSDag-Erling Smørgrav 				return node;
50265b390aaSDag-Erling Smørgrav 			}
50365b390aaSDag-Erling Smørgrav 		}
50465b390aaSDag-Erling Smørgrav 		/* This is our final depth, but we haven't found an answer. */
50565b390aaSDag-Erling Smørgrav 		if (depth == sourcemask)
50665b390aaSDag-Erling Smørgrav 			return NULL;
50765b390aaSDag-Erling Smørgrav 		/* Find an edge to traverse */
50865b390aaSDag-Erling Smørgrav 		edge = node->edge[getbit(addr, sourcemask, depth)];
50965b390aaSDag-Erling Smørgrav 		if (!edge || !edge->node)
51065b390aaSDag-Erling Smørgrav 			return NULL;
51165b390aaSDag-Erling Smørgrav 		if (edge->len > sourcemask )
51265b390aaSDag-Erling Smørgrav 			return NULL;
51365b390aaSDag-Erling Smørgrav 		if (!issub(edge->str, edge->len, addr, sourcemask, depth))
51465b390aaSDag-Erling Smørgrav 			return NULL;
51565b390aaSDag-Erling Smørgrav 		log_assert(depth < edge->len);
51665b390aaSDag-Erling Smørgrav 		depth = edge->len;
51765b390aaSDag-Erling Smørgrav 		node = edge->node;
51865b390aaSDag-Erling Smørgrav 	}
51965b390aaSDag-Erling Smørgrav }
52065b390aaSDag-Erling Smørgrav 
52165b390aaSDag-Erling Smørgrav /** Wrappers for static functions to unit test */
unittest_wrapper_addrtree_cmpbit(const addrkey_t * key1,const addrkey_t * key2,addrlen_t n)52265b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_cmpbit(const addrkey_t *key1,
52365b390aaSDag-Erling Smørgrav 	const addrkey_t *key2, addrlen_t n) {
52465b390aaSDag-Erling Smørgrav 	return cmpbit(key1, key2, n);
52565b390aaSDag-Erling Smørgrav }
unittest_wrapper_addrtree_bits_common(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)52665b390aaSDag-Erling Smørgrav addrlen_t unittest_wrapper_addrtree_bits_common(const addrkey_t *s1,
52765b390aaSDag-Erling Smørgrav 	addrlen_t l1, const addrkey_t *s2, addrlen_t l2, addrlen_t skip) {
52865b390aaSDag-Erling Smørgrav 	return bits_common(s1, l1, s2, l2, skip);
52965b390aaSDag-Erling Smørgrav }
unittest_wrapper_addrtree_getbit(const addrkey_t * addr,addrlen_t addrlen,addrlen_t n)53065b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_getbit(const addrkey_t *addr,
53165b390aaSDag-Erling Smørgrav 	addrlen_t addrlen, addrlen_t n) {
53265b390aaSDag-Erling Smørgrav 	return getbit(addr, addrlen, n);
53365b390aaSDag-Erling Smørgrav }
unittest_wrapper_addrtree_issub(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)53465b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_issub(const addrkey_t *s1, addrlen_t l1,
53565b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2,  addrlen_t skip) {
53665b390aaSDag-Erling Smørgrav 	return issub(s1, l1, s2, l2, skip);
53765b390aaSDag-Erling Smørgrav }
538