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 | }