1 | /*************************************** 2 | $Revision: 1.10 $ 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; 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 | } 85 | 86 | // check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, 87 | // level otherwise 88 | 89 | if(walk_mode & RX_WALK_PRFLEN) { 90 | if(node->prefix.bits > maxlevel) { 91 | return nodecounter; 92 | } 93 | } 94 | else if( level > maxlevel ) { 95 | return nodecounter; 96 | } 97 | 98 | // didn't quit ?? OK, count it too... 99 | nodecounter++; 100 | 101 | if( func != NULL ) { 102 | *err = func(node, level, nodecounter, userptr); 103 | 104 | // abort the walk on error 105 | if( *err != RX_OK ) { 106 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK, 107 | "walk_tree: func returned error %d, aborting", *err); 108 | return nodecounter; 109 | } 110 | } 111 | 112 | 113 | for(i=0; i<=1; i++) { 114 | 115 | // reverse the sense of the walk 116 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i; 117 | 118 | if( node->child_ptr[link] != NULL ) { 119 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode, 120 | maxlevel, level, 0, userptr, err); 121 | // abort the walk on error 122 | if( func != NULL && *err != RX_OK ) { 123 | break; 124 | } 125 | } 126 | } 127 | 128 | return nodecounter; 129 | } 130 | 131 | 132 | 133 | 134 | /***************************************************************************/ 135 | /*++++++++++++++ 136 | finds a tree matching the specified criteria(registry+space+family). 137 | 138 | MT-note: locks/unlocks forest (still to be done) 139 | 140 | Returns: RX_OK or RX_NOTREE if no such tree can be found. 141 | +++++++++++*/ 142 | 143 | er_ret_t 144 | RX_get_tree ( rx_tree_t **treeptr, /*+ answer goes here, please +*/ 145 | rx_regid_t reg_id, /*+ id of the registry +*/ 146 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/ 147 | rx_fam_t fam_id /*+ family of objects (route/inetnum) +*/ 148 | ) 149 | 150 | { 151 | GList *elem = g_list_first(rx_forest); 152 | rx_tree_t *trp; 153 | 154 | while( elem != NULL ) { 155 | trp = (rx_tree_t *) elem->data; 156 | 157 | if( trp->reg_id == reg_id 158 | && trp->space == spc_id && trp->family == fam_id) { 159 | /* copy the value to user's data */ 160 | *treeptr = trp; 161 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "tree found at %08x",trp); 162 | 163 | return RX_OK; 164 | } 165 | elem = g_list_next(elem); 166 | } 167 | 168 | *treeptr = NULL; // set no NOT FOUND 169 | return RX_NOTREE; 170 | } 171 | 172 | 173 | /***************************************************************************/ 174 | /*++++++ 175 | creates a (top) tree for the space, fills out sql table of trees 176 | generates a tablename for a tree (if NONE) 177 | updates LL of trees 178 | 179 | MT-note: locks/unlocks the forest (still to be done) 180 | 181 | ++++++++*/ 182 | er_ret_t 183 | RX_space_cre ( 184 | rx_regid_t reg_id, /*+ id of the registry +*/ 185 | ip_space_t spc_id, /*+ space id, one of IPv4 IPv6. +*/ 186 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/ 187 | char *prefixstr, /*+ prefix the tree will cover (string) +*/ 188 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/ 189 | rx_subtree_mt subtrees /*+ one of NONE, AUTO, HAND +*/ 190 | ) 191 | 192 | { 193 | er_ret_t err; 194 | rx_tree_t *newtree; 195 | ip_prefix_t newpref; 196 | 197 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) { 198 | die; 199 | } 200 | 201 | RX_get_tree ( &newtree, reg_id, spc_id, fam_id); 202 | 203 | if ( newtree != NULL ) { 204 | // die; /* error RX_TRALEX == tree already exists */ 205 | return RX_TRALEX; 206 | } 207 | 208 | /* set forest mutex; */ 209 | 210 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) { 211 | return err; // die 212 | } 213 | 214 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree); 215 | 216 | /* copy tree settings */ 217 | 218 | newtree -> reg_id = reg_id; 219 | newtree -> space = spc_id; 220 | newtree -> family = fam_id; 221 | newtree -> subtrees = subtrees; 222 | newtree -> mem_mode = mem_mode; 223 | 224 | /* set other tree values */ 225 | 226 | /* parent set to NULL because it's not a subtree */ 227 | newtree -> parent_tree = NULL; 228 | // PR_zeroprefix(& newtree -> prefix); 229 | newtree -> maxbits = IP_sizebits(spc_id); 230 | 231 | strcpy(newtree->data_table.val,""); 232 | strcpy(newtree->radix_table.val,""); 233 | strcpy(newtree->leaves_table.val,""); 234 | 235 | newtree->num_nodes = 0; 236 | 237 | newtree->top_ptr = NULL; 238 | newtree->top_key = SQ_NOKEY; 239 | 240 | newtree->prefix = newpref; 241 | 242 | /* put into LL of trees; handle alloc err ??? */ 243 | 244 | rx_forest = g_list_append (rx_forest, newtree); 245 | 246 | /* release forest mutex; */ 247 | return RX_OK; 248 | } 249 |