1 | /*************************************** 2 | $Revision: 1.10 $ 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 | int 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_BOT, "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_BOT, "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_BOT, "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_BOT, "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 | /*+ hook for g_list_foreach to free a list element +*/ 287 | 288 | void 289 | rx_free_list_element(void *cpy, void *trash) 290 | { 291 | wr_free(cpy); 292 | } 293 | 294 | /***************************************************************************/ 295 | /*+++++++++++++++++++ 296 | 297 | General function to operate on dataleaves attached to a single node 298 | (create / modify / delete). 299 | 300 | searches tree, finds and creates (modifies/deletes) a node, 301 | copies modified nodes to disk using rx_sql_node_set (not yet implemented). 302 | Updates memory rollback info. 303 | 304 | Currently only creation is implemented. 305 | 306 | Add a dataleaf at node defined by prefix. Create a new node if it doesn't 307 | exist yet. 308 | 309 | MT notes: requires the tree to be locked. 310 | 311 | Returns: RX_OK or error code. 312 | 313 | Errors from: 314 | rx_bin_search, 315 | memory alloc routines. 316 | 317 | - no such node (if not in create mode) 318 | 319 | - too many nodes found (strange). 320 | 321 | +++++++++++++++++*/ 322 | 323 | er_ret_t 324 | RX_bin_node ( 325 | rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/ 326 | ip_prefix_t *newpref, /*+ prefix of the node +*/ 327 | rx_tree_t *tree, /*+ pointer to the tree structure +*/ 328 | rx_dataleaf_t *dataleaf /*+ dataleaf to attach at the node +*/ 329 | ) 330 | 331 | { 332 | GList *nodlist = NULL; 333 | int nodesfound, stackdepth; 334 | int glue; 335 | rx_nodcpy_t *curcpy; 336 | rx_node_t *curnode; 337 | rx_nodcpy_t *stack; 338 | er_ret_t err; 339 | char bbf[IP_PREFSTR_MAX]; 340 | 341 | 342 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) { 343 | IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX); 344 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 345 | "rx_bin_node: new %s in spc %d /fam %d /reg %d", 346 | bbf, tree->space, tree->family, tree->reg_id); 347 | } 348 | 349 | // first check: are we using the correct tree ??? 350 | if( tree->space != newpref->ip.space ) { 351 | /* trying to insert a prefix of space %d into a tree of space %d\n", 352 | tree->space, 353 | newpref->ip.space); 354 | */ 355 | die; 356 | } 357 | 358 | assert( newpref->bits <= IP_sizebits(tree->space) ); 359 | 360 | // fix the prefix, to make sure all insignificant bits are 0 361 | IP_pref_bit_fix( newpref ); 362 | 363 | if( (err=wr_malloc( (void **) &stack, 364 | sizeof(rx_nodcpy_t) * IP_sizebits(tree->space))) != UT_OK) { 365 | return err; //die; 366 | } 367 | 368 | if( (err=rx_build_stack(stack, &stackdepth, 369 | tree, newpref, RX_STK_CREAT) != RX_OK )) { 370 | return err; //die 371 | } 372 | 373 | // rx_stk_print(stack, stackdepth); 374 | 375 | // perform a search on the stack. The result is a list, and it must 376 | // be properly deleted after use!! 377 | 378 | if( rx_nod_search(RX_SRCH_CREAT, 0, 0, 379 | tree, newpref, stack, stackdepth, 380 | &nodlist, RX_ANS_ALL) != RX_OK ) { 381 | return err; // die; 382 | } 383 | 384 | 385 | // count number of nodes in the answer 386 | nodesfound = g_list_length (nodlist); 387 | 388 | switch( nodesfound ) { 389 | case 0: 390 | /* no such node (yet). See what we're up to. 391 | if( mode==cre ) create, else - program error, die */ 392 | 393 | if( mode != RX_OPER_CRE) { 394 | die; 395 | } 396 | 397 | /* C R E A T I O N */ 398 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 399 | "Creating a new node "); 400 | rx_creat_node( newpref, tree, dataleaf, stack, stackdepth ); 401 | break; 402 | case 1: /* found */ 403 | switch( mode ) { 404 | case RX_OPER_CRE: 405 | // attach the data at the node that was found; 406 | 407 | curcpy = g_list_nth_data(nodlist, 0); 408 | 409 | curnode = curcpy->srcptr; 410 | // was it glue ? 411 | glue = curnode->glue; 412 | 413 | curnode->leaves_ptr = g_list_prepend(curnode->leaves_ptr, dataleaf); 414 | // not it's not a glue anymore 415 | curnode->glue = 0; 416 | 417 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, "Appended data to a %s node", 418 | glue ? "glue" : "data"); 419 | 420 | break; 421 | case RX_OPER_MOD: 422 | // put new data in; 423 | break; 424 | case RX_OPER_DEL: 425 | break; 426 | // fine, check the number of children: 427 | // 0 - just delete, 428 | // 1 - copy the child's link to parent. then delete 429 | // 2 - turn into a glue 430 | } 431 | break; 432 | default: 433 | /* too many nodes found! from an exact/exact-less-1 search. 434 | this cannot happen. Call Ghostbusters now. 435 | */ 436 | die; 437 | } 438 | 439 | g_list_foreach(nodlist, rx_free_list_element, NULL); 440 | 441 | wr_free(stack); 442 | return RX_OK; 443 | } 444 | 445 | /***************************************************************************/ 446 | /*+++++++++++++++ 447 | performs the actual update for inetnums (possibly composed of many prefixes). 448 | Decomposes the ranges into prefixes and then falls back to rx_bin_node 449 | to perform changes at the nodes. 450 | 451 | Requires/returns - practically the same as rx_bin_node. 452 | ++++++++++++++++*/ 453 | 454 | er_ret_t 455 | RX_inum_node( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/ 456 | ip_range_t *rang, /*+ range of IP addresses +*/ 457 | rx_tree_t *tree, /*+ pointer to the tree structure +*/ 458 | rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/ 459 | ) 460 | { 461 | int i, prefcount; 462 | GList *preflist = NULL; 463 | char buf[IP_RANGSTR_MAX]; 464 | 465 | if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_BOT)) { 466 | IP_rang_b2a(rang, buf, IP_RANGSTR_MAX ); 467 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 468 | "rx_inum_node: adding %s", buf); 469 | } 470 | 471 | // decompose, put links to the data leaf into every prefix 472 | // that makes up this range. 473 | IP_rang_decomp(rang, &preflist); 474 | 475 | // see if there is more than 1 prefix, set the composed flag 476 | prefcount = g_list_length(preflist); 477 | leafptr->composed = (prefcount > 1) ; 478 | 479 | leafptr->iprange = *rang; 480 | 481 | for(i=0; i < prefcount; i++) { 482 | ip_prefix_t *mypref = g_list_nth_data(preflist, i); 483 | 484 | RX_bin_node(mode, mypref, tree, leafptr); 485 | } 486 | 487 | // free the storage from decomposition 488 | g_list_foreach(preflist, rx_free_list_element, NULL); 489 | g_list_free(preflist); 490 | 491 | return RX_OK; 492 | } 493 | 494 | 495 | /***************************************************************************/ 496 | /*+++++++++++++++ 497 | translates ranges/prefixes into binary prefixes. 498 | finds tree, locks it. 499 | initiates memory rollback structure (???) 500 | 501 | builds a dataleaf and puts into the node(s), 502 | calling rx_bin_node for every prefix. 503 | 504 | checks rollback condition and (possibly) rolls back ??? 505 | 506 | MT-note: locks/unlocks the tree. 507 | 508 | Possible errors 509 | - all errors from: 510 | ip_asc_2_bin, 511 | rx_get_tree, 512 | rx_bin_node, 513 | wr_free 514 | 515 | +++++++++++++++++*/ 516 | er_ret_t 517 | RX_asc_node ( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/ 518 | char *rangstr, /*+ string prefix/range/IP +*/ 519 | rx_regid_t reg_id, /*+ id of the registry +*/ 520 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/ 521 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/ 522 | void *data /*+ pointer to the payload +*/ 523 | ) 524 | 525 | { 526 | 527 | /* 528 | For creation of a new node: 529 | 530 | READ-LOCK THE FOREST 531 | 532 | get the root tree for this space (rx_get_tree) 533 | got it ? good. No ? error!!! 534 | 535 | Check if any of the prefixes spans more than one subtree... 536 | Check if they all exist already.. 537 | 538 | if any is missing 539 | then 540 | WRITE-LOCK THE FOREST 541 | fi 542 | 543 | for all missing subtrees 544 | create missing trees 545 | rof 546 | 547 | UNLOCK THE FOREST 548 | 549 | **now start writing the data:** 550 | 551 | put *data* records in memory and sql table 552 | 553 | for all matchind [sub]trees (in order of the list) 554 | WRITE-LOCK the in-memory [sub]tree 555 | WRITE-LOCK the sql-table for it 556 | 557 | for(all prefixes in memory that match this tree) 558 | create a node in the tree pointing to the data 559 | rof 560 | UNLOCK the tree 561 | rof 562 | 563 | 564 | */ 565 | 566 | 567 | ip_range_t myrang; 568 | ip_prefix_t mypref; 569 | rx_dataleaf_t *leafptr; 570 | rx_tree_t *mytree; 571 | int rang_ok; 572 | 573 | if( RX_get_tree ( &mytree, reg_id, spc_id, fam_id) != RX_OK ) { 574 | die; 575 | } 576 | 577 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 578 | "rx_asc_node: inserting object %s", rangstr); 579 | 580 | // set the data leaf values 581 | if( wr_calloc( (void **)& leafptr, sizeof(rx_dataleaf_t), 1) 582 | != UT_OK) { 583 | die; 584 | } 585 | 586 | leafptr->data_ptr = data; 587 | 588 | switch( fam_id ) 589 | { 590 | case RX_FAM_IN: 591 | rang_ok = 1; 592 | 593 | if( IP_rang_e2b(&myrang, rangstr) == IP_OK ) { 594 | // that's nice. everything is set. 595 | } else { 596 | // see if's a valid IP, maybe it's an IPv4 classful range 597 | if( IP_addr_e2b( &myrang.begin, rangstr ) == IP_OK ) { 598 | if( IP_rang_classful( &myrang , &myrang.begin ) != IP_OK ) { 599 | rang_ok = 0; 600 | } 601 | } 602 | else { 603 | // sorry. we don't accept that. 604 | rang_ok = 0; 605 | } 606 | } 607 | 608 | if( rang_ok == 1 ) { 609 | return RX_inum_node( mode, &myrang, mytree, leafptr ); 610 | } 611 | // else: fall through to the end of the function. (unrecognized arg) 612 | 613 | break; 614 | 615 | case RX_FAM_RT: 616 | if( IP_pref_e2b(&mypref, rangstr) == IP_OK ) { 617 | return RX_bin_node(RX_OPER_CRE, &mypref, mytree, leafptr); 618 | } 619 | } 620 | 621 | ER_dbg_va(FAC_RX, ASP_RX_NODCRE_BOT, 622 | "can't understand the key, discarding the OBJECT."); 623 | wr_free(data); 624 | wr_free(leafptr); 625 | 626 | return RX_BADKEY; 627 | } 628 |