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