1 | /*************************************** 2 | $Revision: 1.11 $ 3 | 4 | Radix tree (rx). rx_tree.c - functions to operate on trees 5 | (creation/deletion/finding). 6 | 7 | Status: NOT REVUED, TESTED, INCOMPLETE 8 | 9 | Design and implementation by: Marek Bukowy 10 | 11 | ******************/ /****************** 12 | Copyright (c) 1999 RIPE NCC 13 | 14 | All Rights Reserved 15 | 16 | Permission to use, copy, modify, and distribute this software and its 17 | documentation for any purpose and without fee is hereby granted, 18 | provided that the above copyright notice appear in all copies and that 19 | both that copyright notice and this permission notice appear in 20 | supporting documentation, and that the name of the author not be 21 | used in advertising or publicity pertaining to distribution of the 22 | software without specific, written prior permission. 23 | 24 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 25 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 26 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 27 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 28 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 29 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30 | ***************************************/ 31 | 32 | #include <erroutines.h> 33 | #include <iproutines.h> 34 | #include <memwrap.h> 35 | #include <stubs.h> 36 | 37 | /***************************************************************************/ 38 | 39 | #define RX_IMPL 40 | 41 | #include <rxroutines.h> 42 | /***************************************************************************/ 43 | 44 | 45 | /*+++++++++ 46 | go down the tree calling func on every node. 47 | (func takes the node pointer and the current level) 48 | 49 | the function is called recursively with level increased 50 | it stops recursing when no child nodes are found or maxlevel is reached. 51 | 52 | therefore the initial call must set level to 0. 53 | 54 | the nodecounter increments at every node, and is the return value 55 | of the function. So start with 0 to get the number of nodes traversed. 56 | 57 | ERROR HANDLING IS DIFFERENT HERE! 58 | Unlike other functions it is not the return value: 59 | The error code from the func function IF DEFINED (== not NULL ) goes 60 | to the variable pointed to by the last parameter. 61 | ++++++++++++*/ 62 | int 63 | rx_walk_tree(rx_node_t *node, 64 | er_ret_t (*func)(rx_node_t *node, int level, int nodecounter, 65 | void *userptr), 66 | rx_walk_mt walk_mode, 67 | // controls if glue nodes are counted 68 | // and if levels or prefix lenghts are checked 69 | int maxlevel, 70 | int level, 71 | int nodecounter, 72 | void *userptr, 73 | er_ret_t *err) 74 | { 75 | int i, link, skpglue=0; 76 | 77 | if( node == NULL ) die; // program error. we expect a valid, checked, node. 78 | 79 | // count the node appropriately: 80 | // if (not glue) or (it doesn't matter) 81 | 82 | if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) { 83 | level++; 84 | } else { /* nodeglue = 1 && walkmode&skpglue = 1 */ 85 | skpglue = 1; 86 | } 87 | 88 | // check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, 89 | // level otherwise 90 | 91 | if(walk_mode & RX_WALK_PRFLEN) { 92 | if(node->prefix.bits > maxlevel) { 93 | return nodecounter; 94 | } 95 | } 96 | else if( level > maxlevel ) { 97 | return nodecounter; 98 | } 99 | 100 | // didn't quit ?? OK, count it too... 101 | if( skpglue == 0 ) { 102 | nodecounter++; 103 | } 104 | 105 | if( func != NULL && skpglue == 0 ) { 106 | *err = func(node, level, nodecounter, userptr); 107 | 108 | // abort the walk on error 109 | if( *err != RX_OK ) { 110 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK, 111 | "walk_tree: func returned error %d, aborting", *err); 112 | return nodecounter; 113 | } 114 | } 115 | 116 | 117 | for(i=0; i<=1; i++) { 118 | 119 | // reverse the sense of the walk 120 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i; 121 | 122 | if( node->child_ptr[link] != NULL ) { 123 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode, 124 | maxlevel, level, 0, userptr, err); 125 | // abort the walk on error 126 | if( func != NULL && *err != RX_OK ) { 127 | break; 128 | } 129 | } 130 | } 131 | 132 | return nodecounter; 133 | } 134 | 135 | 136 | 137 | 138 | /***************************************************************************/ 139 | /*++++++++++++++ 140 | finds a tree matching the specified criteria(registry+space+family). 141 | 142 | MT-note: locks/unlocks forest (still to be done) 143 | 144 | Returns: RX_OK or RX_NOTREE if no such tree can be found. 145 | +++++++++++*/ 146 | 147 | er_ret_t 148 | RX_get_tree ( rx_tree_t **treeptr, /*+ answer goes here, please +*/ 149 | rx_regid_t reg_id, /*+ id of the registry +*/ 150 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/ 151 | rx_fam_t fam_id /*+ family of objects (route/inetnum) +*/ 152 | ) 153 | 154 | { 155 | GList *elem = g_list_first(rx_forest); 156 | rx_tree_t *trp; 157 | 158 | while( elem != NULL ) { 159 | trp = (rx_tree_t *) elem->data; 160 | 161 | if( trp->reg_id == reg_id 162 | && trp->space == spc_id && trp->family == fam_id) { 163 | /* copy the value to user's data */ 164 | *treeptr = trp; 165 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "tree found at %08x",trp); 166 | 167 | return RX_OK; 168 | } 169 | elem = g_list_next(elem); 170 | } 171 | 172 | *treeptr = NULL; // set no NOT FOUND 173 | return RX_NOTREE; 174 | } 175 | 176 | 177 | /***************************************************************************/ 178 | /*++++++ 179 | creates a (top) tree for the space, fills out sql table of trees 180 | generates a tablename for a tree (if NONE) 181 | updates LL of trees 182 | 183 | MT-note: locks/unlocks the forest (still to be done) 184 | 185 | ++++++++*/ 186 | er_ret_t 187 | RX_tree_cre ( 188 | rx_regid_t reg_id, /*+ id of the registry +*/ 189 | ip_space_t spc_id, /*+ space id, one of IPv4 IPv6. +*/ 190 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/ 191 | char *prefixstr, /*+ prefix the tree will cover (string) +*/ 192 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/ 193 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/ 194 | rx_tree_t **treestore /* store the tree pointer here */ 195 | ) 196 | 197 | { 198 | er_ret_t err; 199 | rx_tree_t *newtree; 200 | ip_prefix_t newpref; 201 | 202 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) { 203 | die; 204 | } 205 | 206 | RX_get_tree ( &newtree, reg_id, spc_id, fam_id); 207 | 208 | if ( newtree != NULL ) { 209 | // die; /* error RX_TRALEX == tree already exists */ 210 | return RX_TRALEX; 211 | } 212 | 213 | 214 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) { 215 | return err; // die 216 | } 217 | 218 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree); 219 | 220 | /* copy tree settings */ 221 | 222 | newtree -> reg_id = reg_id; 223 | newtree -> space = spc_id; 224 | newtree -> family = fam_id; 225 | newtree -> subtrees = subtrees; 226 | newtree -> mem_mode = mem_mode; 227 | 228 | /* set other tree values */ 229 | 230 | /* parent set to NULL because it's not a subtree */ 231 | newtree -> parent_tree = NULL; 232 | // PR_zeroprefix(& newtree -> prefix); 233 | newtree -> maxbits = IP_sizebits(spc_id); 234 | 235 | strcpy(newtree->data_table.val,""); 236 | strcpy(newtree->radix_table.val,""); 237 | strcpy(newtree->leaves_table.val,""); 238 | 239 | newtree->num_nodes = 0; 240 | 241 | newtree->top_ptr = NULL; 242 | newtree->top_key = SQ_NOKEY; 243 | 244 | newtree->prefix = newpref; 245 | 246 | TH_init_read_write_lock( &(newtree->rwlock)); 247 | 248 | *treestore = newtree; 249 | 250 | return RX_OK; 251 | } 252 | 253 | void RX_attach2forest(rx_tree_t *newtree) { 254 | /* put into LL of trees; handle alloc err ??? */ 255 | /* if threads are supposed to be reading already, 256 | set forest mutex; */ 257 | 258 | rx_forest = g_list_append (rx_forest, newtree); 259 | 260 | /* release forest mutex; */ 261 | 262 | }