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 | }