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  |