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