modules/rx/rx_node.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rx_creat_node
- rx_delete_node
- rx_bin_node
- RX_rt_node
- RX_in_node
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 (
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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 (
/* [<][>][^][v][top][bottom][index][help] */
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 (
/* [<][>][^][v][top][bottom][index][help] */
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} +*/
/* [<][>][^][v][top][bottom][index][help] */
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 }