Source File modules/rx/rx_tree.c

    1    | /***************************************
    2    |   $Revision: 1.15 $
    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                              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 <iproutines.h>
    34   | #include <memwrap.h>
    35   | #include <stubs.h>
    36   |
    37   | /***************************************************************************/
    38   |
    39   | #define RX_IMPL
    40   |
    41   | #include <rxroutines.h>
    42   | /***************************************************************************/
    43   |
    44   |
    45   | /*+++++++++
    46   |   go down the tree calling func on every node.
    47   |   (func takes the node pointer and the current level)
    48   |
    49   |   the function is called recursively with level increased
    50   |   it stops recursing when no child nodes are found or maxlevel is reached.
    51   |
    52   |   therefore the initial call must set level to 0.
    53   |
    54   |   the nodecounter increments at every node, and is the return value
    55   |   of the function. So start with 0 to get the number of nodes traversed.
    56   |
    57   |   ERROR HANDLING IS DIFFERENT HERE!
    58   |   Unlike other functions it is not the return value:
    59   |   The error code from the func function IF DEFINED (== not NULL ) goes
    60   |   to the variable pointed to by the last parameter.
    61   | ++++++++++++*/
    62   | int
    63   | rx_walk_tree(rx_node_t *node,
    64   | 	     er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
    65   | 			  void *userptr),
    66   | 	     rx_walk_mt walk_mode,
    67   | 	                     /* controls if glue nodes are counted*/
    68   | 	                     /* and if levels or prefix lenghts are checked*/
    69   | 	     int maxlevel,
    70   | 	     int level,
    71   | 	     int nodecounter,
    72   | 	     void *userptr,
    73   | 	     er_ret_t *err)
    74   | {
    75   | int i, link, skpglue=0;
    76   |
    77   |  if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
    78   |
    79   |  /* count the node appropriately:*/
    80   |  /* if (not glue) or (it doesn't matter)*/
    81   |
    82   |  if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
    83   |    level++;
    84   |  } else { /* nodeglue = 1 && walkmode&skpglue = 1 */
    85   |    skpglue = 1;
    86   |  }
    87   |
    88   |  /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */
    89   |  /* level otherwise */
    90   |
    91   |  if(walk_mode & RX_WALK_PRFLEN) {
    92   |    if(node->prefix.bits > maxlevel) {
    93   |      return nodecounter;
    94   |    }
    95   |  }
    96   |  else if( level > maxlevel ) {
    97   |    return nodecounter;
    98   |  }
    99   |
    100  |  /* didn't quit ?? OK, count it too...*/
    101  |  if( skpglue == 0 ) {
    102  |    nodecounter++;
    103  |  }
    104  |
    105  |  if( func != NULL && skpglue == 0 ) {
    106  |    *err = func(node, level, nodecounter, userptr);
    107  |
    108  |    /* abort the walk on error*/
    109  |    if( *err != RX_OK ) {
    110  |      ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
    111  | 	       "walk_tree: func returned error %d, aborting", *err);
    112  |      return nodecounter;
    113  |    }
    114  |  }
    115  |
    116  |
    117  |  for(i=0; i<=1; i++) {
    118  |
    119  |    /* reverse the sense of the walk*/
    120  |    link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
    121  |
    122  |    if( node->child_ptr[link] != NULL ) {
    123  |      nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
    124  | 				 maxlevel, level, 0, userptr, err);
    125  |      /* abort the walk on error*/
    126  |      if( func != NULL && *err != RX_OK ) {
    127  |        break;
    128  |      }
    129  |    }
    130  |  }
    131  |
    132  |  return nodecounter;
    133  | }
    134  |
    135  |
    136  |
    137  | /***************************************************************************/
    138  | /*++++++
    139  |   creates a (top) tree for the space, fills out sql table of trees
    140  |   generates a tablename for a tree (if NONE)
    141  |   updates LL of trees
    142  |
    143  |   MT-note: locks/unlocks the forest (still to be done)
    144  |
    145  | ++++++++*/
    146  | er_ret_t
    147  | RX_tree_cre (
    148  | 	      char      *prefixstr, /*+ prefix the tree will cover (string) +*/
    149  | 	      rx_fam_t   fam_id,
    150  | 	      rx_mem_mt   mem_mode, /* memory only, memory+sql, sql only +*/
    151  | 	      rx_subtree_mt subtrees,	/*+ one of NONE, AUTO, HAND +*/
    152  | 	      rx_tree_t **treestore /* store the tree pointer here */
    153  | 	     )
    154  |
    155  | {
    156  |   er_ret_t     err;
    157  |   rx_tree_t    *newtree;
    158  |   ip_prefix_t  newpref;
    159  |   ip_space_t   spc_id;
    160  |
    161  |   if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
    162  |     die;
    163  |   }
    164  |
    165  |   spc_id = IP_pref_b2_space( &newpref );
    166  |
    167  |   if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
    168  |     return err;  /* die*/
    169  |   }
    170  |
    171  |   ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree);
    172  |
    173  |   /* copy tree settings */
    174  |   newtree -> space  = spc_id;
    175  |   newtree -> family = fam_id;
    176  |
    177  |   newtree -> subtrees = subtrees;
    178  |   newtree -> mem_mode = mem_mode;
    179  |
    180  |   /* set other tree values */
    181  |
    182  |   /* parent set to NULL because it's not a subtree */
    183  |   newtree -> parent_tree = NULL;
    184  |   /* PR_zeroprefix(& newtree -> prefix);*/
    185  |   newtree -> maxbits = IP_sizebits(spc_id);
    186  |
    187  |   strcpy(newtree->data_table.val,"");
    188  |   strcpy(newtree->radix_table.val,"");
    189  |   strcpy(newtree->leaves_table.val,"");
    190  |
    191  |   newtree->num_nodes = 0;
    192  |
    193  |   newtree->top_ptr = NULL;
    194  |   newtree->top_key = SQ_NOKEY;
    195  |
    196  |   newtree->prefix = newpref;
    197  |
    198  |   TH_init_read_write_lock( &(newtree->rwlock));
    199  |
    200  |   *treestore = newtree;
    201  |
    202  |   return RX_OK;
    203  | }
    204  |
    205  |
    206  | /* ************************************
    207  |    special walk function for use in consistency checks - it checks the parent
    208  |    pointer too.
    209  | ************************************/
    210  | int rx_check_walk_tree( rx_node_t *node,
    211  | 			rx_node_t *parent_node,
    212  | 			int nodecounter,
    213  | 			rx_treecheck_t *checkstruct )
    214  | {
    215  | int i;
    216  |
    217  |  /* checks*/
    218  |  if( node == NULL ) {
    219  |    checkstruct->code |= 1;
    220  |  }
    221  |  if( node->parent_ptr != parent_node ) {
    222  |    checkstruct->code |= 2;
    223  |  }
    224  |  if( node->glue && node->leaves_ptr ) {
    225  |    checkstruct->code |= 4;
    226  |  }
    227  |  if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
    228  |    checkstruct->code |= 8;
    229  |  }
    230  |
    231  |
    232  |  if( node->leaves_ptr && checkstruct->datatoo ) {
    233  |    switch( checkstruct->tree->family ) {
    234  |    case  RX_FAM_IP:
    235  |      /* the simplest (?) case: only one leaf attached to any node
    236  | 	(except for glues) */
    237  |      if( g_list_length(node->leaves_ptr) != 1 ) {
    238  |        checkstruct->code |= 16;
    239  |      }
    240  |      break;
    241  |    case RX_FAM_RT:
    242  |      /* many dataleaves attached to nodes. */
    243  |      break;
    244  |    case RX_FAM_IN:
    245  |      /* many dataleaves attached to nodes.
    246  | 	Some leaves pointed to from many nodes => from as many as the number
    247  | 	of composing prefixes
    248  |      */
    249  |      break;
    250  |    default:
    251  |      /* ignore */
    252  |      break;
    253  |    }
    254  |  }
    255  |
    256  |
    257  |  if( checkstruct->code != 0 ) {
    258  |    checkstruct->node = node;
    259  |
    260  |    return nodecounter;          /* abort the walk on error*/
    261  |  }
    262  |
    263  |
    264  |   nodecounter++;
    265  |
    266  |   for(i=0; i<=1; i++) {
    267  |     if( node->child_ptr[i] != NULL ) {
    268  |       nodecounter += rx_check_walk_tree( node->child_ptr[i],
    269  | 					 node,
    270  | 					 0, checkstruct );
    271  |       /* abort the walk on error*/
    272  |       if ( checkstruct->code != 0 ) {
    273  | 	break;
    274  |       }
    275  |     }
    276  |   }
    277  |   return nodecounter;
    278  | }
    279  |
    280  | /* **************************************************************************
    281  | tree consistency check.
    282  |
    283  | if datatoo = 0, then only parent/child links are checked.
    284  |
    285  | if datatoo = 1, then a check on the contents of the nodes is done too.
    286  |
    287  | **************************************************************************/
    288  |
    289  | er_ret_t
    290  | RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
    291  | {
    292  |   er_ret_t err = RX_OK;
    293  |   int nodnum;
    294  |
    295  |   errorfound->tree = tree;
    296  |   errorfound->datatoo = datatoo;
    297  |
    298  |   /* errorfound.node will be set by hook if it finds an error*/
    299  |   errorfound->code = 0;
    300  |
    301  |   nodnum = rx_check_walk_tree( tree->top_ptr,
    302  | 			       NULL,
    303  | 			       0,
    304  | 			       errorfound );
    305  |
    306  |   if( nodnum != tree->num_nodes ) {
    307  |     errorfound->code |= 1024;
    308  |   }
    309  |   if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
    310  |     errorfound->code |= 2048;
    311  |   }
    312  |   if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
    313  |     errorfound->code |= 4096;
    314  |   }
    315  |
    316  |   if( errorfound->code != 0) {
    317  |     err = RX_DATNOF;
    318  |   }
    319  |   return err;
    320  | }