xref: /freebsd/contrib/unbound/edns-subnet/addrtree.c (revision 65b390aa03158608c95d842609dcc4c7129d6476)
1*65b390aaSDag-Erling Smørgrav /*
2*65b390aaSDag-Erling Smørgrav  * edns-subnet/addrtree.c -- radix tree for edns subnet cache.
3*65b390aaSDag-Erling Smørgrav  *
4*65b390aaSDag-Erling Smørgrav  * Copyright (c) 2013, NLnet Labs. All rights reserved.
5*65b390aaSDag-Erling Smørgrav  *
6*65b390aaSDag-Erling Smørgrav  * This software is open source.
7*65b390aaSDag-Erling Smørgrav  *
8*65b390aaSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9*65b390aaSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10*65b390aaSDag-Erling Smørgrav  * are met:
11*65b390aaSDag-Erling Smørgrav  *
12*65b390aaSDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13*65b390aaSDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14*65b390aaSDag-Erling Smørgrav  *
15*65b390aaSDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16*65b390aaSDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17*65b390aaSDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18*65b390aaSDag-Erling Smørgrav  *
19*65b390aaSDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20*65b390aaSDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21*65b390aaSDag-Erling Smørgrav  * specific prior written permission.
22*65b390aaSDag-Erling Smørgrav  *
23*65b390aaSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*65b390aaSDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*65b390aaSDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*65b390aaSDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*65b390aaSDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*65b390aaSDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*65b390aaSDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*65b390aaSDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*65b390aaSDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*65b390aaSDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*65b390aaSDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*65b390aaSDag-Erling Smørgrav  */
35*65b390aaSDag-Erling Smørgrav /** \file
36*65b390aaSDag-Erling Smørgrav  * addrtree -- radix tree for edns subnet cache.
37*65b390aaSDag-Erling Smørgrav  */
38*65b390aaSDag-Erling Smørgrav 
39*65b390aaSDag-Erling Smørgrav #include "config.h"
40*65b390aaSDag-Erling Smørgrav #include "util/log.h"
41*65b390aaSDag-Erling Smørgrav #include "util/data/msgreply.h"
42*65b390aaSDag-Erling Smørgrav #include "util/module.h"
43*65b390aaSDag-Erling Smørgrav #include "addrtree.h"
44*65b390aaSDag-Erling Smørgrav 
45*65b390aaSDag-Erling Smørgrav /**
46*65b390aaSDag-Erling Smørgrav  * Create a new edge
47*65b390aaSDag-Erling Smørgrav  * @param node: Child node this edge will connect to.
48*65b390aaSDag-Erling Smørgrav  * @param addr: full key to this edge.
49*65b390aaSDag-Erling Smørgrav  * @param addrlen: length of relevant part of key for this node
50*65b390aaSDag-Erling Smørgrav  * @param parent_node: Parent node for node
51*65b390aaSDag-Erling Smørgrav  * @param parent_index: Index of child node at parent node
52*65b390aaSDag-Erling Smørgrav  * @return new addredge or NULL on failure
53*65b390aaSDag-Erling Smørgrav  */
54*65b390aaSDag-Erling Smørgrav static struct addredge *
55*65b390aaSDag-Erling Smørgrav edge_create(struct addrnode *node, const addrkey_t *addr,
56*65b390aaSDag-Erling Smørgrav 	addrlen_t addrlen, struct addrnode *parent_node, int parent_index)
57*65b390aaSDag-Erling Smørgrav {
58*65b390aaSDag-Erling Smørgrav 	size_t n;
59*65b390aaSDag-Erling Smørgrav 	struct addredge *edge = (struct addredge *)malloc( sizeof (*edge) );
60*65b390aaSDag-Erling Smørgrav 	if (!edge)
61*65b390aaSDag-Erling Smørgrav 		return NULL;
62*65b390aaSDag-Erling Smørgrav 	edge->node = node;
63*65b390aaSDag-Erling Smørgrav 	edge->len = addrlen;
64*65b390aaSDag-Erling Smørgrav 	edge->parent_index = parent_index;
65*65b390aaSDag-Erling Smørgrav 	edge->parent_node = parent_node;
66*65b390aaSDag-Erling Smørgrav 	/* ceil() */
67*65b390aaSDag-Erling Smørgrav 	n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0));
68*65b390aaSDag-Erling Smørgrav 	edge->str = (addrkey_t *)calloc(n, sizeof (addrkey_t));
69*65b390aaSDag-Erling Smørgrav 	if (!edge->str) {
70*65b390aaSDag-Erling Smørgrav 		free(edge);
71*65b390aaSDag-Erling Smørgrav 		return NULL;
72*65b390aaSDag-Erling Smørgrav 	}
73*65b390aaSDag-Erling Smørgrav 	memcpy(edge->str, addr, n * sizeof (addrkey_t));
74*65b390aaSDag-Erling Smørgrav 	/* Only manipulate other objects after successful alloc */
75*65b390aaSDag-Erling Smørgrav 	node->parent_edge = edge;
76*65b390aaSDag-Erling Smørgrav 	log_assert(parent_node->edge[parent_index] == NULL);
77*65b390aaSDag-Erling Smørgrav 	parent_node->edge[parent_index] = edge;
78*65b390aaSDag-Erling Smørgrav 	return edge;
79*65b390aaSDag-Erling Smørgrav }
80*65b390aaSDag-Erling Smørgrav 
81*65b390aaSDag-Erling Smørgrav /**
82*65b390aaSDag-Erling Smørgrav  * Create a new node
83*65b390aaSDag-Erling Smørgrav  * @param tree: Tree the node lives in.
84*65b390aaSDag-Erling Smørgrav  * @param elem: Element to store at this node
85*65b390aaSDag-Erling Smørgrav  * @param scope: Scopemask from server reply
86*65b390aaSDag-Erling Smørgrav  * @param ttl: Element is valid up to this time. Absolute, seconds
87*65b390aaSDag-Erling Smørgrav  * @return new addrnode or NULL on failure
88*65b390aaSDag-Erling Smørgrav  */
89*65b390aaSDag-Erling Smørgrav static struct addrnode *
90*65b390aaSDag-Erling Smørgrav node_create(struct addrtree *tree, void *elem, addrlen_t scope,
91*65b390aaSDag-Erling Smørgrav 	time_t ttl)
92*65b390aaSDag-Erling Smørgrav {
93*65b390aaSDag-Erling Smørgrav 	struct addrnode* node = (struct addrnode *)malloc( sizeof (*node) );
94*65b390aaSDag-Erling Smørgrav 	if (!node)
95*65b390aaSDag-Erling Smørgrav 		return NULL;
96*65b390aaSDag-Erling Smørgrav 	node->elem = elem;
97*65b390aaSDag-Erling Smørgrav 	tree->node_count++;
98*65b390aaSDag-Erling Smørgrav 	node->scope = scope;
99*65b390aaSDag-Erling Smørgrav 	node->ttl = ttl;
100*65b390aaSDag-Erling Smørgrav 	node->edge[0] = NULL;
101*65b390aaSDag-Erling Smørgrav 	node->edge[1] = NULL;
102*65b390aaSDag-Erling Smørgrav 	node->parent_edge = NULL;
103*65b390aaSDag-Erling Smørgrav 	node->next = NULL;
104*65b390aaSDag-Erling Smørgrav 	node->prev = NULL;
105*65b390aaSDag-Erling Smørgrav 	return node;
106*65b390aaSDag-Erling Smørgrav }
107*65b390aaSDag-Erling Smørgrav 
108*65b390aaSDag-Erling Smørgrav /** Size in bytes of node and parent edge
109*65b390aaSDag-Erling Smørgrav  * @param tree: tree the node lives in
110*65b390aaSDag-Erling Smørgrav  * @param n: node which size must be calculated
111*65b390aaSDag-Erling Smørgrav  * @return size in bytes.
112*65b390aaSDag-Erling Smørgrav  **/
113*65b390aaSDag-Erling Smørgrav static inline size_t
114*65b390aaSDag-Erling Smørgrav node_size(const struct addrtree *tree, const struct addrnode *n)
115*65b390aaSDag-Erling Smørgrav {
116*65b390aaSDag-Erling Smørgrav 	return sizeof *n + sizeof *n->parent_edge + n->parent_edge->len +
117*65b390aaSDag-Erling Smørgrav 		(n->elem?tree->sizefunc(n->elem):0);
118*65b390aaSDag-Erling Smørgrav }
119*65b390aaSDag-Erling Smørgrav 
120*65b390aaSDag-Erling Smørgrav struct addrtree *
121*65b390aaSDag-Erling Smørgrav addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *),
122*65b390aaSDag-Erling Smørgrav 	size_t (*sizefunc)(void *), void *env, unsigned int max_node_count)
123*65b390aaSDag-Erling Smørgrav {
124*65b390aaSDag-Erling Smørgrav 	struct addrtree *tree;
125*65b390aaSDag-Erling Smørgrav 	log_assert(delfunc != NULL);
126*65b390aaSDag-Erling Smørgrav 	log_assert(sizefunc != NULL);
127*65b390aaSDag-Erling Smørgrav 	tree = (struct addrtree *)calloc(1, sizeof(*tree));
128*65b390aaSDag-Erling Smørgrav 	if (!tree)
129*65b390aaSDag-Erling Smørgrav 		return NULL;
130*65b390aaSDag-Erling Smørgrav 	tree->root = node_create(tree, NULL, 0, 0);
131*65b390aaSDag-Erling Smørgrav 	if (!tree->root) {
132*65b390aaSDag-Erling Smørgrav 		free(tree);
133*65b390aaSDag-Erling Smørgrav 		return NULL;
134*65b390aaSDag-Erling Smørgrav 	}
135*65b390aaSDag-Erling Smørgrav 	tree->size_bytes = sizeof *tree + sizeof *tree->root;
136*65b390aaSDag-Erling Smørgrav 	tree->first = NULL;
137*65b390aaSDag-Erling Smørgrav 	tree->last = NULL;
138*65b390aaSDag-Erling Smørgrav 	tree->max_depth = max_depth;
139*65b390aaSDag-Erling Smørgrav 	tree->delfunc = delfunc;
140*65b390aaSDag-Erling Smørgrav 	tree->sizefunc = sizefunc;
141*65b390aaSDag-Erling Smørgrav 	tree->env = env;
142*65b390aaSDag-Erling Smørgrav 	tree->node_count = 0;
143*65b390aaSDag-Erling Smørgrav 	tree->max_node_count = max_node_count;
144*65b390aaSDag-Erling Smørgrav 	return tree;
145*65b390aaSDag-Erling Smørgrav }
146*65b390aaSDag-Erling Smørgrav 
147*65b390aaSDag-Erling Smørgrav /**
148*65b390aaSDag-Erling Smørgrav  * Scrub a node clean of elem
149*65b390aaSDag-Erling Smørgrav  * @param tree: tree the node lives in.
150*65b390aaSDag-Erling Smørgrav  * @param node: node to be cleaned.
151*65b390aaSDag-Erling Smørgrav  */
152*65b390aaSDag-Erling Smørgrav static void
153*65b390aaSDag-Erling Smørgrav clean_node(struct addrtree *tree, struct addrnode *node)
154*65b390aaSDag-Erling Smørgrav {
155*65b390aaSDag-Erling Smørgrav 	if (!node->elem) return;
156*65b390aaSDag-Erling Smørgrav 	tree->size_bytes -= tree->sizefunc(node->elem);
157*65b390aaSDag-Erling Smørgrav 	tree->delfunc(tree->env, node->elem);
158*65b390aaSDag-Erling Smørgrav 	node->elem = NULL;
159*65b390aaSDag-Erling Smørgrav }
160*65b390aaSDag-Erling Smørgrav 
161*65b390aaSDag-Erling Smørgrav /** Remove specified node from LRU list */
162*65b390aaSDag-Erling Smørgrav static void
163*65b390aaSDag-Erling Smørgrav lru_pop(struct addrtree *tree, struct addrnode *node)
164*65b390aaSDag-Erling Smørgrav {
165*65b390aaSDag-Erling Smørgrav 	if (node == tree->first) {
166*65b390aaSDag-Erling Smørgrav 		if (!node->next) { /* it is the last as well */
167*65b390aaSDag-Erling Smørgrav 			tree->first = NULL;
168*65b390aaSDag-Erling Smørgrav 			tree->last = NULL;
169*65b390aaSDag-Erling Smørgrav 		} else {
170*65b390aaSDag-Erling Smørgrav 			tree->first = node->next;
171*65b390aaSDag-Erling Smørgrav 			tree->first->prev = NULL;
172*65b390aaSDag-Erling Smørgrav 		}
173*65b390aaSDag-Erling Smørgrav 	} else if (node == tree->last) { /* but not the first */
174*65b390aaSDag-Erling Smørgrav 		tree->last = node->prev;
175*65b390aaSDag-Erling Smørgrav 		tree->last->next = NULL;
176*65b390aaSDag-Erling Smørgrav 	} else {
177*65b390aaSDag-Erling Smørgrav 		node->prev->next = node->next;
178*65b390aaSDag-Erling Smørgrav 		node->next->prev = node->prev;
179*65b390aaSDag-Erling Smørgrav 	}
180*65b390aaSDag-Erling Smørgrav }
181*65b390aaSDag-Erling Smørgrav 
182*65b390aaSDag-Erling Smørgrav /** Add node to LRU list as most recently used. */
183*65b390aaSDag-Erling Smørgrav static void
184*65b390aaSDag-Erling Smørgrav lru_push(struct addrtree *tree, struct addrnode *node)
185*65b390aaSDag-Erling Smørgrav {
186*65b390aaSDag-Erling Smørgrav 	if (!tree->first) {
187*65b390aaSDag-Erling Smørgrav 		tree->first = node;
188*65b390aaSDag-Erling Smørgrav 		node->prev = NULL;
189*65b390aaSDag-Erling Smørgrav 	} else {
190*65b390aaSDag-Erling Smørgrav 		tree->last->next = node;
191*65b390aaSDag-Erling Smørgrav 		node->prev = tree->last;
192*65b390aaSDag-Erling Smørgrav 	}
193*65b390aaSDag-Erling Smørgrav 	tree->last = node;
194*65b390aaSDag-Erling Smørgrav 	node->next = NULL;
195*65b390aaSDag-Erling Smørgrav }
196*65b390aaSDag-Erling Smørgrav 
197*65b390aaSDag-Erling Smørgrav /** Move node to the end of LRU list */
198*65b390aaSDag-Erling Smørgrav static void
199*65b390aaSDag-Erling Smørgrav lru_update(struct addrtree *tree, struct addrnode *node)
200*65b390aaSDag-Erling Smørgrav {
201*65b390aaSDag-Erling Smørgrav 	if (tree->root == node) return;
202*65b390aaSDag-Erling Smørgrav 	lru_pop(tree, node);
203*65b390aaSDag-Erling Smørgrav 	lru_push(tree, node);
204*65b390aaSDag-Erling Smørgrav }
205*65b390aaSDag-Erling Smørgrav 
206*65b390aaSDag-Erling Smørgrav /**
207*65b390aaSDag-Erling Smørgrav  * Purge a node from the tree. Node and parentedge are cleaned and
208*65b390aaSDag-Erling Smørgrav  * free'd.
209*65b390aaSDag-Erling Smørgrav  * @param tree: Tree the node lives in.
210*65b390aaSDag-Erling Smørgrav  * @param node: Node to be freed
211*65b390aaSDag-Erling Smørgrav  */
212*65b390aaSDag-Erling Smørgrav static void
213*65b390aaSDag-Erling Smørgrav purge_node(struct addrtree *tree, struct addrnode *node)
214*65b390aaSDag-Erling Smørgrav {
215*65b390aaSDag-Erling Smørgrav 	struct addredge *parent_edge, *child_edge = NULL;
216*65b390aaSDag-Erling Smørgrav 	int index;
217*65b390aaSDag-Erling Smørgrav 	int keep = node->edge[0] && node->edge[1];
218*65b390aaSDag-Erling Smørgrav 
219*65b390aaSDag-Erling Smørgrav 	clean_node(tree, node);
220*65b390aaSDag-Erling Smørgrav 	parent_edge = node->parent_edge;
221*65b390aaSDag-Erling Smørgrav 	if (keep || !parent_edge) return;
222*65b390aaSDag-Erling Smørgrav 	tree->node_count--;
223*65b390aaSDag-Erling Smørgrav 	index = parent_edge->parent_index;
224*65b390aaSDag-Erling Smørgrav 	child_edge = node->edge[!node->edge[0]];
225*65b390aaSDag-Erling Smørgrav 	if (child_edge) {
226*65b390aaSDag-Erling Smørgrav 		child_edge->parent_node  = parent_edge->parent_node;
227*65b390aaSDag-Erling Smørgrav 		child_edge->parent_index = index;
228*65b390aaSDag-Erling Smørgrav 	}
229*65b390aaSDag-Erling Smørgrav 	parent_edge->parent_node->edge[index] = child_edge;
230*65b390aaSDag-Erling Smørgrav 	tree->size_bytes -= node_size(tree, node);
231*65b390aaSDag-Erling Smørgrav 	free(parent_edge->str);
232*65b390aaSDag-Erling Smørgrav 	free(parent_edge);
233*65b390aaSDag-Erling Smørgrav 	lru_pop(tree, node);
234*65b390aaSDag-Erling Smørgrav 	free(node);
235*65b390aaSDag-Erling Smørgrav }
236*65b390aaSDag-Erling Smørgrav 
237*65b390aaSDag-Erling Smørgrav /**
238*65b390aaSDag-Erling Smørgrav  * If a limit is set remove old nodes while above that limit.
239*65b390aaSDag-Erling Smørgrav  * @param tree: Tree to be cleaned up.
240*65b390aaSDag-Erling Smørgrav  */
241*65b390aaSDag-Erling Smørgrav static void
242*65b390aaSDag-Erling Smørgrav lru_cleanup(struct addrtree *tree)
243*65b390aaSDag-Erling Smørgrav {
244*65b390aaSDag-Erling Smørgrav 	struct addrnode *n, *p;
245*65b390aaSDag-Erling Smørgrav 	int children;
246*65b390aaSDag-Erling Smørgrav 	if (tree->max_node_count == 0) return;
247*65b390aaSDag-Erling Smørgrav 	while (tree->node_count > tree->max_node_count) {
248*65b390aaSDag-Erling Smørgrav 		n = tree->first;
249*65b390aaSDag-Erling Smørgrav 		if (!n) break;
250*65b390aaSDag-Erling Smørgrav 		children = (n->edge[0] != NULL) + (n->edge[1] != NULL);
251*65b390aaSDag-Erling Smørgrav 		/** Don't remove this node, it is either the root or we can't
252*65b390aaSDag-Erling Smørgrav 		 * do without it because it has 2 children */
253*65b390aaSDag-Erling Smørgrav 		if (children == 2 || !n->parent_edge) {
254*65b390aaSDag-Erling Smørgrav 			lru_update(tree, n);
255*65b390aaSDag-Erling Smørgrav 			continue;
256*65b390aaSDag-Erling Smørgrav 		}
257*65b390aaSDag-Erling Smørgrav 		p = n->parent_edge->parent_node;
258*65b390aaSDag-Erling Smørgrav 		purge_node(tree, n);
259*65b390aaSDag-Erling Smørgrav 		/** Since we removed n, n's parent p is eligible for deletion
260*65b390aaSDag-Erling Smørgrav 		 * if it is not the root node, caries no data and has only 1
261*65b390aaSDag-Erling Smørgrav 		 * child */
262*65b390aaSDag-Erling Smørgrav 		children = (p->edge[0] != NULL) + (p->edge[1] != NULL);
263*65b390aaSDag-Erling Smørgrav 		if (!p->elem && children == 1 && p->parent_edge) {
264*65b390aaSDag-Erling Smørgrav 			purge_node(tree, p);
265*65b390aaSDag-Erling Smørgrav 		}
266*65b390aaSDag-Erling Smørgrav 	}
267*65b390aaSDag-Erling Smørgrav }
268*65b390aaSDag-Erling Smørgrav 
269*65b390aaSDag-Erling Smørgrav inline size_t
270*65b390aaSDag-Erling Smørgrav addrtree_size(const struct addrtree *tree)
271*65b390aaSDag-Erling Smørgrav {
272*65b390aaSDag-Erling Smørgrav 	return tree?tree->size_bytes:0;
273*65b390aaSDag-Erling Smørgrav }
274*65b390aaSDag-Erling Smørgrav 
275*65b390aaSDag-Erling Smørgrav void addrtree_delete(struct addrtree *tree)
276*65b390aaSDag-Erling Smørgrav {
277*65b390aaSDag-Erling Smørgrav 	struct addrnode *n;
278*65b390aaSDag-Erling Smørgrav 	if (!tree) return;
279*65b390aaSDag-Erling Smørgrav 	clean_node(tree, tree->root);
280*65b390aaSDag-Erling Smørgrav 	free(tree->root);
281*65b390aaSDag-Erling Smørgrav 	tree->size_bytes -= sizeof(struct addrnode);
282*65b390aaSDag-Erling Smørgrav 	while ((n = tree->first)) {
283*65b390aaSDag-Erling Smørgrav 		tree->first = n->next;
284*65b390aaSDag-Erling Smørgrav 		clean_node(tree, n);
285*65b390aaSDag-Erling Smørgrav 		tree->size_bytes -= node_size(tree, n);
286*65b390aaSDag-Erling Smørgrav 		free(n->parent_edge->str);
287*65b390aaSDag-Erling Smørgrav 		free(n->parent_edge);
288*65b390aaSDag-Erling Smørgrav 		free(n);
289*65b390aaSDag-Erling Smørgrav 	}
290*65b390aaSDag-Erling Smørgrav 	log_assert(sizeof *tree == addrtree_size(tree));
291*65b390aaSDag-Erling Smørgrav 	free(tree);
292*65b390aaSDag-Erling Smørgrav }
293*65b390aaSDag-Erling Smørgrav 
294*65b390aaSDag-Erling Smørgrav /**
295*65b390aaSDag-Erling Smørgrav  * Get N'th bit from address
296*65b390aaSDag-Erling Smørgrav  * @param addr: address to inspect
297*65b390aaSDag-Erling Smørgrav  * @param addrlen: length of addr in bits
298*65b390aaSDag-Erling Smørgrav  * @param n: index of bit to test. Must be in range [0, addrlen)
299*65b390aaSDag-Erling Smørgrav  * @return 0 or 1
300*65b390aaSDag-Erling Smørgrav  */
301*65b390aaSDag-Erling Smørgrav static int
302*65b390aaSDag-Erling Smørgrav getbit(const addrkey_t *addr, addrlen_t addrlen, addrlen_t n)
303*65b390aaSDag-Erling Smørgrav {
304*65b390aaSDag-Erling Smørgrav 	log_assert(addrlen > n);
305*65b390aaSDag-Erling Smørgrav 	return (int)(addr[n/KEYWIDTH]>>((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
306*65b390aaSDag-Erling Smørgrav }
307*65b390aaSDag-Erling Smørgrav 
308*65b390aaSDag-Erling Smørgrav /**
309*65b390aaSDag-Erling Smørgrav  * Test for equality on N'th bit.
310*65b390aaSDag-Erling Smørgrav  * @return 0 for equal, 1 otherwise
311*65b390aaSDag-Erling Smørgrav  */
312*65b390aaSDag-Erling Smørgrav static inline int
313*65b390aaSDag-Erling Smørgrav cmpbit(const addrkey_t *key1, const addrkey_t *key2, addrlen_t n)
314*65b390aaSDag-Erling Smørgrav {
315*65b390aaSDag-Erling Smørgrav 	addrkey_t c = key1[n/KEYWIDTH] ^ key2[n/KEYWIDTH];
316*65b390aaSDag-Erling Smørgrav 	return (int)(c >> ((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
317*65b390aaSDag-Erling Smørgrav }
318*65b390aaSDag-Erling Smørgrav 
319*65b390aaSDag-Erling Smørgrav /**
320*65b390aaSDag-Erling Smørgrav  * Common number of bits in prefix.
321*65b390aaSDag-Erling Smørgrav  * @param s1: first prefix.
322*65b390aaSDag-Erling Smørgrav  * @param l1: length of s1 in bits.
323*65b390aaSDag-Erling Smørgrav  * @param s2: second prefix.
324*65b390aaSDag-Erling Smørgrav  * @param l2: length of s2 in bits.
325*65b390aaSDag-Erling Smørgrav  * @param skip: nr of bits already checked.
326*65b390aaSDag-Erling Smørgrav  * @return common number of bits.
327*65b390aaSDag-Erling Smørgrav  */
328*65b390aaSDag-Erling Smørgrav static addrlen_t
329*65b390aaSDag-Erling Smørgrav bits_common(const addrkey_t *s1, addrlen_t l1,
330*65b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2, addrlen_t skip)
331*65b390aaSDag-Erling Smørgrav {
332*65b390aaSDag-Erling Smørgrav 	addrlen_t len, i;
333*65b390aaSDag-Erling Smørgrav 	len = (l1 > l2) ? l2 : l1;
334*65b390aaSDag-Erling Smørgrav 	log_assert(skip < len);
335*65b390aaSDag-Erling Smørgrav 	for (i = skip; i < len; i++) {
336*65b390aaSDag-Erling Smørgrav 		if (cmpbit(s1, s2, i)) return i;
337*65b390aaSDag-Erling Smørgrav 	}
338*65b390aaSDag-Erling Smørgrav 	return len;
339*65b390aaSDag-Erling Smørgrav }
340*65b390aaSDag-Erling Smørgrav 
341*65b390aaSDag-Erling Smørgrav /**
342*65b390aaSDag-Erling Smørgrav  * Tests if s1 is a substring of s2
343*65b390aaSDag-Erling Smørgrav  * @param s1: first prefix.
344*65b390aaSDag-Erling Smørgrav  * @param l1: length of s1 in bits.
345*65b390aaSDag-Erling Smørgrav  * @param s2: second prefix.
346*65b390aaSDag-Erling Smørgrav  * @param l2: length of s2 in bits.
347*65b390aaSDag-Erling Smørgrav  * @param skip: nr of bits already checked.
348*65b390aaSDag-Erling Smørgrav  * @return 1 for substring, 0 otherwise
349*65b390aaSDag-Erling Smørgrav  */
350*65b390aaSDag-Erling Smørgrav static int
351*65b390aaSDag-Erling Smørgrav issub(const addrkey_t *s1, addrlen_t l1,
352*65b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2,  addrlen_t skip)
353*65b390aaSDag-Erling Smørgrav {
354*65b390aaSDag-Erling Smørgrav 	return bits_common(s1, l1, s2, l2, skip) == l1;
355*65b390aaSDag-Erling Smørgrav }
356*65b390aaSDag-Erling Smørgrav 
357*65b390aaSDag-Erling Smørgrav void
358*65b390aaSDag-Erling Smørgrav addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
359*65b390aaSDag-Erling Smørgrav 	addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
360*65b390aaSDag-Erling Smørgrav 	time_t now)
361*65b390aaSDag-Erling Smørgrav {
362*65b390aaSDag-Erling Smørgrav 	struct addrnode *newnode, *node;
363*65b390aaSDag-Erling Smørgrav 	struct addredge *edge;
364*65b390aaSDag-Erling Smørgrav 	int index;
365*65b390aaSDag-Erling Smørgrav 	addrlen_t common, depth;
366*65b390aaSDag-Erling Smørgrav 
367*65b390aaSDag-Erling Smørgrav 	node = tree->root;
368*65b390aaSDag-Erling Smørgrav 	log_assert(node != NULL);
369*65b390aaSDag-Erling Smørgrav 
370*65b390aaSDag-Erling Smørgrav 	/* Protect our cache against too much fine-grained data */
371*65b390aaSDag-Erling Smørgrav 	if (tree->max_depth < scope) scope = tree->max_depth;
372*65b390aaSDag-Erling Smørgrav 	/* Server answer was less specific than question */
373*65b390aaSDag-Erling Smørgrav 	if (scope < sourcemask) sourcemask = scope;
374*65b390aaSDag-Erling Smørgrav 
375*65b390aaSDag-Erling Smørgrav 	depth = 0;
376*65b390aaSDag-Erling Smørgrav 	while (1) {
377*65b390aaSDag-Erling Smørgrav 		log_assert(depth <= sourcemask);
378*65b390aaSDag-Erling Smørgrav 		/* Case 1: update existing node */
379*65b390aaSDag-Erling Smørgrav 		if (depth == sourcemask) {
380*65b390aaSDag-Erling Smørgrav 			/* update this node's scope and data */
381*65b390aaSDag-Erling Smørgrav 			clean_node(tree, node);
382*65b390aaSDag-Erling Smørgrav 			node->ttl = ttl;
383*65b390aaSDag-Erling Smørgrav 			node->elem = elem;
384*65b390aaSDag-Erling Smørgrav 			node->scope = scope;
385*65b390aaSDag-Erling Smørgrav 			tree->size_bytes += tree->sizefunc(elem);
386*65b390aaSDag-Erling Smørgrav 			return;
387*65b390aaSDag-Erling Smørgrav 		}
388*65b390aaSDag-Erling Smørgrav 		index = getbit(addr, sourcemask, depth);
389*65b390aaSDag-Erling Smørgrav 		/* Get an edge to an unexpired node */
390*65b390aaSDag-Erling Smørgrav 		edge = node->edge[index];
391*65b390aaSDag-Erling Smørgrav 		while (edge) {
392*65b390aaSDag-Erling Smørgrav 			/* Purge all expired nodes on path */
393*65b390aaSDag-Erling Smørgrav 			if (!edge->node->elem || edge->node->ttl >= now)
394*65b390aaSDag-Erling Smørgrav 				break;
395*65b390aaSDag-Erling Smørgrav 			purge_node(tree, edge->node);
396*65b390aaSDag-Erling Smørgrav 			edge = node->edge[index];
397*65b390aaSDag-Erling Smørgrav 		}
398*65b390aaSDag-Erling Smørgrav 		/* Case 2: New leafnode */
399*65b390aaSDag-Erling Smørgrav 		if (!edge) {
400*65b390aaSDag-Erling Smørgrav 			newnode = node_create(tree, elem, scope, ttl);
401*65b390aaSDag-Erling Smørgrav 			if (!newnode) return;
402*65b390aaSDag-Erling Smørgrav 			if (!edge_create(newnode, addr, sourcemask, node,
403*65b390aaSDag-Erling Smørgrav 				index)) {
404*65b390aaSDag-Erling Smørgrav 				clean_node(tree, newnode);
405*65b390aaSDag-Erling Smørgrav 				tree->node_count--;
406*65b390aaSDag-Erling Smørgrav 				free(newnode);
407*65b390aaSDag-Erling Smørgrav 				return;
408*65b390aaSDag-Erling Smørgrav 			}
409*65b390aaSDag-Erling Smørgrav 			tree->size_bytes += node_size(tree, newnode);
410*65b390aaSDag-Erling Smørgrav 			lru_push(tree, newnode);
411*65b390aaSDag-Erling Smørgrav 			lru_cleanup(tree);
412*65b390aaSDag-Erling Smørgrav 			return;
413*65b390aaSDag-Erling Smørgrav 		}
414*65b390aaSDag-Erling Smørgrav 		/* Case 3: Traverse edge */
415*65b390aaSDag-Erling Smørgrav 		common = bits_common(edge->str, edge->len, addr, sourcemask,
416*65b390aaSDag-Erling Smørgrav 			depth);
417*65b390aaSDag-Erling Smørgrav 		if (common == edge->len) {
418*65b390aaSDag-Erling Smørgrav 			/* We update the scope of intermediate nodes. Apparently
419*65b390aaSDag-Erling Smørgrav 			 * the * authority changed its mind. If we would not do
420*65b390aaSDag-Erling Smørgrav 			 * this we might not be able to reach our new node. */
421*65b390aaSDag-Erling Smørgrav 			node->scope = scope;
422*65b390aaSDag-Erling Smørgrav 			depth = edge->len;
423*65b390aaSDag-Erling Smørgrav 			node = edge->node;
424*65b390aaSDag-Erling Smørgrav 			continue;
425*65b390aaSDag-Erling Smørgrav 		}
426*65b390aaSDag-Erling Smørgrav 		/* Case 4: split. */
427*65b390aaSDag-Erling Smørgrav 		if (!(newnode = node_create(tree, NULL, 0, 0)))
428*65b390aaSDag-Erling Smørgrav 			return;
429*65b390aaSDag-Erling Smørgrav 		node->edge[index] = NULL;
430*65b390aaSDag-Erling Smørgrav 		if (!edge_create(newnode, addr, common, node, index)) {
431*65b390aaSDag-Erling Smørgrav 			node->edge[index] = edge;
432*65b390aaSDag-Erling Smørgrav 			clean_node(tree, newnode);
433*65b390aaSDag-Erling Smørgrav 			tree->node_count--;
434*65b390aaSDag-Erling Smørgrav 			free(newnode);
435*65b390aaSDag-Erling Smørgrav 			return;
436*65b390aaSDag-Erling Smørgrav 		}
437*65b390aaSDag-Erling Smørgrav 		lru_push(tree, newnode);
438*65b390aaSDag-Erling Smørgrav 		/* connect existing child to our new node */
439*65b390aaSDag-Erling Smørgrav 		index = getbit(edge->str, edge->len, common);
440*65b390aaSDag-Erling Smørgrav 		newnode->edge[index] = edge;
441*65b390aaSDag-Erling Smørgrav 		edge->parent_node = newnode;
442*65b390aaSDag-Erling Smørgrav 		edge->parent_index = (int)index;
443*65b390aaSDag-Erling Smørgrav 
444*65b390aaSDag-Erling Smørgrav 		if (common == sourcemask) {
445*65b390aaSDag-Erling Smørgrav 			/* Data is stored in the node */
446*65b390aaSDag-Erling Smørgrav 			newnode->elem = elem;
447*65b390aaSDag-Erling Smørgrav 			newnode->scope = scope;
448*65b390aaSDag-Erling Smørgrav 			newnode->ttl = ttl;
449*65b390aaSDag-Erling Smørgrav 		}
450*65b390aaSDag-Erling Smørgrav 
451*65b390aaSDag-Erling Smørgrav 		tree->size_bytes += node_size(tree, newnode);
452*65b390aaSDag-Erling Smørgrav 
453*65b390aaSDag-Erling Smørgrav 		if (common != sourcemask) {
454*65b390aaSDag-Erling Smørgrav 			/* Data is stored in other leafnode */
455*65b390aaSDag-Erling Smørgrav 			node = newnode;
456*65b390aaSDag-Erling Smørgrav 			newnode = node_create(tree, elem, scope, ttl);
457*65b390aaSDag-Erling Smørgrav 			if (!edge_create(newnode, addr, sourcemask, node,
458*65b390aaSDag-Erling Smørgrav 				index^1)) {
459*65b390aaSDag-Erling Smørgrav 				clean_node(tree, newnode);
460*65b390aaSDag-Erling Smørgrav 				tree->node_count--;
461*65b390aaSDag-Erling Smørgrav 				free(newnode);
462*65b390aaSDag-Erling Smørgrav 				return;
463*65b390aaSDag-Erling Smørgrav 			}
464*65b390aaSDag-Erling Smørgrav 			tree->size_bytes += node_size(tree, newnode);
465*65b390aaSDag-Erling Smørgrav 			lru_push(tree, newnode);
466*65b390aaSDag-Erling Smørgrav 		}
467*65b390aaSDag-Erling Smørgrav 		lru_cleanup(tree);
468*65b390aaSDag-Erling Smørgrav 		return;
469*65b390aaSDag-Erling Smørgrav 	}
470*65b390aaSDag-Erling Smørgrav }
471*65b390aaSDag-Erling Smørgrav 
472*65b390aaSDag-Erling Smørgrav struct addrnode *
473*65b390aaSDag-Erling Smørgrav addrtree_find(struct addrtree *tree, const addrkey_t *addr,
474*65b390aaSDag-Erling Smørgrav 	addrlen_t sourcemask, time_t now)
475*65b390aaSDag-Erling Smørgrav {
476*65b390aaSDag-Erling Smørgrav 	struct addrnode *node = tree->root;
477*65b390aaSDag-Erling Smørgrav 	struct addredge *edge = NULL;
478*65b390aaSDag-Erling Smørgrav 	addrlen_t depth = 0;
479*65b390aaSDag-Erling Smørgrav 
480*65b390aaSDag-Erling Smørgrav 	log_assert(node != NULL);
481*65b390aaSDag-Erling Smørgrav 	while (1) {
482*65b390aaSDag-Erling Smørgrav 		/* Current node more specific then question. */
483*65b390aaSDag-Erling Smørgrav 		log_assert(depth <= sourcemask);
484*65b390aaSDag-Erling Smørgrav 		/* does this node have data? if yes, see if we have a match */
485*65b390aaSDag-Erling Smørgrav 		if (node->elem && node->ttl >= now) {
486*65b390aaSDag-Erling Smørgrav 			/* saved at wrong depth */;
487*65b390aaSDag-Erling Smørgrav 			log_assert(node->scope >= depth)
488*65b390aaSDag-Erling Smørgrav 			if (depth == node->scope ||
489*65b390aaSDag-Erling Smørgrav 				(node->scope > sourcemask &&
490*65b390aaSDag-Erling Smørgrav 				 depth == sourcemask)) {
491*65b390aaSDag-Erling Smørgrav 				/* Authority indicates it does not have a more
492*65b390aaSDag-Erling Smørgrav 				 * precise answer or we cannot ask a more
493*65b390aaSDag-Erling Smørgrav 				 * specific question. */
494*65b390aaSDag-Erling Smørgrav 				lru_update(tree, node);
495*65b390aaSDag-Erling Smørgrav 				return node;
496*65b390aaSDag-Erling Smørgrav 			}
497*65b390aaSDag-Erling Smørgrav 		}
498*65b390aaSDag-Erling Smørgrav 		/* This is our final depth, but we haven't found an answer. */
499*65b390aaSDag-Erling Smørgrav 		if (depth == sourcemask)
500*65b390aaSDag-Erling Smørgrav 			return NULL;
501*65b390aaSDag-Erling Smørgrav 		/* Find an edge to traverse */
502*65b390aaSDag-Erling Smørgrav 		edge = node->edge[getbit(addr, sourcemask, depth)];
503*65b390aaSDag-Erling Smørgrav 		if (!edge || !edge->node)
504*65b390aaSDag-Erling Smørgrav 			return NULL;
505*65b390aaSDag-Erling Smørgrav 		if (edge->len > sourcemask )
506*65b390aaSDag-Erling Smørgrav 			return NULL;
507*65b390aaSDag-Erling Smørgrav 		if (!issub(edge->str, edge->len, addr, sourcemask, depth))
508*65b390aaSDag-Erling Smørgrav 			return NULL;
509*65b390aaSDag-Erling Smørgrav 		log_assert(depth < edge->len);
510*65b390aaSDag-Erling Smørgrav 		depth = edge->len;
511*65b390aaSDag-Erling Smørgrav 		node = edge->node;
512*65b390aaSDag-Erling Smørgrav 	}
513*65b390aaSDag-Erling Smørgrav }
514*65b390aaSDag-Erling Smørgrav 
515*65b390aaSDag-Erling Smørgrav /** Wrappers for static functions to unit test */
516*65b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_cmpbit(const addrkey_t *key1,
517*65b390aaSDag-Erling Smørgrav 	const addrkey_t *key2, addrlen_t n) {
518*65b390aaSDag-Erling Smørgrav 	return cmpbit(key1, key2, n);
519*65b390aaSDag-Erling Smørgrav }
520*65b390aaSDag-Erling Smørgrav addrlen_t unittest_wrapper_addrtree_bits_common(const addrkey_t *s1,
521*65b390aaSDag-Erling Smørgrav 	addrlen_t l1, const addrkey_t *s2, addrlen_t l2, addrlen_t skip) {
522*65b390aaSDag-Erling Smørgrav 	return bits_common(s1, l1, s2, l2, skip);
523*65b390aaSDag-Erling Smørgrav }
524*65b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_getbit(const addrkey_t *addr,
525*65b390aaSDag-Erling Smørgrav 	addrlen_t addrlen, addrlen_t n) {
526*65b390aaSDag-Erling Smørgrav 	return getbit(addr, addrlen, n);
527*65b390aaSDag-Erling Smørgrav }
528*65b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_issub(const addrkey_t *s1, addrlen_t l1,
529*65b390aaSDag-Erling Smørgrav 	const addrkey_t *s2, addrlen_t l2,  addrlen_t skip) {
530*65b390aaSDag-Erling Smørgrav 	return issub(s1, l1, s2, l2, skip);
531*65b390aaSDag-Erling Smørgrav }
532