1 | /*************************************** 2 | $Revision: 1.15 $ 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 | creates a (top) tree for the space, fills out sql table of trees 140 | generates a tablename for a tree (if NONE) 141 | updates LL of trees 142 | 143 | MT-note: locks/unlocks the forest (still to be done) 144 | 145 | ++++++++*/ 146 | er_ret_t 147 | RX_tree_cre ( 148 | char *prefixstr, /*+ prefix the tree will cover (string) +*/ 149 | rx_fam_t fam_id, 150 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/ 151 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/ 152 | rx_tree_t **treestore /* store the tree pointer here */ 153 | ) 154 | 155 | { 156 | er_ret_t err; 157 | rx_tree_t *newtree; 158 | ip_prefix_t newpref; 159 | ip_space_t spc_id; 160 | 161 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) { 162 | die; 163 | } 164 | 165 | spc_id = IP_pref_b2_space( &newpref ); 166 | 167 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) { 168 | return err; /* die*/ 169 | } 170 | 171 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree); 172 | 173 | /* copy tree settings */ 174 | newtree -> space = spc_id; 175 | newtree -> family = fam_id; 176 | 177 | newtree -> subtrees = subtrees; 178 | newtree -> mem_mode = mem_mode; 179 | 180 | /* set other tree values */ 181 | 182 | /* parent set to NULL because it's not a subtree */ 183 | newtree -> parent_tree = NULL; 184 | /* PR_zeroprefix(& newtree -> prefix);*/ 185 | newtree -> maxbits = IP_sizebits(spc_id); 186 | 187 | strcpy(newtree->data_table.val,""); 188 | strcpy(newtree->radix_table.val,""); 189 | strcpy(newtree->leaves_table.val,""); 190 | 191 | newtree->num_nodes = 0; 192 | 193 | newtree->top_ptr = NULL; 194 | newtree->top_key = SQ_NOKEY; 195 | 196 | newtree->prefix = newpref; 197 | 198 | TH_init_read_write_lock( &(newtree->rwlock)); 199 | 200 | *treestore = newtree; 201 | 202 | return RX_OK; 203 | } 204 | 205 | 206 | /* ************************************ 207 | special walk function for use in consistency checks - it checks the parent 208 | pointer too. 209 | ************************************/ 210 | int rx_check_walk_tree( rx_node_t *node, 211 | rx_node_t *parent_node, 212 | int nodecounter, 213 | rx_treecheck_t *checkstruct ) 214 | { 215 | int i; 216 | 217 | /* checks*/ 218 | if( node == NULL ) { 219 | checkstruct->code |= 1; 220 | } 221 | if( node->parent_ptr != parent_node ) { 222 | checkstruct->code |= 2; 223 | } 224 | if( node->glue && node->leaves_ptr ) { 225 | checkstruct->code |= 4; 226 | } 227 | if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) { 228 | checkstruct->code |= 8; 229 | } 230 | 231 | 232 | if( node->leaves_ptr && checkstruct->datatoo ) { 233 | switch( checkstruct->tree->family ) { 234 | case RX_FAM_IP: 235 | /* the simplest (?) case: only one leaf attached to any node 236 | (except for glues) */ 237 | if( g_list_length(node->leaves_ptr) != 1 ) { 238 | checkstruct->code |= 16; 239 | } 240 | break; 241 | case RX_FAM_RT: 242 | /* many dataleaves attached to nodes. */ 243 | break; 244 | case RX_FAM_IN: 245 | /* many dataleaves attached to nodes. 246 | Some leaves pointed to from many nodes => from as many as the number 247 | of composing prefixes 248 | */ 249 | break; 250 | default: 251 | /* ignore */ 252 | break; 253 | } 254 | } 255 | 256 | 257 | if( checkstruct->code != 0 ) { 258 | checkstruct->node = node; 259 | 260 | return nodecounter; /* abort the walk on error*/ 261 | } 262 | 263 | 264 | nodecounter++; 265 | 266 | for(i=0; i<=1; i++) { 267 | if( node->child_ptr[i] != NULL ) { 268 | nodecounter += rx_check_walk_tree( node->child_ptr[i], 269 | node, 270 | 0, checkstruct ); 271 | /* abort the walk on error*/ 272 | if ( checkstruct->code != 0 ) { 273 | break; 274 | } 275 | } 276 | } 277 | return nodecounter; 278 | } 279 | 280 | /* ************************************************************************** 281 | tree consistency check. 282 | 283 | if datatoo = 0, then only parent/child links are checked. 284 | 285 | if datatoo = 1, then a check on the contents of the nodes is done too. 286 | 287 | **************************************************************************/ 288 | 289 | er_ret_t 290 | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound) 291 | { 292 | er_ret_t err = RX_OK; 293 | int nodnum; 294 | 295 | errorfound->tree = tree; 296 | errorfound->datatoo = datatoo; 297 | 298 | /* errorfound.node will be set by hook if it finds an error*/ 299 | errorfound->code = 0; 300 | 301 | nodnum = rx_check_walk_tree( tree->top_ptr, 302 | NULL, 303 | 0, 304 | errorfound ); 305 | 306 | if( nodnum != tree->num_nodes ) { 307 | errorfound->code |= 1024; 308 | } 309 | if( tree->num_nodes == 0 && tree->top_ptr != NULL ) { 310 | errorfound->code |= 2048; 311 | } 312 | if( tree->num_nodes != 0 && tree->top_ptr == NULL ) { 313 | errorfound->code |= 4096; 314 | } 315 | 316 | if( errorfound->code != 0) { 317 | err = RX_DATNOF; 318 | } 319 | return err; 320 | }