Source File modules/rx/rx_node.c

    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  |