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 * 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 * 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; 10065b390aaSDag-Erling Smørgrav node->edge[0] = NULL; 10165b390aaSDag-Erling Smørgrav node->edge[1] = NULL; 10265b390aaSDag-Erling Smørgrav node->parent_edge = NULL; 10365b390aaSDag-Erling Smørgrav node->next = NULL; 10465b390aaSDag-Erling Smørgrav node->prev = NULL; 10565b390aaSDag-Erling Smørgrav return node; 10665b390aaSDag-Erling Smørgrav } 10765b390aaSDag-Erling Smørgrav 10865b390aaSDag-Erling Smørgrav /** Size in bytes of node and parent edge 10965b390aaSDag-Erling Smørgrav * @param tree: tree the node lives in 11065b390aaSDag-Erling Smørgrav * @param n: node which size must be calculated 11165b390aaSDag-Erling Smørgrav * @return size in bytes. 11265b390aaSDag-Erling Smørgrav **/ 11365b390aaSDag-Erling Smørgrav static inline size_t 11465b390aaSDag-Erling Smørgrav node_size(const struct addrtree *tree, const struct addrnode *n) 11565b390aaSDag-Erling Smørgrav { 11665b390aaSDag-Erling Smørgrav return sizeof *n + sizeof *n->parent_edge + n->parent_edge->len + 11765b390aaSDag-Erling Smørgrav (n->elem?tree->sizefunc(n->elem):0); 11865b390aaSDag-Erling Smørgrav } 11965b390aaSDag-Erling Smørgrav 12065b390aaSDag-Erling Smørgrav struct addrtree * 12165b390aaSDag-Erling Smørgrav addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *), 12265b390aaSDag-Erling Smørgrav size_t (*sizefunc)(void *), void *env, unsigned int max_node_count) 12365b390aaSDag-Erling Smørgrav { 12465b390aaSDag-Erling Smørgrav struct addrtree *tree; 12565b390aaSDag-Erling Smørgrav log_assert(delfunc != NULL); 12665b390aaSDag-Erling Smørgrav log_assert(sizefunc != NULL); 12765b390aaSDag-Erling Smørgrav tree = (struct addrtree *)calloc(1, sizeof(*tree)); 12865b390aaSDag-Erling Smørgrav if (!tree) 12965b390aaSDag-Erling Smørgrav return NULL; 13065b390aaSDag-Erling Smørgrav tree->root = node_create(tree, NULL, 0, 0); 13165b390aaSDag-Erling Smørgrav if (!tree->root) { 13265b390aaSDag-Erling Smørgrav free(tree); 13365b390aaSDag-Erling Smørgrav return NULL; 13465b390aaSDag-Erling Smørgrav } 13565b390aaSDag-Erling Smørgrav tree->size_bytes = sizeof *tree + sizeof *tree->root; 13665b390aaSDag-Erling Smørgrav tree->first = NULL; 13765b390aaSDag-Erling Smørgrav tree->last = NULL; 13865b390aaSDag-Erling Smørgrav tree->max_depth = max_depth; 13965b390aaSDag-Erling Smørgrav tree->delfunc = delfunc; 14065b390aaSDag-Erling Smørgrav tree->sizefunc = sizefunc; 14165b390aaSDag-Erling Smørgrav tree->env = env; 14265b390aaSDag-Erling Smørgrav tree->node_count = 0; 14365b390aaSDag-Erling Smørgrav tree->max_node_count = max_node_count; 14465b390aaSDag-Erling Smørgrav return tree; 14565b390aaSDag-Erling Smørgrav } 14665b390aaSDag-Erling Smørgrav 14765b390aaSDag-Erling Smørgrav /** 14865b390aaSDag-Erling Smørgrav * Scrub a node clean of elem 14965b390aaSDag-Erling Smørgrav * @param tree: tree the node lives in. 15065b390aaSDag-Erling Smørgrav * @param node: node to be cleaned. 15165b390aaSDag-Erling Smørgrav */ 15265b390aaSDag-Erling Smørgrav static void 15365b390aaSDag-Erling Smørgrav clean_node(struct addrtree *tree, struct addrnode *node) 15465b390aaSDag-Erling Smørgrav { 15565b390aaSDag-Erling Smørgrav if (!node->elem) return; 15665b390aaSDag-Erling Smørgrav tree->size_bytes -= tree->sizefunc(node->elem); 15765b390aaSDag-Erling Smørgrav tree->delfunc(tree->env, node->elem); 15865b390aaSDag-Erling Smørgrav node->elem = NULL; 15965b390aaSDag-Erling Smørgrav } 16065b390aaSDag-Erling Smørgrav 16165b390aaSDag-Erling Smørgrav /** Remove specified node from LRU list */ 16265b390aaSDag-Erling Smørgrav static void 16365b390aaSDag-Erling Smørgrav lru_pop(struct addrtree *tree, struct addrnode *node) 16465b390aaSDag-Erling Smørgrav { 16565b390aaSDag-Erling Smørgrav if (node == tree->first) { 16665b390aaSDag-Erling Smørgrav if (!node->next) { /* it is the last as well */ 16765b390aaSDag-Erling Smørgrav tree->first = NULL; 16865b390aaSDag-Erling Smørgrav tree->last = NULL; 16965b390aaSDag-Erling Smørgrav } else { 17065b390aaSDag-Erling Smørgrav tree->first = node->next; 17165b390aaSDag-Erling Smørgrav tree->first->prev = NULL; 17265b390aaSDag-Erling Smørgrav } 17365b390aaSDag-Erling Smørgrav } else if (node == tree->last) { /* but not the first */ 17465b390aaSDag-Erling Smørgrav tree->last = node->prev; 17565b390aaSDag-Erling Smørgrav tree->last->next = NULL; 17665b390aaSDag-Erling Smørgrav } else { 17765b390aaSDag-Erling Smørgrav node->prev->next = node->next; 17865b390aaSDag-Erling Smørgrav node->next->prev = node->prev; 17965b390aaSDag-Erling Smørgrav } 18065b390aaSDag-Erling Smørgrav } 18165b390aaSDag-Erling Smørgrav 18265b390aaSDag-Erling Smørgrav /** Add node to LRU list as most recently used. */ 18365b390aaSDag-Erling Smørgrav static void 18465b390aaSDag-Erling Smørgrav lru_push(struct addrtree *tree, struct addrnode *node) 18565b390aaSDag-Erling Smørgrav { 18665b390aaSDag-Erling Smørgrav if (!tree->first) { 18765b390aaSDag-Erling Smørgrav tree->first = node; 18865b390aaSDag-Erling Smørgrav node->prev = NULL; 18965b390aaSDag-Erling Smørgrav } else { 19065b390aaSDag-Erling Smørgrav tree->last->next = node; 19165b390aaSDag-Erling Smørgrav node->prev = tree->last; 19265b390aaSDag-Erling Smørgrav } 19365b390aaSDag-Erling Smørgrav tree->last = node; 19465b390aaSDag-Erling Smørgrav node->next = NULL; 19565b390aaSDag-Erling Smørgrav } 19665b390aaSDag-Erling Smørgrav 19765b390aaSDag-Erling Smørgrav /** Move node to the end of LRU list */ 19865b390aaSDag-Erling Smørgrav static void 19965b390aaSDag-Erling Smørgrav lru_update(struct addrtree *tree, struct addrnode *node) 20065b390aaSDag-Erling Smørgrav { 20165b390aaSDag-Erling Smørgrav if (tree->root == node) return; 20265b390aaSDag-Erling Smørgrav lru_pop(tree, node); 20365b390aaSDag-Erling Smørgrav lru_push(tree, node); 20465b390aaSDag-Erling Smørgrav } 20565b390aaSDag-Erling Smørgrav 20665b390aaSDag-Erling Smørgrav /** 20765b390aaSDag-Erling Smørgrav * Purge a node from the tree. Node and parentedge are cleaned and 20865b390aaSDag-Erling Smørgrav * free'd. 20965b390aaSDag-Erling Smørgrav * @param tree: Tree the node lives in. 21065b390aaSDag-Erling Smørgrav * @param node: Node to be freed 21165b390aaSDag-Erling Smørgrav */ 21265b390aaSDag-Erling Smørgrav static void 21365b390aaSDag-Erling Smørgrav purge_node(struct addrtree *tree, struct addrnode *node) 21465b390aaSDag-Erling Smørgrav { 21565b390aaSDag-Erling Smørgrav struct addredge *parent_edge, *child_edge = NULL; 21665b390aaSDag-Erling Smørgrav int index; 21765b390aaSDag-Erling Smørgrav int keep = node->edge[0] && node->edge[1]; 21865b390aaSDag-Erling Smørgrav 21965b390aaSDag-Erling Smørgrav clean_node(tree, node); 22065b390aaSDag-Erling Smørgrav parent_edge = node->parent_edge; 22165b390aaSDag-Erling Smørgrav if (keep || !parent_edge) return; 22265b390aaSDag-Erling Smørgrav tree->node_count--; 22365b390aaSDag-Erling Smørgrav index = parent_edge->parent_index; 22465b390aaSDag-Erling Smørgrav child_edge = node->edge[!node->edge[0]]; 22565b390aaSDag-Erling Smørgrav if (child_edge) { 22665b390aaSDag-Erling Smørgrav child_edge->parent_node = parent_edge->parent_node; 22765b390aaSDag-Erling Smørgrav child_edge->parent_index = index; 22865b390aaSDag-Erling Smørgrav } 22965b390aaSDag-Erling Smørgrav parent_edge->parent_node->edge[index] = child_edge; 23065b390aaSDag-Erling Smørgrav tree->size_bytes -= node_size(tree, node); 23165b390aaSDag-Erling Smørgrav free(parent_edge->str); 23265b390aaSDag-Erling Smørgrav free(parent_edge); 23365b390aaSDag-Erling Smørgrav lru_pop(tree, node); 23465b390aaSDag-Erling Smørgrav free(node); 23565b390aaSDag-Erling Smørgrav } 23665b390aaSDag-Erling Smørgrav 23765b390aaSDag-Erling Smørgrav /** 23865b390aaSDag-Erling Smørgrav * If a limit is set remove old nodes while above that limit. 23965b390aaSDag-Erling Smørgrav * @param tree: Tree to be cleaned up. 24065b390aaSDag-Erling Smørgrav */ 24165b390aaSDag-Erling Smørgrav static void 24265b390aaSDag-Erling Smørgrav lru_cleanup(struct addrtree *tree) 24365b390aaSDag-Erling Smørgrav { 24465b390aaSDag-Erling Smørgrav struct addrnode *n, *p; 24565b390aaSDag-Erling Smørgrav int children; 24665b390aaSDag-Erling Smørgrav if (tree->max_node_count == 0) return; 24765b390aaSDag-Erling Smørgrav while (tree->node_count > tree->max_node_count) { 24865b390aaSDag-Erling Smørgrav n = tree->first; 24965b390aaSDag-Erling Smørgrav if (!n) break; 25065b390aaSDag-Erling Smørgrav children = (n->edge[0] != NULL) + (n->edge[1] != NULL); 25165b390aaSDag-Erling Smørgrav /** Don't remove this node, it is either the root or we can't 25265b390aaSDag-Erling Smørgrav * do without it because it has 2 children */ 25365b390aaSDag-Erling Smørgrav if (children == 2 || !n->parent_edge) { 25465b390aaSDag-Erling Smørgrav lru_update(tree, n); 25565b390aaSDag-Erling Smørgrav continue; 25665b390aaSDag-Erling Smørgrav } 25765b390aaSDag-Erling Smørgrav p = n->parent_edge->parent_node; 25865b390aaSDag-Erling Smørgrav purge_node(tree, n); 25965b390aaSDag-Erling Smørgrav /** Since we removed n, n's parent p is eligible for deletion 26065b390aaSDag-Erling Smørgrav * if it is not the root node, caries no data and has only 1 26165b390aaSDag-Erling Smørgrav * child */ 26265b390aaSDag-Erling Smørgrav children = (p->edge[0] != NULL) + (p->edge[1] != NULL); 26365b390aaSDag-Erling Smørgrav if (!p->elem && children == 1 && p->parent_edge) { 26465b390aaSDag-Erling Smørgrav purge_node(tree, p); 26565b390aaSDag-Erling Smørgrav } 26665b390aaSDag-Erling Smørgrav } 26765b390aaSDag-Erling Smørgrav } 26865b390aaSDag-Erling Smørgrav 26965b390aaSDag-Erling Smørgrav inline size_t 27065b390aaSDag-Erling Smørgrav addrtree_size(const struct addrtree *tree) 27165b390aaSDag-Erling Smørgrav { 27265b390aaSDag-Erling Smørgrav return tree?tree->size_bytes:0; 27365b390aaSDag-Erling Smørgrav } 27465b390aaSDag-Erling Smørgrav 27565b390aaSDag-Erling Smørgrav void addrtree_delete(struct addrtree *tree) 27665b390aaSDag-Erling Smørgrav { 27765b390aaSDag-Erling Smørgrav struct addrnode *n; 27865b390aaSDag-Erling Smørgrav if (!tree) return; 27965b390aaSDag-Erling Smørgrav clean_node(tree, tree->root); 28065b390aaSDag-Erling Smørgrav free(tree->root); 28165b390aaSDag-Erling Smørgrav tree->size_bytes -= sizeof(struct addrnode); 28265b390aaSDag-Erling Smørgrav while ((n = tree->first)) { 28365b390aaSDag-Erling Smørgrav tree->first = n->next; 28465b390aaSDag-Erling Smørgrav clean_node(tree, n); 28565b390aaSDag-Erling Smørgrav tree->size_bytes -= node_size(tree, n); 28665b390aaSDag-Erling Smørgrav free(n->parent_edge->str); 28765b390aaSDag-Erling Smørgrav free(n->parent_edge); 28865b390aaSDag-Erling Smørgrav free(n); 28965b390aaSDag-Erling Smørgrav } 29065b390aaSDag-Erling Smørgrav log_assert(sizeof *tree == addrtree_size(tree)); 29165b390aaSDag-Erling Smørgrav free(tree); 29265b390aaSDag-Erling Smørgrav } 29365b390aaSDag-Erling Smørgrav 29465b390aaSDag-Erling Smørgrav /** 29565b390aaSDag-Erling Smørgrav * Get N'th bit from address 29665b390aaSDag-Erling Smørgrav * @param addr: address to inspect 29765b390aaSDag-Erling Smørgrav * @param addrlen: length of addr in bits 29865b390aaSDag-Erling Smørgrav * @param n: index of bit to test. Must be in range [0, addrlen) 29965b390aaSDag-Erling Smørgrav * @return 0 or 1 30065b390aaSDag-Erling Smørgrav */ 30165b390aaSDag-Erling Smørgrav static int 30265b390aaSDag-Erling Smørgrav getbit(const addrkey_t *addr, addrlen_t addrlen, addrlen_t n) 30365b390aaSDag-Erling Smørgrav { 30465b390aaSDag-Erling Smørgrav log_assert(addrlen > n); 305*c7f4d7adSDag-Erling Smørgrav (void)addrlen; 30665b390aaSDag-Erling Smørgrav return (int)(addr[n/KEYWIDTH]>>((KEYWIDTH-1)-(n%KEYWIDTH))) & 1; 30765b390aaSDag-Erling Smørgrav } 30865b390aaSDag-Erling Smørgrav 30965b390aaSDag-Erling Smørgrav /** 31065b390aaSDag-Erling Smørgrav * Test for equality on N'th bit. 31165b390aaSDag-Erling Smørgrav * @return 0 for equal, 1 otherwise 31265b390aaSDag-Erling Smørgrav */ 31365b390aaSDag-Erling Smørgrav static inline int 31465b390aaSDag-Erling Smørgrav cmpbit(const addrkey_t *key1, const addrkey_t *key2, addrlen_t n) 31565b390aaSDag-Erling Smørgrav { 31665b390aaSDag-Erling Smørgrav addrkey_t c = key1[n/KEYWIDTH] ^ key2[n/KEYWIDTH]; 31765b390aaSDag-Erling Smørgrav return (int)(c >> ((KEYWIDTH-1)-(n%KEYWIDTH))) & 1; 31865b390aaSDag-Erling Smørgrav } 31965b390aaSDag-Erling Smørgrav 32065b390aaSDag-Erling Smørgrav /** 32165b390aaSDag-Erling Smørgrav * Common number of bits in prefix. 32265b390aaSDag-Erling Smørgrav * @param s1: first prefix. 32365b390aaSDag-Erling Smørgrav * @param l1: length of s1 in bits. 32465b390aaSDag-Erling Smørgrav * @param s2: second prefix. 32565b390aaSDag-Erling Smørgrav * @param l2: length of s2 in bits. 32665b390aaSDag-Erling Smørgrav * @param skip: nr of bits already checked. 32765b390aaSDag-Erling Smørgrav * @return common number of bits. 32865b390aaSDag-Erling Smørgrav */ 32965b390aaSDag-Erling Smørgrav static addrlen_t 33065b390aaSDag-Erling Smørgrav bits_common(const addrkey_t *s1, addrlen_t l1, 33165b390aaSDag-Erling Smørgrav const addrkey_t *s2, addrlen_t l2, addrlen_t skip) 33265b390aaSDag-Erling Smørgrav { 33365b390aaSDag-Erling Smørgrav addrlen_t len, i; 33465b390aaSDag-Erling Smørgrav len = (l1 > l2) ? l2 : l1; 33565b390aaSDag-Erling Smørgrav log_assert(skip < len); 33665b390aaSDag-Erling Smørgrav for (i = skip; i < len; i++) { 33765b390aaSDag-Erling Smørgrav if (cmpbit(s1, s2, i)) return i; 33865b390aaSDag-Erling Smørgrav } 33965b390aaSDag-Erling Smørgrav return len; 34065b390aaSDag-Erling Smørgrav } 34165b390aaSDag-Erling Smørgrav 34265b390aaSDag-Erling Smørgrav /** 34365b390aaSDag-Erling Smørgrav * Tests if s1 is a substring of s2 34465b390aaSDag-Erling Smørgrav * @param s1: first prefix. 34565b390aaSDag-Erling Smørgrav * @param l1: length of s1 in bits. 34665b390aaSDag-Erling Smørgrav * @param s2: second prefix. 34765b390aaSDag-Erling Smørgrav * @param l2: length of s2 in bits. 34865b390aaSDag-Erling Smørgrav * @param skip: nr of bits already checked. 34965b390aaSDag-Erling Smørgrav * @return 1 for substring, 0 otherwise 35065b390aaSDag-Erling Smørgrav */ 35165b390aaSDag-Erling Smørgrav static int 35265b390aaSDag-Erling Smørgrav issub(const addrkey_t *s1, addrlen_t l1, 35365b390aaSDag-Erling Smørgrav const addrkey_t *s2, addrlen_t l2, addrlen_t skip) 35465b390aaSDag-Erling Smørgrav { 35565b390aaSDag-Erling Smørgrav return bits_common(s1, l1, s2, l2, skip) == l1; 35665b390aaSDag-Erling Smørgrav } 35765b390aaSDag-Erling Smørgrav 35865b390aaSDag-Erling Smørgrav void 35965b390aaSDag-Erling Smørgrav addrtree_insert(struct addrtree *tree, const addrkey_t *addr, 36065b390aaSDag-Erling Smørgrav addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl, 36165b390aaSDag-Erling Smørgrav time_t now) 36265b390aaSDag-Erling Smørgrav { 36365b390aaSDag-Erling Smørgrav struct addrnode *newnode, *node; 36465b390aaSDag-Erling Smørgrav struct addredge *edge; 36565b390aaSDag-Erling Smørgrav int index; 36665b390aaSDag-Erling Smørgrav addrlen_t common, depth; 36765b390aaSDag-Erling Smørgrav 36865b390aaSDag-Erling Smørgrav node = tree->root; 36965b390aaSDag-Erling Smørgrav log_assert(node != NULL); 37065b390aaSDag-Erling Smørgrav 37165b390aaSDag-Erling Smørgrav /* Protect our cache against too much fine-grained data */ 37265b390aaSDag-Erling Smørgrav if (tree->max_depth < scope) scope = tree->max_depth; 37365b390aaSDag-Erling Smørgrav /* Server answer was less specific than question */ 37465b390aaSDag-Erling Smørgrav if (scope < sourcemask) sourcemask = scope; 37565b390aaSDag-Erling Smørgrav 37665b390aaSDag-Erling Smørgrav depth = 0; 37765b390aaSDag-Erling Smørgrav while (1) { 37865b390aaSDag-Erling Smørgrav log_assert(depth <= sourcemask); 37965b390aaSDag-Erling Smørgrav /* Case 1: update existing node */ 38065b390aaSDag-Erling Smørgrav if (depth == sourcemask) { 38165b390aaSDag-Erling Smørgrav /* update this node's scope and data */ 38265b390aaSDag-Erling Smørgrav clean_node(tree, node); 38365b390aaSDag-Erling Smørgrav node->ttl = ttl; 38465b390aaSDag-Erling Smørgrav node->elem = elem; 38565b390aaSDag-Erling Smørgrav node->scope = scope; 38665b390aaSDag-Erling Smørgrav tree->size_bytes += tree->sizefunc(elem); 38765b390aaSDag-Erling Smørgrav return; 38865b390aaSDag-Erling Smørgrav } 38965b390aaSDag-Erling Smørgrav index = getbit(addr, sourcemask, depth); 39065b390aaSDag-Erling Smørgrav /* Get an edge to an unexpired node */ 39165b390aaSDag-Erling Smørgrav edge = node->edge[index]; 39265b390aaSDag-Erling Smørgrav while (edge) { 39365b390aaSDag-Erling Smørgrav /* Purge all expired nodes on path */ 39465b390aaSDag-Erling Smørgrav if (!edge->node->elem || edge->node->ttl >= now) 39565b390aaSDag-Erling Smørgrav break; 39665b390aaSDag-Erling Smørgrav purge_node(tree, edge->node); 39765b390aaSDag-Erling Smørgrav edge = node->edge[index]; 39865b390aaSDag-Erling Smørgrav } 39965b390aaSDag-Erling Smørgrav /* Case 2: New leafnode */ 40065b390aaSDag-Erling Smørgrav if (!edge) { 40165b390aaSDag-Erling Smørgrav newnode = node_create(tree, elem, scope, ttl); 40265b390aaSDag-Erling Smørgrav if (!newnode) return; 40365b390aaSDag-Erling Smørgrav if (!edge_create(newnode, addr, sourcemask, node, 40465b390aaSDag-Erling Smørgrav index)) { 40565b390aaSDag-Erling Smørgrav clean_node(tree, newnode); 40665b390aaSDag-Erling Smørgrav tree->node_count--; 40765b390aaSDag-Erling Smørgrav free(newnode); 40865b390aaSDag-Erling Smørgrav return; 40965b390aaSDag-Erling Smørgrav } 41065b390aaSDag-Erling Smørgrav tree->size_bytes += node_size(tree, newnode); 41165b390aaSDag-Erling Smørgrav lru_push(tree, newnode); 41265b390aaSDag-Erling Smørgrav lru_cleanup(tree); 41365b390aaSDag-Erling Smørgrav return; 41465b390aaSDag-Erling Smørgrav } 41565b390aaSDag-Erling Smørgrav /* Case 3: Traverse edge */ 41665b390aaSDag-Erling Smørgrav common = bits_common(edge->str, edge->len, addr, sourcemask, 41765b390aaSDag-Erling Smørgrav depth); 41865b390aaSDag-Erling Smørgrav if (common == edge->len) { 41965b390aaSDag-Erling Smørgrav /* We update the scope of intermediate nodes. Apparently 42065b390aaSDag-Erling Smørgrav * the * authority changed its mind. If we would not do 42165b390aaSDag-Erling Smørgrav * this we might not be able to reach our new node. */ 42265b390aaSDag-Erling Smørgrav node->scope = scope; 42365b390aaSDag-Erling Smørgrav depth = edge->len; 42465b390aaSDag-Erling Smørgrav node = edge->node; 42565b390aaSDag-Erling Smørgrav continue; 42665b390aaSDag-Erling Smørgrav } 42765b390aaSDag-Erling Smørgrav /* Case 4: split. */ 42865b390aaSDag-Erling Smørgrav if (!(newnode = node_create(tree, NULL, 0, 0))) 42965b390aaSDag-Erling Smørgrav return; 43065b390aaSDag-Erling Smørgrav node->edge[index] = NULL; 43165b390aaSDag-Erling Smørgrav if (!edge_create(newnode, addr, common, node, index)) { 43265b390aaSDag-Erling Smørgrav node->edge[index] = edge; 43365b390aaSDag-Erling Smørgrav clean_node(tree, newnode); 43465b390aaSDag-Erling Smørgrav tree->node_count--; 43565b390aaSDag-Erling Smørgrav free(newnode); 43665b390aaSDag-Erling Smørgrav return; 43765b390aaSDag-Erling Smørgrav } 43865b390aaSDag-Erling Smørgrav lru_push(tree, newnode); 43965b390aaSDag-Erling Smørgrav /* connect existing child to our new node */ 44065b390aaSDag-Erling Smørgrav index = getbit(edge->str, edge->len, common); 44165b390aaSDag-Erling Smørgrav newnode->edge[index] = edge; 44265b390aaSDag-Erling Smørgrav edge->parent_node = newnode; 44365b390aaSDag-Erling Smørgrav edge->parent_index = (int)index; 44465b390aaSDag-Erling Smørgrav 44565b390aaSDag-Erling Smørgrav if (common == sourcemask) { 44665b390aaSDag-Erling Smørgrav /* Data is stored in the node */ 44765b390aaSDag-Erling Smørgrav newnode->elem = elem; 44865b390aaSDag-Erling Smørgrav newnode->scope = scope; 44965b390aaSDag-Erling Smørgrav newnode->ttl = ttl; 45065b390aaSDag-Erling Smørgrav } 45165b390aaSDag-Erling Smørgrav 45265b390aaSDag-Erling Smørgrav tree->size_bytes += node_size(tree, newnode); 45365b390aaSDag-Erling Smørgrav 45465b390aaSDag-Erling Smørgrav if (common != sourcemask) { 45565b390aaSDag-Erling Smørgrav /* Data is stored in other leafnode */ 45665b390aaSDag-Erling Smørgrav node = newnode; 45765b390aaSDag-Erling Smørgrav newnode = node_create(tree, elem, scope, ttl); 45865b390aaSDag-Erling Smørgrav if (!edge_create(newnode, addr, sourcemask, node, 45965b390aaSDag-Erling Smørgrav index^1)) { 46065b390aaSDag-Erling Smørgrav clean_node(tree, newnode); 46165b390aaSDag-Erling Smørgrav tree->node_count--; 46265b390aaSDag-Erling Smørgrav free(newnode); 46365b390aaSDag-Erling Smørgrav return; 46465b390aaSDag-Erling Smørgrav } 46565b390aaSDag-Erling Smørgrav tree->size_bytes += node_size(tree, newnode); 46665b390aaSDag-Erling Smørgrav lru_push(tree, newnode); 46765b390aaSDag-Erling Smørgrav } 46865b390aaSDag-Erling Smørgrav lru_cleanup(tree); 46965b390aaSDag-Erling Smørgrav return; 47065b390aaSDag-Erling Smørgrav } 47165b390aaSDag-Erling Smørgrav } 47265b390aaSDag-Erling Smørgrav 47365b390aaSDag-Erling Smørgrav struct addrnode * 47465b390aaSDag-Erling Smørgrav addrtree_find(struct addrtree *tree, const addrkey_t *addr, 47565b390aaSDag-Erling Smørgrav addrlen_t sourcemask, time_t now) 47665b390aaSDag-Erling Smørgrav { 47765b390aaSDag-Erling Smørgrav struct addrnode *node = tree->root; 47865b390aaSDag-Erling Smørgrav struct addredge *edge = NULL; 47965b390aaSDag-Erling Smørgrav addrlen_t depth = 0; 48065b390aaSDag-Erling Smørgrav 48165b390aaSDag-Erling Smørgrav log_assert(node != NULL); 48265b390aaSDag-Erling Smørgrav while (1) { 48365b390aaSDag-Erling Smørgrav /* Current node more specific then question. */ 48465b390aaSDag-Erling Smørgrav log_assert(depth <= sourcemask); 48565b390aaSDag-Erling Smørgrav /* does this node have data? if yes, see if we have a match */ 48665b390aaSDag-Erling Smørgrav if (node->elem && node->ttl >= now) { 48765b390aaSDag-Erling Smørgrav /* saved at wrong depth */; 48865b390aaSDag-Erling Smørgrav log_assert(node->scope >= depth) 48965b390aaSDag-Erling Smørgrav if (depth == node->scope || 49065b390aaSDag-Erling Smørgrav (node->scope > sourcemask && 49165b390aaSDag-Erling Smørgrav depth == sourcemask)) { 49265b390aaSDag-Erling Smørgrav /* Authority indicates it does not have a more 49365b390aaSDag-Erling Smørgrav * precise answer or we cannot ask a more 49465b390aaSDag-Erling Smørgrav * specific question. */ 49565b390aaSDag-Erling Smørgrav lru_update(tree, node); 49665b390aaSDag-Erling Smørgrav return node; 49765b390aaSDag-Erling Smørgrav } 49865b390aaSDag-Erling Smørgrav } 49965b390aaSDag-Erling Smørgrav /* This is our final depth, but we haven't found an answer. */ 50065b390aaSDag-Erling Smørgrav if (depth == sourcemask) 50165b390aaSDag-Erling Smørgrav return NULL; 50265b390aaSDag-Erling Smørgrav /* Find an edge to traverse */ 50365b390aaSDag-Erling Smørgrav edge = node->edge[getbit(addr, sourcemask, depth)]; 50465b390aaSDag-Erling Smørgrav if (!edge || !edge->node) 50565b390aaSDag-Erling Smørgrav return NULL; 50665b390aaSDag-Erling Smørgrav if (edge->len > sourcemask ) 50765b390aaSDag-Erling Smørgrav return NULL; 50865b390aaSDag-Erling Smørgrav if (!issub(edge->str, edge->len, addr, sourcemask, depth)) 50965b390aaSDag-Erling Smørgrav return NULL; 51065b390aaSDag-Erling Smørgrav log_assert(depth < edge->len); 51165b390aaSDag-Erling Smørgrav depth = edge->len; 51265b390aaSDag-Erling Smørgrav node = edge->node; 51365b390aaSDag-Erling Smørgrav } 51465b390aaSDag-Erling Smørgrav } 51565b390aaSDag-Erling Smørgrav 51665b390aaSDag-Erling Smørgrav /** Wrappers for static functions to unit test */ 51765b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_cmpbit(const addrkey_t *key1, 51865b390aaSDag-Erling Smørgrav const addrkey_t *key2, addrlen_t n) { 51965b390aaSDag-Erling Smørgrav return cmpbit(key1, key2, n); 52065b390aaSDag-Erling Smørgrav } 52165b390aaSDag-Erling Smørgrav addrlen_t unittest_wrapper_addrtree_bits_common(const addrkey_t *s1, 52265b390aaSDag-Erling Smørgrav addrlen_t l1, const addrkey_t *s2, addrlen_t l2, addrlen_t skip) { 52365b390aaSDag-Erling Smørgrav return bits_common(s1, l1, s2, l2, skip); 52465b390aaSDag-Erling Smørgrav } 52565b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_getbit(const addrkey_t *addr, 52665b390aaSDag-Erling Smørgrav addrlen_t addrlen, addrlen_t n) { 52765b390aaSDag-Erling Smørgrav return getbit(addr, addrlen, n); 52865b390aaSDag-Erling Smørgrav } 52965b390aaSDag-Erling Smørgrav int unittest_wrapper_addrtree_issub(const addrkey_t *s1, addrlen_t l1, 53065b390aaSDag-Erling Smørgrav const addrkey_t *s2, addrlen_t l2, addrlen_t skip) { 53165b390aaSDag-Erling Smørgrav return issub(s1, l1, s2, l2, skip); 53265b390aaSDag-Erling Smørgrav } 533