Source File rx/rx_node.c

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