Source File rx/rx_tree.c

    1    | /***************************************
    2    |   $Revision: 1.21 $
    3    |
    4    |   Radix tree (rx).  rx_tree.c - functions to operate on trees
    5    |   (creation/deletion/finding).
    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   | #define RX_IMPL
    33   | #include "rip.h"
    34   |
    35   |
    36   | /*+++++++++
    37   |   go down the tree calling func on every node.
    38   |   (func takes the node pointer and the current level)
    39   |
    40   |   the function is called recursively with level increased
    41   |   it stops recursing when no child nodes are found or maxlevel is reached.
    42   |
    43   |   therefore the initial call must set level to 0.
    44   |
    45   |   the nodecounter increments at every node, and is the return value
    46   |   of the function. So start with 0 to get the number of nodes traversed.
    47   |
    48   |   ERROR HANDLING IS DIFFERENT HERE!
    49   |   Unlike other functions it is not the return value:
    50   |   The error code from the func function IF DEFINED (== not NULL ) goes
    51   |   to the variable pointed to by the last parameter.
    52   |
    53   |   XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from
    54   |        calling parameter list, shane 2001-02-01
    55   | ++++++++++++*/
    56   | int
    57   | rx_walk_tree(rx_node_t *node,
    58   | 	     er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
    59   | 			  void *userptr),
    60   | 	     rx_walk_mt walk_mode,
    61   | 	                     /* controls if glue nodes are counted*/
    62   | 	                     /* and if levels or prefix lenghts are checked*/
    63   | 	     int maxlevel,
    64   | 	     int level,
    65   | 	     int nodecounter,
    66   | 	     void *userptr,
    67   | 	     er_ret_t *err)
    68   | {
    69   | int i, link;
    70   |
    71   |  if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
    72   |
    73   |  /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */
    74   |  /* level otherwise */
    75   |
    76   |  if(walk_mode & RX_WALK_PRFLEN) {
    77   |    if(node->prefix.bits > maxlevel) {
    78   |      return nodecounter;
    79   |    }
    80   |  }
    81   |  else if( level > maxlevel ) {
    82   |    return nodecounter;
    83   |  }
    84   |
    85   |
    86   |  /* process the node appropriately: */
    87   |  /* if (not node glue) or (process glue nodes) */
    88   |
    89   |  if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
    90   |
    91   |    /* increase our depth counter */
    92   |    level++;
    93   |
    94   |    /* increase the count of visited nodes */
    95   |    nodecounter++;
    96   |
    97   |    /* call supplied function, if any */
    98   |    if( func != NULL ) {
    99   |      *err = func(node, level, nodecounter, userptr);
    100  |
    101  |      /* abort the walk on error*/
    102  |      if( *err != RX_OK ) {
    103  |        ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
    104  |   	         "walk_tree: func returned error %d, aborting", *err);
    105  |        return nodecounter;
    106  |      }
    107  |    }
    108  |  }
    109  |
    110  |  /* process left and right children */
    111  |  for(i=0; i<=1; i++) {
    112  |
    113  |    /* reverse the sense of the walk*/
    114  |    link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
    115  |
    116  |    if( node->child_ptr[link] != NULL ) {
    117  |      nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
    118  | 				 maxlevel, level, 0, userptr, err);
    119  |      /* abort the walk on error*/
    120  |      if( func != NULL && *err != RX_OK ) {
    121  |        break;
    122  |      }
    123  |    }
    124  |  }
    125  |
    126  |  /* return count of nodes visited */
    127  |  return nodecounter;
    128  | }
    129  |
    130  | /*+++++++++
    131  |   go down the tree and delete all nodes of the tree.
    132  |
    133  |   the function is called recursively with level increased
    134  |   it stops recursing when no child nodes are found or maxlevel is reached.
    135  |
    136  |   therefore the initial call must set level to 0.
    137  |
    138  |   the nodecounter increments at every node, and is the return value
    139  |   of the function. So start with 0 to get the number of nodes traversed.
    140  |
    141  |   ERROR HANDLING IS DIFFERENT HERE!
    142  |   Unlike other functions it is not the return value:
    143  |   The error code from the func function IF DEFINED (== not NULL ) goes
    144  |   to the variable pointed to by the last parameter.
    145  |
    146  |   XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from
    147  |        calling parameter list, shane 2001-02-01
    148  | ++++++++++++*/
    149  | void rx_delete_dataleaves(void *element_data, void *result_ptr)
    150  | {
    151  | 	rx_dataleaf_t *leafptr = element_data;
    152  | 	rx_tree_t *tree = result_ptr;
    153  |
    154  | 	if(tree->family == RX_FAM_IP ) {
    155  |         /* do not look at the leaf if  RX_FAM_IP */
    156  |         /* Just free the payload, there must be one and just one. */
    157  |            UT_free(leafptr);
    158  |         }
    159  |         else { /* other families */
    160  |           /* if not >composed< then delete dataleaf */
    161  |           if( leafptr->composed == 0 ) {
    162  |              if( leafptr->data_ptr )
    163  | 	         UT_free(leafptr->data_ptr);
    164  |              UT_free(leafptr);
    165  |
    166  |              ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount = 0, removed");
    167  |
    168  |           }
    169  |           /* else decrement the reference number ( == number of prefixes
    170  |              composing the range minus 1 == the >composed< flag */
    171  |           else {
    172  |              leafptr->composed--;
    173  |
    174  |              ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount -- to %d ",
    175  | 		           leafptr->composed );
    176  |           }
    177  |         } /* if family != RX_FAM_IP */
    178  | }
    179  |
    180  | void rx_delete_treenode(rx_tree_t *tree, rx_node_t *curnode)
    181  | {
    182  |      if(curnode->leaves_ptr) {
    183  | 	 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "deleting dataleaves of node at %08x", curnode);
    184  |          g_list_foreach( curnode->leaves_ptr, rx_delete_dataleaves, tree);
    185  | 	 /* delete the GList */
    186  | 	 g_list_free(curnode->leaves_ptr);
    187  |      }
    188  |      ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "node at %08x removed", curnode);
    189  |      UT_free(curnode);
    190  |
    191  | }
    192  |
    193  | /* The fuction itself */
    194  | int
    195  | rx_delete_tree(rx_tree_t *tree, rx_node_t *node,
    196  |              int maxlevel,
    197  | 	     int level,
    198  | 	     int nodecounter,
    199  | 	     void *userptr)
    200  | {
    201  | int i, link;
    202  |
    203  |  if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
    204  |
    205  |  /* check if the level is reached */
    206  |
    207  |  if( level > maxlevel ) {
    208  |    return nodecounter;
    209  |  }
    210  |
    211  |
    212  |  /* process the node appropriately: */
    213  |  /* increase our depth counter */
    214  |  level++;
    215  |
    216  |  /* increase the count of visited nodes */
    217  |  nodecounter++;
    218  |
    219  |
    220  |  /* process left and right children */
    221  |  for(i=0; i<=1; i++) {
    222  |
    223  |    link = i;
    224  |
    225  |    if( node->child_ptr[link] != NULL ) {
    226  |      nodecounter += rx_delete_tree(tree, node->child_ptr[link], maxlevel, level, 0, userptr);
    227  |      /* delete the processed child node */
    228  |      rx_delete_treenode(tree, node->child_ptr[link]);
    229  |    }
    230  |  }
    231  |
    232  |  /* if this is the top level - delete the top node and the tree*/
    233  |  if(node == tree->top_ptr){
    234  | 	 rx_delete_treenode(tree, node);
    235  | 	 tree->top_ptr=NULL;
    236  |  }
    237  |
    238  |  /* return count of nodes deleted */
    239  |  return nodecounter;
    240  | }
    241  |
    242  |
    243  | /***************************************************************************/
    244  | /*++++++
    245  |   creates a (top) tree for the space, fills out sql table of trees
    246  |   generates a tablename for a tree (if NONE)
    247  |   updates LL of trees
    248  |
    249  |   MT-note: locks/unlocks the forest (still to be done)
    250  |
    251  | ++++++++*/
    252  | er_ret_t
    253  | RX_tree_cre (
    254  | 	      char      *prefixstr, /*+ prefix the tree will cover (string) +*/
    255  | 	      rx_fam_t   fam_id,
    256  | 	      rx_mem_mt   mem_mode, /* memory only, memory+sql, sql only +*/
    257  | 	      rx_subtree_mt subtrees,	/*+ one of NONE, AUTO, HAND +*/
    258  | 	      rx_tree_t **treestore /* store the tree pointer here */
    259  | 	     )
    260  |
    261  | {
    262  |   rx_tree_t    *newtree;
    263  |   ip_prefix_t  newpref;
    264  |   ip_space_t   spc_id;
    265  |
    266  |   if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
    267  |     die;
    268  |   }
    269  |
    270  |   spc_id = IP_pref_b2_space( &newpref );
    271  |
    272  |   newtree = (rx_tree_t *)UT_malloc(sizeof(rx_tree_t));
    273  |
    274  |   ER_dbg_va(FAC_RX, ASP_RX_TREE_GEN, "creating a tree at %08x", newtree);
    275  |
    276  |   /* copy tree settings */
    277  |   newtree -> space  = spc_id;
    278  |   newtree -> family = fam_id;
    279  |
    280  |   newtree -> subtrees = subtrees;
    281  |   newtree -> mem_mode = mem_mode;
    282  |
    283  |   /* set other tree values */
    284  |
    285  |   /* parent set to NULL because it's not a subtree */
    286  |   newtree -> parent_tree = NULL;
    287  |   /* PR_zeroprefix(& newtree -> prefix);*/
    288  |   newtree -> maxbits = IP_sizebits(spc_id);
    289  |
    290  |   strcpy(newtree->data_table.val,"");
    291  |   strcpy(newtree->radix_table.val,"");
    292  |   strcpy(newtree->leaves_table.val,"");
    293  |
    294  |   newtree->num_nodes = 0;
    295  |
    296  |   newtree->top_ptr = NULL;
    297  |   newtree->top_key = SQ_NOKEY;
    298  |
    299  |   newtree->prefix = newpref;
    300  |
    301  |   TH_init_read_write_lockw( &(newtree->rwlock));
    302  |
    303  |   *treestore = newtree;
    304  |
    305  |   return RX_OK;
    306  | }
    307  |
    308  |
    309  | /* ************************************
    310  |    special walk function for use in consistency checks - it checks the parent
    311  |    pointer too.
    312  | ************************************/
    313  | int rx_check_walk_tree( rx_node_t *node,
    314  | 			rx_node_t *parent_node,
    315  | 			int nodecounter,
    316  | 			rx_treecheck_t *checkstruct )
    317  | {
    318  | int i;
    319  |
    320  |  /* checks*/
    321  |  if( node == NULL ) {
    322  |    checkstruct->code |= 1;
    323  |  }
    324  |  if( node->parent_ptr != parent_node ) {
    325  |    checkstruct->code |= 2;
    326  |  }
    327  |  if( node->glue && node->leaves_ptr ) {
    328  |    checkstruct->code |= 4;
    329  |  }
    330  |  if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
    331  |    checkstruct->code |= 8;
    332  |  }
    333  |
    334  |
    335  |  if( node->leaves_ptr && checkstruct->datatoo ) {
    336  |    switch( checkstruct->tree->family ) {
    337  |    case  RX_FAM_IP:
    338  |      /* the simplest (?) case: only one leaf attached to any node
    339  | 	(except for glues) */
    340  |      if( g_list_length(node->leaves_ptr) != 1 ) {
    341  |        checkstruct->code |= 16;
    342  |      }
    343  |      break;
    344  |    case RX_FAM_RT:
    345  |      /* many dataleaves attached to nodes. */
    346  |      break;
    347  |    case RX_FAM_IN:
    348  |      /* many dataleaves attached to nodes.
    349  | 	Some leaves pointed to from many nodes => from as many as the number
    350  | 	of composing prefixes
    351  |      */
    352  |      break;
    353  |    default:
    354  |      /* ignore */
    355  |      break;
    356  |    }
    357  |  }
    358  |
    359  |
    360  |  if( checkstruct->code != 0 ) {
    361  |    checkstruct->node = node;
    362  |
    363  |    return nodecounter;          /* abort the walk on error*/
    364  |  }
    365  |
    366  |
    367  |   nodecounter++;
    368  |
    369  |   for(i=0; i<=1; i++) {
    370  |     if( node->child_ptr[i] != NULL ) {
    371  |       nodecounter += rx_check_walk_tree( node->child_ptr[i],
    372  | 					 node,
    373  | 					 0, checkstruct );
    374  |       /* abort the walk on error*/
    375  |       if ( checkstruct->code != 0 ) {
    376  | 	die; break;
    377  |       }
    378  |     }
    379  |   }
    380  |   return nodecounter;
    381  | }
    382  |
    383  | /* **************************************************************************
    384  | tree consistency check.
    385  |
    386  | if datatoo = 0, then only parent/child links are checked.
    387  |
    388  | if datatoo = 1, then a check on the contents of the nodes is done too.
    389  |
    390  | **************************************************************************/
    391  |
    392  | er_ret_t
    393  | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
    394  | {
    395  |   er_ret_t err = RX_OK;
    396  |   int nodnum;
    397  |
    398  |   errorfound->tree = tree;
    399  |   errorfound->datatoo = datatoo;
    400  |
    401  |   /* errorfound.node will be set by hook if it finds an error*/
    402  |   errorfound->code = 0;
    403  |
    404  |   nodnum = rx_check_walk_tree( tree->top_ptr,
    405  | 			       NULL,
    406  | 			       0,
    407  | 			       errorfound );
    408  |
    409  |   if( nodnum != tree->num_nodes ) {
    410  |     errorfound->code |= 1024;
    411  |   }
    412  |   if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
    413  |     errorfound->code |= 2048;
    414  |   }
    415  |   if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
    416  |     errorfound->code |= 4096;
    417  |   }
    418  |
    419  |   if( errorfound->code != 0) {
    420  |     err = RX_DATNOF;
    421  |   }
    422  |   return err;
    423  | }