1 | /*************************************** 2 | $Revision: 1.19 $ 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 | XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from 63 | calling parameter list, shane 2001-02-01 64 | ++++++++++++*/ 65 | int 66 | rx_walk_tree(rx_node_t *node, 67 | er_ret_t (*func)(rx_node_t *node, int level, int nodecounter, 68 | void *userptr), 69 | rx_walk_mt walk_mode, 70 | /* controls if glue nodes are counted*/ 71 | /* and if levels or prefix lenghts are checked*/ 72 | int maxlevel, 73 | int level, 74 | int nodecounter, 75 | void *userptr, 76 | er_ret_t *err) 77 | { 78 | int i, link; 79 | 80 | if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/ 81 | 82 | /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */ 83 | /* level otherwise */ 84 | 85 | if(walk_mode & RX_WALK_PRFLEN) { 86 | if(node->prefix.bits > maxlevel) { 87 | return nodecounter; 88 | } 89 | } 90 | else if( level > maxlevel ) { 91 | return nodecounter; 92 | } 93 | 94 | 95 | /* process the node appropriately: */ 96 | /* if (not node glue) or (process glue nodes) */ 97 | 98 | if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) { 99 | 100 | /* increase our depth counter */ 101 | level++; 102 | 103 | /* increase the count of visited nodes */ 104 | nodecounter++; 105 | 106 | /* call supplied function, if any */ 107 | if( func != NULL ) { 108 | *err = func(node, level, nodecounter, userptr); 109 | 110 | /* abort the walk on error*/ 111 | if( *err != RX_OK ) { 112 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK, 113 | "walk_tree: func returned error %d, aborting", *err); 114 | return nodecounter; 115 | } 116 | } 117 | } 118 | 119 | /* process left and right children */ 120 | for(i=0; i<=1; i++) { 121 | 122 | /* reverse the sense of the walk*/ 123 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i; 124 | 125 | if( node->child_ptr[link] != NULL ) { 126 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode, 127 | maxlevel, level, 0, userptr, err); 128 | /* abort the walk on error*/ 129 | if( func != NULL && *err != RX_OK ) { 130 | break; 131 | } 132 | } 133 | } 134 | 135 | /* return count of nodes visited */ 136 | return nodecounter; 137 | } 138 | 139 | /*+++++++++ 140 | go down the tree and delete all nodes of the tree. 141 | 142 | the function is called recursively with level increased 143 | it stops recursing when no child nodes are found or maxlevel is reached. 144 | 145 | therefore the initial call must set level to 0. 146 | 147 | the nodecounter increments at every node, and is the return value 148 | of the function. So start with 0 to get the number of nodes traversed. 149 | 150 | ERROR HANDLING IS DIFFERENT HERE! 151 | Unlike other functions it is not the return value: 152 | The error code from the func function IF DEFINED (== not NULL ) goes 153 | to the variable pointed to by the last parameter. 154 | 155 | XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from 156 | calling parameter list, shane 2001-02-01 157 | ++++++++++++*/ 158 | void rx_delete_dataleaves(void *element_data, void *result_ptr) 159 | { 160 | rx_dataleaf_t *leafptr = element_data; 161 | rx_tree_t *tree = result_ptr; 162 | 163 | if(tree->family == RX_FAM_IP ) { 164 | /* do not look at the leaf if RX_FAM_IP */ 165 | /* Just free the payload, there must be one and just one. */ 166 | wr_free(leafptr); 167 | } 168 | else { /* other families */ 169 | /* if not >composed< then delete dataleaf */ 170 | if( leafptr->composed == 0 ) { 171 | if( leafptr->data_ptr ) 172 | wr_free(leafptr->data_ptr); 173 | wr_free(leafptr); 174 | 175 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount = 0, removed"); 176 | 177 | } 178 | /* else decrement the reference number ( == number of prefixes 179 | composing the range minus 1 == the >composed< flag */ 180 | else { 181 | leafptr->composed--; 182 | 183 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount -- to %d ", 184 | leafptr->composed ); 185 | } 186 | } /* if family != RX_FAM_IP */ 187 | } 188 | 189 | void rx_delete_treenode(rx_tree_t *tree, rx_node_t *curnode) 190 | { 191 | if(curnode->leaves_ptr) { 192 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "deleting dataleaves of node at %08x", curnode); 193 | g_list_foreach( curnode->leaves_ptr, rx_delete_dataleaves, tree); 194 | /* delete the GList */ 195 | g_list_free(curnode->leaves_ptr); 196 | } 197 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "node at %08x removed", curnode); 198 | wr_free(curnode); 199 | 200 | } 201 | 202 | /* The fuction itself */ 203 | int 204 | rx_delete_tree(rx_tree_t *tree, rx_node_t *node, 205 | int maxlevel, 206 | int level, 207 | int nodecounter, 208 | void *userptr) 209 | { 210 | int i, link; 211 | 212 | if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/ 213 | 214 | /* check if the level is reached */ 215 | 216 | if( level > maxlevel ) { 217 | return nodecounter; 218 | } 219 | 220 | 221 | /* process the node appropriately: */ 222 | /* increase our depth counter */ 223 | level++; 224 | 225 | /* increase the count of visited nodes */ 226 | nodecounter++; 227 | 228 | 229 | /* process left and right children */ 230 | for(i=0; i<=1; i++) { 231 | 232 | link = i; 233 | 234 | if( node->child_ptr[link] != NULL ) { 235 | nodecounter += rx_delete_tree(tree, node->child_ptr[link], maxlevel, level, 0, userptr); 236 | /* delete the processed child node */ 237 | rx_delete_treenode(tree, node->child_ptr[link]); 238 | } 239 | } 240 | 241 | /* if this is the top level - delete the top node and the tree*/ 242 | if(node == tree->top_ptr){ 243 | rx_delete_treenode(tree, node); 244 | tree->top_ptr=NULL; 245 | } 246 | 247 | /* return count of nodes deleted */ 248 | return nodecounter; 249 | } 250 | 251 | 252 | /***************************************************************************/ 253 | /*++++++ 254 | creates a (top) tree for the space, fills out sql table of trees 255 | generates a tablename for a tree (if NONE) 256 | updates LL of trees 257 | 258 | MT-note: locks/unlocks the forest (still to be done) 259 | 260 | ++++++++*/ 261 | er_ret_t 262 | RX_tree_cre ( 263 | char *prefixstr, /*+ prefix the tree will cover (string) +*/ 264 | rx_fam_t fam_id, 265 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/ 266 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/ 267 | rx_tree_t **treestore /* store the tree pointer here */ 268 | ) 269 | 270 | { 271 | er_ret_t err; 272 | rx_tree_t *newtree; 273 | ip_prefix_t newpref; 274 | ip_space_t spc_id; 275 | 276 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) { 277 | die; 278 | } 279 | 280 | spc_id = IP_pref_b2_space( &newpref ); 281 | 282 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) { 283 | return err; /* die*/ 284 | } 285 | 286 | ER_dbg_va(FAC_RX, ASP_RX_TREE_GEN, "creating a tree at %08x", newtree); 287 | 288 | /* copy tree settings */ 289 | newtree -> space = spc_id; 290 | newtree -> family = fam_id; 291 | 292 | newtree -> subtrees = subtrees; 293 | newtree -> mem_mode = mem_mode; 294 | 295 | /* set other tree values */ 296 | 297 | /* parent set to NULL because it's not a subtree */ 298 | newtree -> parent_tree = NULL; 299 | /* PR_zeroprefix(& newtree -> prefix);*/ 300 | newtree -> maxbits = IP_sizebits(spc_id); 301 | 302 | strcpy(newtree->data_table.val,""); 303 | strcpy(newtree->radix_table.val,""); 304 | strcpy(newtree->leaves_table.val,""); 305 | 306 | newtree->num_nodes = 0; 307 | 308 | newtree->top_ptr = NULL; 309 | newtree->top_key = SQ_NOKEY; 310 | 311 | newtree->prefix = newpref; 312 | 313 | TH_init_read_write_lockw( &(newtree->rwlock)); 314 | 315 | *treestore = newtree; 316 | 317 | return RX_OK; 318 | } 319 | 320 | 321 | /* ************************************ 322 | special walk function for use in consistency checks - it checks the parent 323 | pointer too. 324 | ************************************/ 325 | int rx_check_walk_tree( rx_node_t *node, 326 | rx_node_t *parent_node, 327 | int nodecounter, 328 | rx_treecheck_t *checkstruct ) 329 | { 330 | int i; 331 | 332 | /* checks*/ 333 | if( node == NULL ) { 334 | checkstruct->code |= 1; 335 | } 336 | if( node->parent_ptr != parent_node ) { 337 | checkstruct->code |= 2; 338 | } 339 | if( node->glue && node->leaves_ptr ) { 340 | checkstruct->code |= 4; 341 | } 342 | if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) { 343 | checkstruct->code |= 8; 344 | } 345 | 346 | 347 | if( node->leaves_ptr && checkstruct->datatoo ) { 348 | switch( checkstruct->tree->family ) { 349 | case RX_FAM_IP: 350 | /* the simplest (?) case: only one leaf attached to any node 351 | (except for glues) */ 352 | if( g_list_length(node->leaves_ptr) != 1 ) { 353 | checkstruct->code |= 16; 354 | } 355 | break; 356 | case RX_FAM_RT: 357 | /* many dataleaves attached to nodes. */ 358 | break; 359 | case RX_FAM_IN: 360 | /* many dataleaves attached to nodes. 361 | Some leaves pointed to from many nodes => from as many as the number 362 | of composing prefixes 363 | */ 364 | break; 365 | default: 366 | /* ignore */ 367 | break; 368 | } 369 | } 370 | 371 | 372 | if( checkstruct->code != 0 ) { 373 | checkstruct->node = node; 374 | 375 | return nodecounter; /* abort the walk on error*/ 376 | } 377 | 378 | 379 | nodecounter++; 380 | 381 | for(i=0; i<=1; i++) { 382 | if( node->child_ptr[i] != NULL ) { 383 | nodecounter += rx_check_walk_tree( node->child_ptr[i], 384 | node, 385 | 0, checkstruct ); 386 | /* abort the walk on error*/ 387 | if ( checkstruct->code != 0 ) { 388 | die; break; 389 | } 390 | } 391 | } 392 | return nodecounter; 393 | } 394 | 395 | /* ************************************************************************** 396 | tree consistency check. 397 | 398 | if datatoo = 0, then only parent/child links are checked. 399 | 400 | if datatoo = 1, then a check on the contents of the nodes is done too. 401 | 402 | **************************************************************************/ 403 | 404 | er_ret_t 405 | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound) 406 | { 407 | er_ret_t err = RX_OK; 408 | int nodnum; 409 | 410 | errorfound->tree = tree; 411 | errorfound->datatoo = datatoo; 412 | 413 | /* errorfound.node will be set by hook if it finds an error*/ 414 | errorfound->code = 0; 415 | 416 | nodnum = rx_check_walk_tree( tree->top_ptr, 417 | NULL, 418 | 0, 419 | errorfound ); 420 | 421 | if( nodnum != tree->num_nodes ) { 422 | errorfound->code |= 1024; 423 | } 424 | if( tree->num_nodes == 0 && tree->top_ptr != NULL ) { 425 | errorfound->code |= 2048; 426 | } 427 | if( tree->num_nodes != 0 && tree->top_ptr == NULL ) { 428 | errorfound->code |= 4096; 429 | } 430 | 431 | if( errorfound->code != 0) { 432 | err = RX_DATNOF; 433 | } 434 | return err; 435 | }