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