1 | /***************************************
2 | $Revision: 1.14 $
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 | /*++++++++++++++
140 | finds a tree matching the specified criteria(registry+space+family).
141 |
142 | MT-note: locks/unlocks forest (still to be done)
143 |
144 | Returns: RX_OK or RX_NOTREE if no such tree can be found.
145 | +++++++++++*/
146 |
147 | er_ret_t
148 | RX_get_tree ( rx_tree_t **treeptr, /*+ answer goes here, please +*/
149 | rx_regid_t reg_id, /*+ id of the registry +*/
150 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/
151 | rx_fam_t fam_id /*+ family of objects (route/inetnum) +*/
152 | )
153 |
154 | {
155 | GList *elem = g_list_first(rx_forest);
156 | rx_tree_t *trp;
157 |
158 | while( elem != NULL ) {
159 | trp = (rx_tree_t *) elem->data;
160 |
161 | if( trp->reg_id == reg_id
162 | && trp->space == spc_id && trp->family == fam_id) {
163 | /* copy the value to user's data */
164 | *treeptr = trp;
165 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "tree found at %08x",trp);
166 |
167 | return RX_OK;
168 | }
169 | elem = g_list_next(elem);
170 | }
171 |
172 | *treeptr = NULL; // set no NOT FOUND
173 | return RX_NOTREE;
174 | }
175 |
176 |
177 | /***************************************************************************/
178 | /*++++++
179 | creates a (top) tree for the space, fills out sql table of trees
180 | generates a tablename for a tree (if NONE)
181 | updates LL of trees
182 |
183 | MT-note: locks/unlocks the forest (still to be done)
184 |
185 | ++++++++*/
186 | er_ret_t
187 | RX_tree_cre (
188 | rx_regid_t reg_id, /*+ id of the registry +*/
189 | ip_space_t spc_id, /*+ space id, one of IPv4 IPv6. +*/
190 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/
191 | char *prefixstr, /*+ prefix the tree will cover (string) +*/
192 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
193 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/
194 | rx_tree_t **treestore /* store the tree pointer here */
195 | )
196 |
197 | {
198 | er_ret_t err;
199 | rx_tree_t *newtree;
200 | ip_prefix_t newpref;
201 |
202 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
203 | die;
204 | }
205 |
206 | RX_get_tree ( &newtree, reg_id, spc_id, fam_id);
207 |
208 | if ( newtree != NULL ) {
209 | // die; /* error RX_TRALEX == tree already exists */
210 | return RX_TRALEX;
211 | }
212 |
213 |
214 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
215 | return err; // die
216 | }
217 |
218 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree);
219 |
220 | /* copy tree settings */
221 |
222 | newtree -> reg_id = reg_id;
223 | newtree -> space = spc_id;
224 | newtree -> family = fam_id;
225 | newtree -> subtrees = subtrees;
226 | newtree -> mem_mode = mem_mode;
227 |
228 | /* set other tree values */
229 |
230 | /* parent set to NULL because it's not a subtree */
231 | newtree -> parent_tree = NULL;
232 | // PR_zeroprefix(& newtree -> prefix);
233 | newtree -> maxbits = IP_sizebits(spc_id);
234 |
235 | strcpy(newtree->data_table.val,"");
236 | strcpy(newtree->radix_table.val,"");
237 | strcpy(newtree->leaves_table.val,"");
238 |
239 | newtree->num_nodes = 0;
240 |
241 | newtree->top_ptr = NULL;
242 | newtree->top_key = SQ_NOKEY;
243 |
244 | newtree->prefix = newpref;
245 |
246 | TH_init_read_write_lock( &(newtree->rwlock));
247 |
248 | *treestore = newtree;
249 |
250 | return RX_OK;
251 | }
252 |
253 | void RX_attach2forest(rx_tree_t *newtree) {
254 | /* put into LL of trees; handle alloc err ??? */
255 | /* if threads are supposed to be reading already,
256 | set forest mutex; */
257 |
258 | rx_forest = g_list_append (rx_forest, newtree);
259 |
260 | /* release forest mutex; */
261 |
262 | }
263 |
264 |
265 | /* ************************************
266 | special walk function for use in consistency checks - it checks the parent
267 | pointer too.
268 | ************************************/
269 | int rx_check_walk_tree( rx_node_t *node,
270 | rx_node_t *parent_node,
271 | int nodecounter,
272 | rx_treecheck_t *checkstruct )
273 | {
274 | int i;
275 |
276 | // checks
277 | if( node == NULL ) {
278 | checkstruct->code |= 1;
279 | }
280 | if( node->parent_ptr != parent_node ) {
281 | checkstruct->code |= 2;
282 | }
283 | if( node->glue && node->leaves_ptr ) {
284 | checkstruct->code |= 4;
285 | }
286 | if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
287 | checkstruct->code |= 8;
288 | }
289 |
290 |
291 | if( node->leaves_ptr && checkstruct->datatoo ) {
292 | switch( checkstruct->tree->family ) {
293 | case RX_FAM_IP:
294 | /* the simplest (?) case: only one leaf attached to any node
295 | (except for glues) */
296 | if( g_list_length(node->leaves_ptr) != 1 ) {
297 | checkstruct->code |= 16;
298 | }
299 | break;
300 | case RX_FAM_RT:
301 | /* many dataleaves attached to nodes. */
302 | break;
303 | case RX_FAM_IN:
304 | /* many dataleaves attached to nodes.
305 | Some leaves pointed to from many nodes => from as many as the number
306 | of composing prefixes
307 | */
308 | break;
309 | }
310 | }
311 |
312 |
313 | if( checkstruct->code != 0 ) {
314 | checkstruct->node = node;
315 |
316 | return nodecounter; // abort the walk on error
317 | }
318 |
319 |
320 | nodecounter++;
321 |
322 | for(i=0; i<=1; i++) {
323 | if( node->child_ptr[i] != NULL ) {
324 | nodecounter += rx_check_walk_tree( node->child_ptr[i],
325 | node,
326 | 0, checkstruct );
327 | // abort the walk on error
328 | if ( checkstruct->code != 0 ) {
329 | break;
330 | }
331 | }
332 | }
333 | return nodecounter;
334 | }
335 |
336 | /* **************************************************************************
337 | tree consistency check.
338 |
339 | if datatoo = 0, then only parent/child links are checked.
340 |
341 | if datatoo = 1, then a check on the contents of the nodes is done too.
342 |
343 | **************************************************************************/
344 |
345 | er_ret_t
346 | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
347 | {
348 | er_ret_t (*hook_function)(); // pointer to the walk_hook function
349 | er_ret_t err = RX_OK;
350 | int nodnum;
351 |
352 | errorfound->tree = tree;
353 | errorfound->datatoo = datatoo;
354 |
355 | /* errorfound.node will be set by hook if it finds an error*/
356 | errorfound->code = 0;
357 |
358 | nodnum = rx_check_walk_tree( tree->top_ptr,
359 | NULL,
360 | 0,
361 | errorfound );
362 |
363 | if( nodnum != tree->num_nodes ) {
364 | errorfound->code |= 1024;
365 | }
366 | if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
367 | errorfound->code |= 2048;
368 | }
369 | if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
370 | errorfound->code |= 4096;
371 | }
372 |
373 | if( errorfound->code != 0) {
374 | err = RX_DATNOF;
375 | }
376 | return err;
377 | }