12be9e038Ssthen /*
22be9e038Ssthen * edns-subnet/addrtree.c -- radix tree for edns subnet cache.
32be9e038Ssthen *
42be9e038Ssthen * Copyright (c) 2013, NLnet Labs. All rights reserved.
52be9e038Ssthen *
62be9e038Ssthen * This software is open source.
72be9e038Ssthen *
82be9e038Ssthen * Redistribution and use in source and binary forms, with or without
92be9e038Ssthen * modification, are permitted provided that the following conditions
102be9e038Ssthen * are met:
112be9e038Ssthen *
122be9e038Ssthen * Redistributions of source code must retain the above copyright notice,
132be9e038Ssthen * this list of conditions and the following disclaimer.
142be9e038Ssthen *
152be9e038Ssthen * Redistributions in binary form must reproduce the above copyright notice,
162be9e038Ssthen * this list of conditions and the following disclaimer in the documentation
172be9e038Ssthen * and/or other materials provided with the distribution.
182be9e038Ssthen *
192be9e038Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
202be9e038Ssthen * be used to endorse or promote products derived from this software without
212be9e038Ssthen * specific prior written permission.
222be9e038Ssthen *
232be9e038Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
242be9e038Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
252be9e038Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
262be9e038Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
272be9e038Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
282be9e038Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
292be9e038Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
302be9e038Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
312be9e038Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
322be9e038Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
332be9e038Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
342be9e038Ssthen */
352be9e038Ssthen /** \file
362be9e038Ssthen * addrtree -- radix tree for edns subnet cache.
372be9e038Ssthen */
382be9e038Ssthen
392be9e038Ssthen #include "config.h"
402be9e038Ssthen #include "util/log.h"
412be9e038Ssthen #include "util/data/msgreply.h"
422be9e038Ssthen #include "util/module.h"
432be9e038Ssthen #include "addrtree.h"
442be9e038Ssthen
452be9e038Ssthen /**
462be9e038Ssthen * Create a new edge
472be9e038Ssthen * @param node: Child node this edge will connect to.
482be9e038Ssthen * @param addr: full key to this edge.
492be9e038Ssthen * @param addrlen: length of relevant part of key for this node
502be9e038Ssthen * @param parent_node: Parent node for node
512be9e038Ssthen * @param parent_index: Index of child node at parent node
522be9e038Ssthen * @return new addredge or NULL on failure
532be9e038Ssthen */
542be9e038Ssthen static struct addredge *
edge_create(struct addrnode * node,const addrkey_t * addr,addrlen_t addrlen,struct addrnode * parent_node,int parent_index)552be9e038Ssthen edge_create(struct addrnode *node, const addrkey_t *addr,
562be9e038Ssthen addrlen_t addrlen, struct addrnode *parent_node, int parent_index)
572be9e038Ssthen {
582be9e038Ssthen size_t n;
592be9e038Ssthen struct addredge *edge = (struct addredge *)malloc( sizeof (*edge) );
602be9e038Ssthen if (!edge)
612be9e038Ssthen return NULL;
622be9e038Ssthen edge->node = node;
632be9e038Ssthen edge->len = addrlen;
642be9e038Ssthen edge->parent_index = parent_index;
652be9e038Ssthen edge->parent_node = parent_node;
662be9e038Ssthen /* ceil() */
672be9e038Ssthen n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0));
682be9e038Ssthen edge->str = (addrkey_t *)calloc(n, sizeof (addrkey_t));
692be9e038Ssthen if (!edge->str) {
702be9e038Ssthen free(edge);
712be9e038Ssthen return NULL;
722be9e038Ssthen }
732be9e038Ssthen memcpy(edge->str, addr, n * sizeof (addrkey_t));
742be9e038Ssthen /* Only manipulate other objects after successful alloc */
752be9e038Ssthen node->parent_edge = edge;
762be9e038Ssthen log_assert(parent_node->edge[parent_index] == NULL);
772be9e038Ssthen parent_node->edge[parent_index] = edge;
782be9e038Ssthen return edge;
792be9e038Ssthen }
802be9e038Ssthen
812be9e038Ssthen /**
822be9e038Ssthen * Create a new node
832be9e038Ssthen * @param tree: Tree the node lives in.
842be9e038Ssthen * @param elem: Element to store at this node
852be9e038Ssthen * @param scope: Scopemask from server reply
862be9e038Ssthen * @param ttl: Element is valid up to this time. Absolute, seconds
872be9e038Ssthen * @return new addrnode or NULL on failure
882be9e038Ssthen */
892be9e038Ssthen static struct addrnode *
node_create(struct addrtree * tree,void * elem,addrlen_t scope,time_t ttl)902be9e038Ssthen node_create(struct addrtree *tree, void *elem, addrlen_t scope,
912be9e038Ssthen time_t ttl)
922be9e038Ssthen {
932be9e038Ssthen struct addrnode* node = (struct addrnode *)malloc( sizeof (*node) );
942be9e038Ssthen if (!node)
952be9e038Ssthen return NULL;
962be9e038Ssthen node->elem = elem;
972be9e038Ssthen tree->node_count++;
982be9e038Ssthen node->scope = scope;
992be9e038Ssthen node->ttl = ttl;
100*45872187Ssthen node->only_match_scope_zero = 0;
1012be9e038Ssthen node->edge[0] = NULL;
1022be9e038Ssthen node->edge[1] = NULL;
1032be9e038Ssthen node->parent_edge = NULL;
1042be9e038Ssthen node->next = NULL;
1052be9e038Ssthen node->prev = NULL;
1062be9e038Ssthen return node;
1072be9e038Ssthen }
1082be9e038Ssthen
1092be9e038Ssthen /** Size in bytes of node and parent edge
1102be9e038Ssthen * @param tree: tree the node lives in
1112be9e038Ssthen * @param n: node which size must be calculated
1122be9e038Ssthen * @return size in bytes.
1132be9e038Ssthen **/
1142be9e038Ssthen static inline size_t
node_size(const struct addrtree * tree,const struct addrnode * n)1152be9e038Ssthen node_size(const struct addrtree *tree, const struct addrnode *n)
1162be9e038Ssthen {
1172be9e038Ssthen return sizeof *n + sizeof *n->parent_edge + n->parent_edge->len +
1182be9e038Ssthen (n->elem?tree->sizefunc(n->elem):0);
1192be9e038Ssthen }
1202be9e038Ssthen
1212be9e038Ssthen struct addrtree *
addrtree_create(addrlen_t max_depth,void (* delfunc)(void *,void *),size_t (* sizefunc)(void *),void * env,uint32_t max_node_count)1222be9e038Ssthen addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *),
1233150e5f6Ssthen size_t (*sizefunc)(void *), void *env, uint32_t max_node_count)
1242be9e038Ssthen {
1252be9e038Ssthen struct addrtree *tree;
1262be9e038Ssthen log_assert(delfunc != NULL);
1272be9e038Ssthen log_assert(sizefunc != NULL);
1282be9e038Ssthen tree = (struct addrtree *)calloc(1, sizeof(*tree));
1292be9e038Ssthen if (!tree)
1302be9e038Ssthen return NULL;
1312be9e038Ssthen tree->root = node_create(tree, NULL, 0, 0);
1322be9e038Ssthen if (!tree->root) {
1332be9e038Ssthen free(tree);
1342be9e038Ssthen return NULL;
1352be9e038Ssthen }
1362be9e038Ssthen tree->size_bytes = sizeof *tree + sizeof *tree->root;
1372be9e038Ssthen tree->first = NULL;
1382be9e038Ssthen tree->last = NULL;
1392be9e038Ssthen tree->max_depth = max_depth;
1402be9e038Ssthen tree->delfunc = delfunc;
1412be9e038Ssthen tree->sizefunc = sizefunc;
1422be9e038Ssthen tree->env = env;
1432be9e038Ssthen tree->node_count = 0;
1442be9e038Ssthen tree->max_node_count = max_node_count;
1452be9e038Ssthen return tree;
1462be9e038Ssthen }
1472be9e038Ssthen
1482be9e038Ssthen /**
1492be9e038Ssthen * Scrub a node clean of elem
1502be9e038Ssthen * @param tree: tree the node lives in.
1512be9e038Ssthen * @param node: node to be cleaned.
1522be9e038Ssthen */
1532be9e038Ssthen static void
clean_node(struct addrtree * tree,struct addrnode * node)1542be9e038Ssthen clean_node(struct addrtree *tree, struct addrnode *node)
1552be9e038Ssthen {
1562be9e038Ssthen if (!node->elem) return;
1572be9e038Ssthen tree->size_bytes -= tree->sizefunc(node->elem);
1582be9e038Ssthen tree->delfunc(tree->env, node->elem);
159*45872187Ssthen node->only_match_scope_zero = 0;
1602be9e038Ssthen node->elem = NULL;
1612be9e038Ssthen }
1622be9e038Ssthen
1632be9e038Ssthen /** Remove specified node from LRU list */
1642be9e038Ssthen static void
lru_pop(struct addrtree * tree,struct addrnode * node)1652be9e038Ssthen lru_pop(struct addrtree *tree, struct addrnode *node)
1662be9e038Ssthen {
1672be9e038Ssthen if (node == tree->first) {
1682be9e038Ssthen if (!node->next) { /* it is the last as well */
1692be9e038Ssthen tree->first = NULL;
1702be9e038Ssthen tree->last = NULL;
1712be9e038Ssthen } else {
1722be9e038Ssthen tree->first = node->next;
1732be9e038Ssthen tree->first->prev = NULL;
1742be9e038Ssthen }
1752be9e038Ssthen } else if (node == tree->last) { /* but not the first */
1762be9e038Ssthen tree->last = node->prev;
1772be9e038Ssthen tree->last->next = NULL;
1782be9e038Ssthen } else {
1792be9e038Ssthen node->prev->next = node->next;
1802be9e038Ssthen node->next->prev = node->prev;
1812be9e038Ssthen }
1822be9e038Ssthen }
1832be9e038Ssthen
1842be9e038Ssthen /** Add node to LRU list as most recently used. */
1852be9e038Ssthen static void
lru_push(struct addrtree * tree,struct addrnode * node)1862be9e038Ssthen lru_push(struct addrtree *tree, struct addrnode *node)
1872be9e038Ssthen {
1882be9e038Ssthen if (!tree->first) {
1892be9e038Ssthen tree->first = node;
1902be9e038Ssthen node->prev = NULL;
1912be9e038Ssthen } else {
1922be9e038Ssthen tree->last->next = node;
1932be9e038Ssthen node->prev = tree->last;
1942be9e038Ssthen }
1952be9e038Ssthen tree->last = node;
1962be9e038Ssthen node->next = NULL;
1972be9e038Ssthen }
1982be9e038Ssthen
1992be9e038Ssthen /** Move node to the end of LRU list */
2002be9e038Ssthen static void
lru_update(struct addrtree * tree,struct addrnode * node)2012be9e038Ssthen lru_update(struct addrtree *tree, struct addrnode *node)
2022be9e038Ssthen {
2032be9e038Ssthen if (tree->root == node) return;
2042be9e038Ssthen lru_pop(tree, node);
2052be9e038Ssthen lru_push(tree, node);
2062be9e038Ssthen }
2072be9e038Ssthen
2082be9e038Ssthen /**
2092be9e038Ssthen * Purge a node from the tree. Node and parentedge are cleaned and
2102be9e038Ssthen * free'd.
2112be9e038Ssthen * @param tree: Tree the node lives in.
2122be9e038Ssthen * @param node: Node to be freed
2132be9e038Ssthen */
2142be9e038Ssthen static void
purge_node(struct addrtree * tree,struct addrnode * node)2152be9e038Ssthen purge_node(struct addrtree *tree, struct addrnode *node)
2162be9e038Ssthen {
2172be9e038Ssthen struct addredge *parent_edge, *child_edge = NULL;
2182be9e038Ssthen int index;
2192be9e038Ssthen int keep = node->edge[0] && node->edge[1];
2202be9e038Ssthen
2212be9e038Ssthen clean_node(tree, node);
2222be9e038Ssthen parent_edge = node->parent_edge;
2232be9e038Ssthen if (keep || !parent_edge) return;
2242be9e038Ssthen tree->node_count--;
2252be9e038Ssthen index = parent_edge->parent_index;
2262be9e038Ssthen child_edge = node->edge[!node->edge[0]];
2272be9e038Ssthen if (child_edge) {
2282be9e038Ssthen child_edge->parent_node = parent_edge->parent_node;
2292be9e038Ssthen child_edge->parent_index = index;
2302be9e038Ssthen }
2312be9e038Ssthen parent_edge->parent_node->edge[index] = child_edge;
2322be9e038Ssthen tree->size_bytes -= node_size(tree, node);
2332be9e038Ssthen free(parent_edge->str);
2342be9e038Ssthen free(parent_edge);
2352be9e038Ssthen lru_pop(tree, node);
2362be9e038Ssthen free(node);
2372be9e038Ssthen }
2382be9e038Ssthen
2392be9e038Ssthen /**
2402be9e038Ssthen * If a limit is set remove old nodes while above that limit.
2412be9e038Ssthen * @param tree: Tree to be cleaned up.
2422be9e038Ssthen */
2432be9e038Ssthen static void
lru_cleanup(struct addrtree * tree)2442be9e038Ssthen lru_cleanup(struct addrtree *tree)
2452be9e038Ssthen {
2462be9e038Ssthen struct addrnode *n, *p;
2472be9e038Ssthen int children;
2482be9e038Ssthen if (tree->max_node_count == 0) return;
2492be9e038Ssthen while (tree->node_count > tree->max_node_count) {
2502be9e038Ssthen n = tree->first;
2512be9e038Ssthen if (!n) break;
2522be9e038Ssthen children = (n->edge[0] != NULL) + (n->edge[1] != NULL);
2532be9e038Ssthen /** Don't remove this node, it is either the root or we can't
2542be9e038Ssthen * do without it because it has 2 children */
2552be9e038Ssthen if (children == 2 || !n->parent_edge) {
2562be9e038Ssthen lru_update(tree, n);
2572be9e038Ssthen continue;
2582be9e038Ssthen }
2592be9e038Ssthen p = n->parent_edge->parent_node;
2602be9e038Ssthen purge_node(tree, n);
2612be9e038Ssthen /** Since we removed n, n's parent p is eligible for deletion
2622be9e038Ssthen * if it is not the root node, caries no data and has only 1
2632be9e038Ssthen * child */
2642be9e038Ssthen children = (p->edge[0] != NULL) + (p->edge[1] != NULL);
2652be9e038Ssthen if (!p->elem && children == 1 && p->parent_edge) {
2662be9e038Ssthen purge_node(tree, p);
2672be9e038Ssthen }
2682be9e038Ssthen }
2692be9e038Ssthen }
2702be9e038Ssthen
2712be9e038Ssthen inline size_t
addrtree_size(const struct addrtree * tree)2722be9e038Ssthen addrtree_size(const struct addrtree *tree)
2732be9e038Ssthen {
2742be9e038Ssthen return tree?tree->size_bytes:0;
2752be9e038Ssthen }
2762be9e038Ssthen
addrtree_delete(struct addrtree * tree)2772be9e038Ssthen void addrtree_delete(struct addrtree *tree)
2782be9e038Ssthen {
2792be9e038Ssthen struct addrnode *n;
2802be9e038Ssthen if (!tree) return;
2812be9e038Ssthen clean_node(tree, tree->root);
2822be9e038Ssthen free(tree->root);
2832be9e038Ssthen tree->size_bytes -= sizeof(struct addrnode);
2842be9e038Ssthen while ((n = tree->first)) {
2852be9e038Ssthen tree->first = n->next;
2862be9e038Ssthen clean_node(tree, n);
2872be9e038Ssthen tree->size_bytes -= node_size(tree, n);
2882be9e038Ssthen free(n->parent_edge->str);
2892be9e038Ssthen free(n->parent_edge);
2902be9e038Ssthen free(n);
2912be9e038Ssthen }
2922be9e038Ssthen log_assert(sizeof *tree == addrtree_size(tree));
2932be9e038Ssthen free(tree);
2942be9e038Ssthen }
2952be9e038Ssthen
2962be9e038Ssthen /**
2972be9e038Ssthen * Get N'th bit from address
2982be9e038Ssthen * @param addr: address to inspect
2992be9e038Ssthen * @param addrlen: length of addr in bits
3002be9e038Ssthen * @param n: index of bit to test. Must be in range [0, addrlen)
3012be9e038Ssthen * @return 0 or 1
3022be9e038Ssthen */
3032be9e038Ssthen static int
getbit(const addrkey_t * addr,addrlen_t addrlen,addrlen_t n)3042be9e038Ssthen getbit(const addrkey_t *addr, addrlen_t addrlen, addrlen_t n)
3052be9e038Ssthen {
3062be9e038Ssthen log_assert(addrlen > n);
3072be9e038Ssthen (void)addrlen;
3082be9e038Ssthen return (int)(addr[n/KEYWIDTH]>>((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
3092be9e038Ssthen }
3102be9e038Ssthen
3112be9e038Ssthen /**
3122be9e038Ssthen * Test for equality on N'th bit.
3132be9e038Ssthen * @return 0 for equal, 1 otherwise
3142be9e038Ssthen */
3152be9e038Ssthen static inline int
cmpbit(const addrkey_t * key1,const addrkey_t * key2,addrlen_t n)3162be9e038Ssthen cmpbit(const addrkey_t *key1, const addrkey_t *key2, addrlen_t n)
3172be9e038Ssthen {
3182be9e038Ssthen addrkey_t c = key1[n/KEYWIDTH] ^ key2[n/KEYWIDTH];
3192be9e038Ssthen return (int)(c >> ((KEYWIDTH-1)-(n%KEYWIDTH))) & 1;
3202be9e038Ssthen }
3212be9e038Ssthen
3222be9e038Ssthen /**
3232be9e038Ssthen * Common number of bits in prefix.
3242be9e038Ssthen * @param s1: first prefix.
3252be9e038Ssthen * @param l1: length of s1 in bits.
3262be9e038Ssthen * @param s2: second prefix.
3272be9e038Ssthen * @param l2: length of s2 in bits.
3282be9e038Ssthen * @param skip: nr of bits already checked.
3292be9e038Ssthen * @return common number of bits.
3302be9e038Ssthen */
3312be9e038Ssthen static addrlen_t
bits_common(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)3322be9e038Ssthen bits_common(const addrkey_t *s1, addrlen_t l1,
3332be9e038Ssthen const addrkey_t *s2, addrlen_t l2, addrlen_t skip)
3342be9e038Ssthen {
3352be9e038Ssthen addrlen_t len, i;
3362be9e038Ssthen len = (l1 > l2) ? l2 : l1;
3372be9e038Ssthen log_assert(skip < len);
3382be9e038Ssthen for (i = skip; i < len; i++) {
3392be9e038Ssthen if (cmpbit(s1, s2, i)) return i;
3402be9e038Ssthen }
3412be9e038Ssthen return len;
3422be9e038Ssthen }
3432be9e038Ssthen
3442be9e038Ssthen /**
3452be9e038Ssthen * Tests if s1 is a substring of s2
3462be9e038Ssthen * @param s1: first prefix.
3472be9e038Ssthen * @param l1: length of s1 in bits.
3482be9e038Ssthen * @param s2: second prefix.
3492be9e038Ssthen * @param l2: length of s2 in bits.
3502be9e038Ssthen * @param skip: nr of bits already checked.
3512be9e038Ssthen * @return 1 for substring, 0 otherwise
3522be9e038Ssthen */
3532be9e038Ssthen static int
issub(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)3542be9e038Ssthen issub(const addrkey_t *s1, addrlen_t l1,
3552be9e038Ssthen const addrkey_t *s2, addrlen_t l2, addrlen_t skip)
3562be9e038Ssthen {
3572be9e038Ssthen return bits_common(s1, l1, s2, l2, skip) == l1;
3582be9e038Ssthen }
3592be9e038Ssthen
3602be9e038Ssthen 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)3612be9e038Ssthen addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
3622be9e038Ssthen addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
363*45872187Ssthen time_t now, int only_match_scope_zero)
3642be9e038Ssthen {
3652be9e038Ssthen struct addrnode *newnode, *node;
3662be9e038Ssthen struct addredge *edge;
3672be9e038Ssthen int index;
3682be9e038Ssthen addrlen_t common, depth;
3692be9e038Ssthen
3702be9e038Ssthen node = tree->root;
3712be9e038Ssthen log_assert(node != NULL);
3722be9e038Ssthen
3732be9e038Ssthen /* Protect our cache against too much fine-grained data */
3742be9e038Ssthen if (tree->max_depth < scope) scope = tree->max_depth;
3752be9e038Ssthen /* Server answer was less specific than question */
3762be9e038Ssthen if (scope < sourcemask) sourcemask = scope;
3772be9e038Ssthen
3782be9e038Ssthen depth = 0;
3792be9e038Ssthen while (1) {
3802be9e038Ssthen log_assert(depth <= sourcemask);
3812be9e038Ssthen /* Case 1: update existing node */
3822be9e038Ssthen if (depth == sourcemask) {
3832be9e038Ssthen /* update this node's scope and data */
3842be9e038Ssthen clean_node(tree, node);
3852be9e038Ssthen node->ttl = ttl;
386*45872187Ssthen node->only_match_scope_zero = only_match_scope_zero;
3872be9e038Ssthen node->elem = elem;
3882be9e038Ssthen node->scope = scope;
3892be9e038Ssthen tree->size_bytes += tree->sizefunc(elem);
3902be9e038Ssthen return;
3912be9e038Ssthen }
3922be9e038Ssthen index = getbit(addr, sourcemask, depth);
3932be9e038Ssthen /* Get an edge to an unexpired node */
3942be9e038Ssthen edge = node->edge[index];
3952be9e038Ssthen while (edge) {
3962be9e038Ssthen /* Purge all expired nodes on path */
3972be9e038Ssthen if (!edge->node->elem || edge->node->ttl >= now)
3982be9e038Ssthen break;
3992be9e038Ssthen purge_node(tree, edge->node);
4002be9e038Ssthen edge = node->edge[index];
4012be9e038Ssthen }
4022be9e038Ssthen /* Case 2: New leafnode */
4032be9e038Ssthen if (!edge) {
4042be9e038Ssthen newnode = node_create(tree, elem, scope, ttl);
4052be9e038Ssthen if (!newnode) return;
4062be9e038Ssthen if (!edge_create(newnode, addr, sourcemask, node,
4072be9e038Ssthen index)) {
4082be9e038Ssthen clean_node(tree, newnode);
4092be9e038Ssthen tree->node_count--;
4102be9e038Ssthen free(newnode);
4112be9e038Ssthen return;
4122be9e038Ssthen }
4132be9e038Ssthen tree->size_bytes += node_size(tree, newnode);
4142be9e038Ssthen lru_push(tree, newnode);
4152be9e038Ssthen lru_cleanup(tree);
4162be9e038Ssthen return;
4172be9e038Ssthen }
4182be9e038Ssthen /* Case 3: Traverse edge */
4192be9e038Ssthen common = bits_common(edge->str, edge->len, addr, sourcemask,
4202be9e038Ssthen depth);
4212be9e038Ssthen if (common == edge->len) {
4222be9e038Ssthen /* We update the scope of intermediate nodes. Apparently
4232be9e038Ssthen * the * authority changed its mind. If we would not do
4242be9e038Ssthen * this we might not be able to reach our new node. */
4252be9e038Ssthen node->scope = scope;
4262be9e038Ssthen depth = edge->len;
4272be9e038Ssthen node = edge->node;
4282be9e038Ssthen continue;
4292be9e038Ssthen }
4302be9e038Ssthen /* Case 4: split. */
4312be9e038Ssthen if (!(newnode = node_create(tree, NULL, 0, 0)))
4322be9e038Ssthen return;
4332be9e038Ssthen node->edge[index] = NULL;
4342be9e038Ssthen if (!edge_create(newnode, addr, common, node, index)) {
4352be9e038Ssthen node->edge[index] = edge;
4362be9e038Ssthen clean_node(tree, newnode);
4372be9e038Ssthen tree->node_count--;
4382be9e038Ssthen free(newnode);
4392be9e038Ssthen return;
4402be9e038Ssthen }
4412be9e038Ssthen lru_push(tree, newnode);
4422be9e038Ssthen /* connect existing child to our new node */
4432be9e038Ssthen index = getbit(edge->str, edge->len, common);
4442be9e038Ssthen newnode->edge[index] = edge;
4452be9e038Ssthen edge->parent_node = newnode;
4462be9e038Ssthen edge->parent_index = (int)index;
4472be9e038Ssthen
4482be9e038Ssthen if (common == sourcemask) {
4492be9e038Ssthen /* Data is stored in the node */
4502be9e038Ssthen newnode->elem = elem;
4512be9e038Ssthen newnode->scope = scope;
4522be9e038Ssthen newnode->ttl = ttl;
453*45872187Ssthen newnode->only_match_scope_zero = only_match_scope_zero;
4542be9e038Ssthen }
4552be9e038Ssthen
4562be9e038Ssthen tree->size_bytes += node_size(tree, newnode);
4572be9e038Ssthen
4582be9e038Ssthen if (common != sourcemask) {
4592be9e038Ssthen /* Data is stored in other leafnode */
4602be9e038Ssthen node = newnode;
4612be9e038Ssthen newnode = node_create(tree, elem, scope, ttl);
4622be9e038Ssthen if (!edge_create(newnode, addr, sourcemask, node,
4632be9e038Ssthen index^1)) {
4642be9e038Ssthen clean_node(tree, newnode);
4652be9e038Ssthen tree->node_count--;
4662be9e038Ssthen free(newnode);
4672be9e038Ssthen return;
4682be9e038Ssthen }
4692be9e038Ssthen tree->size_bytes += node_size(tree, newnode);
4702be9e038Ssthen lru_push(tree, newnode);
4712be9e038Ssthen }
4722be9e038Ssthen lru_cleanup(tree);
4732be9e038Ssthen return;
4742be9e038Ssthen }
4752be9e038Ssthen }
4762be9e038Ssthen
4772be9e038Ssthen struct addrnode *
addrtree_find(struct addrtree * tree,const addrkey_t * addr,addrlen_t sourcemask,time_t now)4782be9e038Ssthen addrtree_find(struct addrtree *tree, const addrkey_t *addr,
4792be9e038Ssthen addrlen_t sourcemask, time_t now)
4802be9e038Ssthen {
4812be9e038Ssthen struct addrnode *node = tree->root;
4822be9e038Ssthen struct addredge *edge = NULL;
4832be9e038Ssthen addrlen_t depth = 0;
4842be9e038Ssthen
4852be9e038Ssthen log_assert(node != NULL);
4862be9e038Ssthen while (1) {
4872be9e038Ssthen /* Current node more specific then question. */
4882be9e038Ssthen log_assert(depth <= sourcemask);
4892be9e038Ssthen /* does this node have data? if yes, see if we have a match */
490*45872187Ssthen if (node->elem && node->ttl >= now &&
491*45872187Ssthen !(sourcemask != 0 && node->only_match_scope_zero)) {
4922be9e038Ssthen /* saved at wrong depth */;
493938a3a5eSflorian log_assert(node->scope >= depth);
4942be9e038Ssthen if (depth == node->scope ||
4952be9e038Ssthen (node->scope > sourcemask &&
4962be9e038Ssthen depth == sourcemask)) {
4972be9e038Ssthen /* Authority indicates it does not have a more
4982be9e038Ssthen * precise answer or we cannot ask a more
4992be9e038Ssthen * specific question. */
5002be9e038Ssthen lru_update(tree, node);
5012be9e038Ssthen return node;
5022be9e038Ssthen }
5032be9e038Ssthen }
5042be9e038Ssthen /* This is our final depth, but we haven't found an answer. */
5052be9e038Ssthen if (depth == sourcemask)
5062be9e038Ssthen return NULL;
5072be9e038Ssthen /* Find an edge to traverse */
5082be9e038Ssthen edge = node->edge[getbit(addr, sourcemask, depth)];
5092be9e038Ssthen if (!edge || !edge->node)
5102be9e038Ssthen return NULL;
5112be9e038Ssthen if (edge->len > sourcemask )
5122be9e038Ssthen return NULL;
5132be9e038Ssthen if (!issub(edge->str, edge->len, addr, sourcemask, depth))
5142be9e038Ssthen return NULL;
5152be9e038Ssthen log_assert(depth < edge->len);
5162be9e038Ssthen depth = edge->len;
5172be9e038Ssthen node = edge->node;
5182be9e038Ssthen }
5192be9e038Ssthen }
5202be9e038Ssthen
5212be9e038Ssthen /** Wrappers for static functions to unit test */
unittest_wrapper_addrtree_cmpbit(const addrkey_t * key1,const addrkey_t * key2,addrlen_t n)5222be9e038Ssthen int unittest_wrapper_addrtree_cmpbit(const addrkey_t *key1,
5232be9e038Ssthen const addrkey_t *key2, addrlen_t n) {
5242be9e038Ssthen return cmpbit(key1, key2, n);
5252be9e038Ssthen }
unittest_wrapper_addrtree_bits_common(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)5262be9e038Ssthen addrlen_t unittest_wrapper_addrtree_bits_common(const addrkey_t *s1,
5272be9e038Ssthen addrlen_t l1, const addrkey_t *s2, addrlen_t l2, addrlen_t skip) {
5282be9e038Ssthen return bits_common(s1, l1, s2, l2, skip);
5292be9e038Ssthen }
unittest_wrapper_addrtree_getbit(const addrkey_t * addr,addrlen_t addrlen,addrlen_t n)5302be9e038Ssthen int unittest_wrapper_addrtree_getbit(const addrkey_t *addr,
5312be9e038Ssthen addrlen_t addrlen, addrlen_t n) {
5322be9e038Ssthen return getbit(addr, addrlen, n);
5332be9e038Ssthen }
unittest_wrapper_addrtree_issub(const addrkey_t * s1,addrlen_t l1,const addrkey_t * s2,addrlen_t l2,addrlen_t skip)5342be9e038Ssthen int unittest_wrapper_addrtree_issub(const addrkey_t *s1, addrlen_t l1,
5352be9e038Ssthen const addrkey_t *s2, addrlen_t l2, addrlen_t skip) {
5362be9e038Ssthen return issub(s1, l1, s2, l2, skip);
5372be9e038Ssthen }
538