1 | /***************************************
2 | $Revision: 1.35 $
3 |
4 | Radix tree (rx). rx_node.c - functions to operate on nodes of the tree
5 | (creation/deletion).
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 | #include "rip.h"
33 | #include <glib.h>
34 |
35 |
36 | /***************************************************************************/
37 | /*++++++++++++++++
38 | rx_creat_node = create a new data node
39 | (empty{glue} nodes get created automatically).
40 |
41 | Takes a pointer to the (already allocated) data leaf to be included
42 | in the list of data nodes (presumably empty as the node is only now being
43 | created).
44 |
45 | Requires a stack of nodes created in CREAT mode (with glue nodes,
46 | until deep enough and the last node being non-glue).
47 |
48 | MT notes: requires the tree to be locked.
49 |
50 | Returns: RX_OK or error code.
51 |
52 | +++++++++++++++++*/
53 | static
54 | er_ret_t
55 | rx_creat_node (
56 | ip_prefix_t *newpref, /*+ prefix of the node to be added +*/
57 | rx_tree_t *tree, /*+ tree the new node goes to +*/
58 | rx_dataleaf_t *dataleaf, /*+ dataleaf to attach at this node+*/
59 | rx_nodcpy_t stack[], /*+ stack==array of node_copies +*/
60 | int stackdepth /*+ length of the stack +*/
61 | )
62 | {
63 | rx_node_t *newnode, *curnode, *memnode, *gluenode;
64 | unsigned chk_bit, dif_bit, link, curpos;
65 | char buf[1024];
66 |
67 | /* assume no such node yet. Will die if there is one.*/
68 |
69 | /* calloc, because parent/child keys and child ptrs are not always set.*/
70 |
71 | newnode = (rx_node_t *)UT_calloc(1, sizeof(rx_node_t));
72 |
73 | /* increment the number of nodes in the tree*/
74 | tree -> num_nodes ++;
75 |
76 | newnode -> prefix = *newpref;
77 |
78 | /* attach the leaf to a (presumably empty?! hence NULL) list...*/
79 | newnode->leaves_ptr = g_list_prepend(NULL, dataleaf);
80 | newnode->glue = 0;
81 |
82 | /* OK, so take a look at the tree*/
83 |
84 | if ( tree -> num_nodes == 1 ) {
85 | /* The tree was empty. Create a new top node.*/
86 |
87 | tree -> top_ptr = newnode;
88 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Created as the top node");
89 | return RX_OK;
90 | }
91 |
92 | /* OK, there is at least one node in the tree. Take a look at the stack.*/
93 |
94 | /* we've got a real node there (not a glue), but we may be too deep.*/
95 | /* (it's not a glue, because glues have always two children.*/
96 | /* we had to go that deep because from a glue alone one doesn't know */
97 | /* what it glues)*/
98 | /* GO UP.*/
99 | /* take the first differing bit from comparing */
100 | /* the new and the found nodes' prefixes. */
101 | /* (not deeper than the shorter of the two)*/
102 |
103 | curpos = stackdepth-1;
104 | curnode = & stack[curpos].cpy;
105 |
106 | chk_bit = smaller(curnode->prefix.bits, newpref->bits );
107 |
108 | for(dif_bit = 0; dif_bit < chk_bit; dif_bit++) {
109 | /* break the loop when the first different bit is found*/
110 |
111 | if( IP_addr_bit_get( & curnode->prefix.ip, dif_bit)
112 | != IP_addr_bit_get( & newpref->ip, dif_bit) ) {
113 | break;
114 | }
115 | }
116 |
117 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
118 | "cur = %d, new = %d, chk_bit = %d, dif_bit = %d",
119 | curnode->prefix.bits, newpref->bits, chk_bit, dif_bit );
120 |
121 | if(dif_bit == IP_sizebits(newpref->ip.space)) die; /* it mustn't happen!!!*/
122 |
123 | /* go up to that level (watch the head of the tree!)*/
124 |
125 | while( curpos > 0 && stack[curpos-1].cpy.prefix.bits >= dif_bit) {
126 | curpos--;
127 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
128 | "up to level %d", curpos );
129 | }
130 |
131 | /*
132 | if the bit lenghts of the node, new prefix and the diffbit are equal
133 | {
134 | YOU'VE GOT THE NODE where the new one will be attached.
135 | Either it has data (and will be moved accordingly),
136 | or is a glue (and will be turned into a regular node).
137 | }
138 | */
139 |
140 | curnode = & stack[curpos].cpy;
141 |
142 | /* RAM: set a pointer to the real node in memory*/
143 | memnode = stack[curpos].srcptr;
144 |
145 | if( dif_bit == newpref->bits
146 | && dif_bit == curnode->prefix.bits ) {
147 |
148 | /* such node already exists, nothing to change in the tree!!!*/
149 | /* this should be checked before calling this function, so..*/
150 |
151 | die;
152 | }
153 | /*
154 | else ** the branch ends here; we must create a new node... **
155 | {
156 | OK, how is the new node's prefix length w.r.t the dif_bit ?
157 | longer -> make it a child of the node found
158 | shorter -> make it the parent of the node found and take its place
159 | equal -> make a glue node the parent of both
160 | }
161 |
162 | WHEN ATTACHING THE NODE, VALUES FROM THE STACK ARE USED,
163 | TO PREVENT EXCESSIVE LOOKUPS AGAIN.
164 |
165 | */
166 | else {
167 |
168 | /* **** attach it.*/
169 | if( ER_is_traced(FAC_RX, ASP_RX_NODCRE_DET) ) {
170 | rx_nod_print(curnode, buf, 1024);
171 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Looking at node %s", buf);
172 | }
173 |
174 | if( curnode -> prefix.bits == dif_bit ) {
175 |
176 | /* attach here as a child of the node found */
177 | link = IP_addr_bit_get( &newpref->ip, dif_bit );
178 |
179 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "attaching as child %d", link);
180 |
181 | if( memnode -> child_ptr[link] != NULL ) {
182 | die;
183 | }
184 |
185 | memnode -> child_ptr[link] = newnode;
186 | newnode -> parent_ptr = memnode;
187 | }
188 | else if ( newpref->bits == dif_bit ) {
189 | /* make it the parent of the node found and take its place,*/
190 | /* moving it down.*/
191 |
192 | /* set the link from the NEW node to the OLD one (different than before)*/
193 |
194 | link = IP_addr_bit_get( &curnode->prefix.ip, dif_bit );
195 |
196 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "shifting down as child %d", link);
197 |
198 | /* PARENT<->NEW LINKS*/
199 | /* see if the node was the top_node*/
200 | if (curnode -> parent_ptr == NULL) {
201 | /* update tree struct */
202 | tree -> top_ptr = newnode;
203 | } else {
204 | /* no - fix the child link at the parent.*/
205 | /* at the link where it was attached*/
206 | int link = (curnode->parent_ptr->child_ptr[1] == memnode);
207 | memnode -> parent_ptr -> child_ptr[link] = newnode;
208 | }
209 | memnode -> parent_ptr = newnode;
210 |
211 | /* NEW<->CHILD LINKS*/
212 | newnode -> parent_ptr = curnode->parent_ptr;
213 | newnode -> child_ptr[link] = memnode;
214 | }
215 | else {
216 | /* create a glue and shift the curnode below the glue,*/
217 | /* then attach the new node at the glue*/
218 |
219 | /* calloc, because parent/child keys are not set.*/
220 |
221 | gluenode = UT_calloc(1, sizeof(rx_node_t));
222 | tree -> num_nodes ++;
223 |
224 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "created glue node at %p", gluenode);
225 |
226 | gluenode -> prefix.bits = dif_bit;
227 |
228 | /* fill in the address. The glue node should get the prefix*/
229 | /* shorter by one than the shorter of the two prefixes that are glued*/
230 | /* (difbit)*/
231 | /**/
232 |
233 | gluenode -> prefix.ip = newpref->ip;
234 | gluenode -> prefix.bits = dif_bit;
235 |
236 | /* the ip in this prefix is probably incorrect. Fix it.*/
237 | IP_pref_bit_fix( & gluenode -> prefix );
238 |
239 | gluenode -> leaves_ptr = NULL;
240 | gluenode -> glue = 1;
241 |
242 | /* 1. Fix the link to and from the parent to the gluenode.*/
243 |
244 | gluenode -> parent_ptr = curnode->parent_ptr;
245 | if (gluenode->parent_ptr == NULL) {
246 | tree -> top_ptr = gluenode;
247 | }
248 | else {
249 | /* fix the child link in the parent. */
250 | /* if it was at 1, then let fix the link 1, 0 otherwise*/
251 |
252 | link = (curnode->parent_ptr->child_ptr[1] == memnode);
253 |
254 | memnode->parent_ptr->child_ptr[link] = gluenode;
255 | }
256 |
257 | /* 2. Fix the links between gluenode and the OLD node*/
258 |
259 | link = IP_addr_bit_get( &newpref->ip, dif_bit );
260 |
261 | gluenode -> child_ptr[ ! link ] = memnode;
262 | memnode->parent_ptr = gluenode;
263 |
264 | /* 3. Fix the links between gluenode and the NEW node*/
265 |
266 | gluenode -> child_ptr[ link ] = newnode;
267 | newnode -> parent_ptr = gluenode;
268 | }
269 | return RX_OK;
270 | }
271 | die;
272 | return -1; /*this is just to calm down the compiler*/
273 | }
274 |
275 |
276 | /******************************************************************
277 | an auxiliary function to delete data from a node
278 | (and delete the node or turn it into a glue afterwards)
279 |
280 | takes
281 |
282 | tree tree
283 | curnode pointer to the node
284 | dataleaf pointer to a dataleaf with ObjectID (dataleaf->data_key)
285 | set; which is used to choose the right dataleaf
286 | when browsing data leaves. It is never assumed to be
287 | allocated via malloc, can be a local variable as well.
288 |
289 | If the composed flag of the dataleaf in the tree
290 | (being the reference count at the same time)
291 | is non zero, decrements the count.
292 | Deletes the dataleaf when it reaches zero.
293 |
294 | suceeds always or dies when dataleaf with such data cannot be found
295 | in the node
296 | */
297 |
298 | void
299 | rx_delete_node (rx_tree_t *tree, rx_node_t *curnode, rx_dataleaf_t *dataleaf)
300 | {
301 | rx_dataleaf_t *leaffound = NULL;
302 | GList *qitem;
303 | int leavesum=0;
304 |
305 | /*+ RX_FAM_IP implies there's no dataleaf!!!
306 | The structure in place of a dataleaf is payload
307 | +*/
308 |
309 | /* go through leaves, comparing the objectID (data_key) */
310 | for( qitem = g_list_first(curnode->leaves_ptr);
311 | qitem != NULL;
312 | qitem = g_list_next(qitem)) {
313 | rx_dataleaf_t *leafptr = qitem->data;
314 |
315 | if( tree->family == RX_FAM_IP /* do not look at the pointers */
316 | || leafptr->data_key == dataleaf->data_key ) { /* if RX_FAM_IP */
317 | leaffound = leafptr;
318 | /* no break - we're counting leaves..*/
319 | }
320 | leavesum++;
321 | }
322 |
323 |
324 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "%d dataleaves at the node", leavesum);
325 |
326 | /* return error if none of the dataleaves matched */
327 | if( leaffound == NULL ) die;
328 |
329 | /* NO error? good. Remove the leaf from the list */
330 | curnode->leaves_ptr = g_list_remove ( curnode->leaves_ptr, leaffound );
331 |
332 |
333 | if(tree->family == RX_FAM_IP ) {
334 | /* again: do not look at the leaf if RX_FAM_IP */
335 | /* Just free the payload, there must be one and just one. */
336 | UT_free(leaffound);
337 | }
338 | else { /* other families */
339 | /* if not >composed< then delete dataleaf */
340 | if( leaffound->composed == 0 ) {
341 | if( leaffound->data_ptr != NULL /* allow dataleafs without attached */
342 | && leaffound->data_len > 0 ) { /* data */
343 | UT_free(leaffound->data_ptr);
344 | }
345 | UT_free(leaffound);
346 |
347 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount = 0, removed");
348 |
349 | }
350 | /* else decrement the reference number ( == number of prefixes
351 | composing the range minus 1 == the >composed< flag */
352 | else {
353 | leaffound->composed--;
354 |
355 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount -- to %d ",
356 | leaffound->composed );
357 | }
358 | } /* if family != RX_FAM_IP */
359 |
360 | /* if that was the last leave at this node, then delete node. */
361 | if( leavesum == 1 ) {
362 | rx_node_t *parent = curnode->parent_ptr;
363 |
364 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "last dataleaf, removing node");
365 |
366 | assert(curnode->leaves_ptr == NULL);
367 | /* To do this, check the number of children: */
368 |
369 | /* 0 - just delete this node and the link to it */
370 | if( curnode->child_ptr[0] == NULL && curnode->child_ptr[1] == NULL ) {
371 |
372 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "no children, just removing");
373 |
374 | if( parent != NULL ) { /* watch the head! */
375 | int plink = (parent->child_ptr[1] == curnode);
376 | parent->child_ptr[plink] = NULL;
377 | }
378 | else {
379 | assert(tree->top_ptr == curnode);
380 | tree->top_ptr = NULL;
381 | }
382 | tree->num_nodes--;
383 | UT_free(curnode);
384 |
385 |
386 | /* now, if we deleted curnode, let's see if the parent node is a glue.
387 | If it is, then hook the remaining child up the grandparent,
388 | and delete the parent */
389 | if( parent != NULL && parent->glue ) {
390 | int slink = (parent->child_ptr[1] != NULL );
391 | rx_node_t *schild = parent->child_ptr[slink];
392 | rx_node_t *gparent = parent->parent_ptr;
393 |
394 | assert( schild != NULL && parent->child_ptr[ ! slink] == NULL);
395 |
396 | /* upd parent */
397 | if( gparent != NULL ) { /* watch the head! */
398 | int plink = (gparent->child_ptr[1] == parent);
399 | gparent->child_ptr[plink] = parent->child_ptr[slink];
400 | } else {
401 | assert(tree->top_ptr == parent);
402 | tree->top_ptr = parent->child_ptr[slink];
403 | }
404 |
405 | /* update the child's parent link too */
406 | parent->child_ptr[slink]->parent_ptr = gparent;
407 |
408 | /* del */
409 | tree->num_nodes--;
410 | UT_free(parent);
411 |
412 | } /* if parent glue */
413 | }
414 | /* 2 - turn into a glue */
415 | else if( curnode->child_ptr[0] != NULL
416 | && curnode->child_ptr[1] != NULL ) {
417 |
418 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "two children, turning into a glue");
419 |
420 | curnode->glue = 1;
421 |
422 | }
423 | /* 1 - copy the child's link to parent. then delete */
424 | else {
425 | int clink = (curnode->child_ptr[1] != NULL );
426 |
427 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "one child at %d, shifting it up",
428 | clink);
429 |
430 | /* upd parent */
431 | if( parent != NULL ) { /* watch the head! */
432 | int plink = (parent->child_ptr[1] == curnode);
433 | parent->child_ptr[plink] = curnode->child_ptr[clink];
434 | } else {
435 | /* no parent; the child becomes the top node now */
436 | tree->top_ptr = curnode->child_ptr[clink];
437 | }
438 |
439 | /* update the child's parent link too */
440 | curnode->child_ptr[clink]->parent_ptr = parent;
441 |
442 | /* del */
443 | tree->num_nodes--;
444 | UT_free(curnode);
445 | }
446 |
447 |
448 | } /* leavesum == 1 <=> that was the last data leaf */
449 | } /* rx_delete_node */
450 |
451 | /*+++++++++++++++++++
452 |
453 | General function to operate on dataleaves attached to a single node
454 | (create / modify / delete).
455 |
456 | searches tree, finds and creates/deletes a node,
457 | copies modified nodes to disk using rx_sql_node_set (not yet implemented).
458 | Updates memory rollback info.
459 |
460 |
461 |
462 |
463 | creation:
464 | Add a dataleaf at the node defined by prefix.
465 | Create a new node if it doesn't exist yet.
466 |
467 |
468 | MT notes: requires the tree to be locked.
469 |
470 | Returns: RX_OK or error code.
471 |
472 | Errors from:
473 | rx_bin_search,
474 | memory alloc routines.
475 |
476 | - no such node (if not in create mode)
477 |
478 | - too many nodes found (strange).
479 |
480 | +++++++++++++++++*/
481 |
482 | /*static*/
483 | er_ret_t
484 | rx_bin_node (
485 | rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
486 | ip_prefix_t *newpref, /*+ prefix of the node +*/
487 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
488 | rx_dataleaf_t *dataleaf /*+ dataleaf to attach at the node +*/
489 | )
490 |
491 | {
492 | GList *nodlist = NULL;
493 | int nodesfound, stackdepth;
494 | int glue;
495 | rx_nodcpy_t *curcpy;
496 | rx_node_t *curnode;
497 | /* rx_nodcpy_t *stack;*/
498 | rx_nodcpy_t stack[128];
499 | er_ret_t err;
500 | char bbf[IP_PREFSTR_MAX];
501 |
502 |
503 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_DET)) {
504 | IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
505 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_GEN,
506 | "rx_bin_node: %s in spc %d /fam %d operation %d",
507 | bbf, tree->space, tree->family, mode);
508 | }
509 |
510 | /* first check: are we using the correct tree ???*/
511 | if( tree->space != newpref->ip.space ) {
512 | /* trying to insert a prefix of space %d into a tree of space %d\n",
513 | tree->space,
514 | newpref->ip.space);
515 | */
516 | die;
517 | }
518 |
519 | assert( dataleaf );
520 | assert( newpref->bits <= IP_sizebits(tree->space) );
521 |
522 | /* fix the prefix, to make sure all insignificant bits are 0*/
523 | IP_pref_bit_fix( newpref );
524 |
525 | if( (err=rx_build_stack(stack, &stackdepth, tree, newpref, RX_STK_CREAT))
526 | != RX_OK ) {
527 | return err; /*die*/
528 | }
529 |
530 | /* rx_stk_print(stack, stackdepth);*/
531 |
532 | /* perform a search on the stack. The result is a list, and it must*/
533 | /* be properly deleted after use!!*/
534 |
535 | if( (err=rx_nod_search(RX_SRCH_CREAT, 0, 0,
536 | tree, newpref, stack, stackdepth,
537 | &nodlist, RX_ANS_ALL)) != RX_OK ) {
538 | return err; /* die;*/
539 | }
540 |
541 |
542 | /* count number of nodes in the answer */
543 | nodesfound = g_list_length (nodlist);
544 |
545 | switch( nodesfound ) {
546 | case 0:
547 | /* no such node (yet). See what we're up to.
548 | if( mode==cre ) create, else - program error, die */
549 |
550 | /* C R E A T I O N */
551 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
552 | "rx_bin_node: Creating a new node %s in spc %d /fam %d ",
553 | bbf, tree->space, tree->family);
554 | if( mode != RX_OPER_CRE) {
555 | die;
556 | }
557 |
558 | rx_creat_node( newpref, tree, dataleaf, stack, stackdepth );
559 | break;
560 | case 1: /* found */
561 | /* set the curnode pointer */
562 | curcpy = g_list_nth_data(nodlist, 0);
563 | curnode = curcpy->srcptr;
564 |
565 | switch( mode ) {
566 | case RX_OPER_CRE:
567 | /* attach the data at the node that was found;*/
568 |
569 | /* was it glue ?*/
570 | glue = curnode->glue;
571 |
572 | curnode->leaves_ptr = g_list_prepend(curnode->leaves_ptr, dataleaf);
573 | /* now it's not a glue anymore */
574 | curnode->glue = 0;
575 |
576 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Appended data to a %s node",
577 | glue ? "glue" : "data");
578 |
579 | break;
580 | case RX_OPER_DEL:
581 |
582 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
583 | "rx_bin_node: Deleting node %s in spc %d /fam %d ",
584 | bbf, tree->space, tree->family);
585 | rx_delete_node( tree, curnode, dataleaf);
586 | break;
587 | }
588 | break;
589 | default:
590 | /* too many nodes found! from an exact/exact-less-1 search.
591 | this cannot happen. Call Ghostbusters now.
592 | */
593 | die;
594 | }
595 |
596 | wr_clear_list( &nodlist );
597 |
598 | return RX_OK;
599 | }
600 |
601 |
602 |
603 | /***************************************************************************/
604 | /* ++++++++++++++++
605 | A wrapper around RX_bin_node.
606 |
607 | It's there only to control the freeing of dataleaf copies passed
608 | for comparison during deletion.
609 |
610 | +++++++++++++++++*/
611 | er_ret_t
612 | RX_rt_node (
613 | rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
614 | ip_prefix_t *newpref, /*+ prefix of the node +*/
615 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
616 | rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
617 | )
618 | {
619 | er_ret_t reterr;
620 |
621 | IP_pref_2_rang( & leafptr->iprange, newpref);
622 | leafptr->preflen = IP_pref_b2_len(newpref);
623 |
624 | /* store the object's range, used in rp.search */
625 |
626 | reterr = rx_bin_node(mode, newpref, tree, leafptr);
627 |
628 | return reterr;
629 | }
630 |
631 | /***************************************************************************/
632 | /*+++++++++++++++
633 | performs the actual update for inetnums (possibly composed of many prefixes).
634 | Decomposes the ranges into prefixes and then falls back to rx_bin_node
635 | to perform changes at the nodes.
636 |
637 | Requires/returns - practically the same as rx_bin_node.
638 | ++++++++++++++++*/
639 |
640 | er_ret_t
641 | RX_in_node( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
642 | ip_range_t *rang, /*+ range of IP addresses +*/
643 | rx_tree_t *tree, /*+ pointer to the tree structure +*/
644 | rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
645 | )
646 | {
647 | unsigned i, prefcount;
648 | GList *preflist = NULL;
649 | char buf[IP_RANGSTR_MAX];
650 |
651 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_GEN)) {
652 | IP_rang_b2a(rang, buf, IP_RANGSTR_MAX );
653 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_GEN,
654 | "rx_inum_node: adding %s", buf);
655 | }
656 |
657 | /* decompose, put links to the data leaf into every prefix*/
658 | /* that makes up this range.*/
659 | IP_rang_decomp(rang, &preflist);
660 |
661 | /* see if there is more than 1 prefix, set the composed flag*/
662 | prefcount = g_list_length(preflist);
663 | leafptr->composed = (prefcount - 1) ;
664 |
665 | leafptr->iprange = *rang;
666 |
667 | #if 0
668 | /* XXX */
669 | if(prefcount==0) {
670 | fprintf(stderr, "**** prefcount=0 range: [%s][%u-%u]\n", buf, (rang->begin).words[0], (rang->end).words[0]);
671 | }
672 | #endif
673 |
674 | if(prefcount==0) {
675 | /* XXX This indicates that some inetnum ranges are not correct (e.g. start>end) */
676 | /* XXX Should not happen and may break normal operation of the rx lookups */
677 | /* XXX maybe we need to die here, but this is too harsh at this point */
678 | IP_rang_b2a(rang, buf, IP_RANGSTR_MAX );
679 | ER_perror(FAC_RX, RX_BADKEY, "prefcount=0 range: [%s][%u-%u]\n",
680 | buf, (rang->begin).words[0], (rang->end).words[0]);
681 | }
682 |
683 |
684 |
685 |
686 | for(i=0; i < prefcount; i++) {
687 | ip_prefix_t *mypref = g_list_nth_data(preflist, i);
688 |
689 | rx_bin_node(mode, mypref, tree, leafptr);
690 | }
691 |
692 | /* free the storage from decomposition*/
693 | wr_clear_list( &preflist );
694 |
695 | return RX_OK;
696 | }