home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / mrdebug.tar.Z / mrdebug.tar / build_adj.c < prev    next >
C/C++ Source or Header  |  1993-10-25  |  24KB  |  758 lines

  1. /************************************************************************
  2.  
  3.     PURPOSE:  Graph Parser, build adjacency list.
  4.  
  5.     DESCRIPTION:
  6.         This program reads in a file containing a description of
  7.         the network and another file containing a list of the
  8.         subnets.  The name of the file to read is supplied as an
  9.         argument when the program is called.  In the file,
  10.         the represention is:
  11.  
  12.         Equivalent Nodes
  13.         = node1 node2       (these interfaces are at the same physical
  14.                              site.  Each line is assumed to only
  15.                      contain 2 node names)
  16.         Non-responding Node
  17.         ? node              (this node did not respond to the mapper
  18.                              query)
  19.         Edge of the Network
  20.         > node1 node2 info  (the edge is from node1 to node2 the
  21.                              info is [metric/threshold/type] where
  22.                      type is one or more of down, disabled,
  23.                      tunnel, querier, and srcrt)
  24.  
  25.     METHODOLOGY:
  26.             The program first reads in the subnets.  Then
  27.         the network description file is read through once to
  28.         determine the size of the adjacency list (number of
  29.         sites).  The adjacency list is then allocated and the
  30.         interfaces are added to each node of the adjacency list.
  31.         Subnets for these interfaces and a hash table for
  32.         conversion from interface names to adjacency list nodes
  33.         are also built at this time.
  34.  
  35.         The network description file is now reread to build the
  36.         network.  Each edge is added to the adjacency list as
  37.         it is read in.  If the destination node of the edge is
  38.         a node that did not respond to the mapper, add a backwards
  39.         edge also but mark it as questionable.
  40.  
  41.     PROGRAMMER:  Deb Agarwal        6/1993
  42.  
  43. ***********************************************************************/
  44.  
  45. #include    <stdio.h>
  46. #include    <string.h>
  47.  
  48. #include       "types.h"
  49. #include       "mrhash.h"
  50. #include       "data_struct_proto.h"
  51. #include       "build_adj_proto.h"
  52.  
  53. /******* GLOBAL VARIABLES *********/
  54. Ifc_list       invisib_ifcs;
  55.  
  56. /********* EXTERNAL REFERENCES ***********/
  57. extern          int       verbose;
  58.  
  59. /*******************************************************************
  60.  
  61.         PROCEDURE:  read_subnets( subnet_fl, subnets )
  62.  
  63.     DESCRIPTION:
  64.              This program reads in the network subnets from a file.
  65.          The subnets as they are read in will be stored in a
  66.          linked list for future use.  The subnet file is assumed
  67.          to be arranged by increasing mask size.  
  68.  
  69. ********************************************************************/
  70.  
  71. void    read_subnets( char *subnet_fl, Ifc_list *subnets )
  72. {
  73.         int         args;
  74.         FILE       *subnet_list;
  75.         char        cur_line[MAXLINE];
  76.         Interface  *cur_ifc;
  77.         NAME        full_name;
  78.     
  79.     /*
  80.     **    open the subnet file
  81.     */
  82.     if( !(subnet_list = fopen( subnet_fl, "r" )))
  83.         {
  84.         printf( "ERROR: Unable to open input file named %s\n", subnet_fl);
  85.         exit(-1);
  86.         }
  87.  
  88.     subnets->number = 0;
  89.     subnets->first = NULL;
  90.  
  91.     /*
  92.     **     Read the file all the way through and get
  93.     **     all the subnet names and determine their masks.
  94.     **     They are sorted in decreasing mask order.
  95.     */
  96.     while( fgets( cur_line, MAXLINE, subnet_list ) != NULL )
  97.         {
  98.         args = sscanf( cur_line, "%s", &full_name );
  99.         if( args < 1 )
  100.            continue;
  101.         cur_ifc = (Interface *)calloc( 1, sizeof( Interface ));
  102.         strcpy( cur_ifc->name, full_name );
  103.         inet_parse(full_name, &cur_ifc->address, &cur_ifc->mask);
  104.         if( cur_ifc->mask != 0xffffffff )
  105.            {
  106.            cur_ifc->next = subnets->first;
  107.            subnets->first = cur_ifc;
  108.            subnets->number++;
  109.            }
  110.         else
  111.            free( cur_ifc );
  112.             }
  113. }
  114.    
  115. /*******************************************************************
  116.  
  117.     PROCEDURE:  read_file( edge_fl, net, subnets )
  118.     
  119.     DESCRIPTION:
  120.         This program opens the file containing the network's
  121.         edge list and reads it in.  It then allocates the
  122.         adjacency list and maps the ip
  123.         names to an internal representation and builds
  124.         mapping functions for going either direction.
  125.  
  126. *********************************************************************/
  127.  
  128. void    read_file( char *edge_fl, Network *net, Ifc_list *subnets, long extra_nodes )
  129. {
  130.     FILE        *edge_list;
  131.     Ifc_list     names;
  132.     char         cur_line[MAXLINE];
  133.     char         *line_type;
  134.     char         *ip_name = 0, *ip_name2 = 0;
  135.     int           i;
  136.     Interface   *cur_ifc, *back_ifc, *temp_ifc;
  137.     Equivalence *first_equiv, *cur_equiv, *next_equiv;
  138.     HENTRY_t    *ht_entry_p;
  139.     
  140.     /*
  141.     **    open the edge file
  142.     */
  143.     if( !(edge_list = fopen( edge_fl, "r" )))
  144.         {
  145.         printf( "ERROR: Unable to open input file named %s\n", edge_fl);
  146.         exit(-1);
  147.         }
  148.  
  149.     /*
  150.     **     Initialize network structures that need to be initialized
  151.     */
  152.     net->changes.number = 0;
  153.     net->changes.last = NULL;
  154.     names.number = 0;
  155.     names.first = NULL;
  156.     first_equiv = NULL;
  157.  
  158.     /*
  159.     **     First read the file all the way through and get
  160.     **     all the ip names in a sorted linked list.
  161.     **     They are sorted in reverse order and duplicates
  162.     **     have been discarded.  The list is stored in
  163.     **     nodes.
  164.     */
  165.     while( fgets( cur_line, MAXLINE, edge_list ) != NULL )
  166.         {
  167.         line_type = strtok( cur_line, " \t\n");
  168.         ip_name = strtok( NULL, " \t\n" );
  169.         if( line_type == NULL || ip_name == NULL )
  170.            continue;
  171.         insert_name( &names, ip_name );
  172.         switch( line_type[0] )
  173.            {
  174.             case '>':
  175.                 /* Register both ends of the network connection */
  176.             ip_name = strtok( NULL, " \t\n" );
  177.             insert_name( &names, ip_name );
  178.             break;
  179.             case '=':
  180.                 /* remember the nodes with multiple interfaces */
  181.             ip_name2 = strtok( NULL, " \t\n" );
  182.             insert_name( &names, ip_name2 );
  183.             add_equivalence( &first_equiv, ip_name, ip_name2 );
  184.             break;
  185.             case '?':
  186.             /* This node did not respond to the mapper query */
  187.             insert_name( &invisib_ifcs, ip_name );
  188.             break;
  189.            }
  190.         }
  191.     fclose( edge_list );
  192.     net->no_interfaces = names.number;
  193.     /*
  194.     **    Now to delete the additional interfaces for each node
  195.     **      that had an equivalence specified.
  196.     */
  197.     for( cur_equiv = first_equiv; cur_equiv != NULL; 
  198.                     cur_equiv = cur_equiv->next )
  199.        if( cur_equiv->ifcs.first != NULL )
  200.           for( cur_ifc = cur_equiv->ifcs.first->next; cur_ifc != NULL;
  201.            cur_ifc = cur_ifc->next )
  202.         delete_name( &names, cur_ifc->name );
  203.     delete_name( &names, "0.0.0.0" );
  204.  
  205.     net->no_nodes = names.number + subnets->number;
  206.     net->no_alloc = net->no_nodes + extra_nodes;
  207.     /*
  208.     **     Allocate the adjacency list for the network
  209.     */
  210.     net->adj_list = (Node *)calloc( net->no_alloc, sizeof(Node));
  211.     create_htable( &net->name_map, NAMEMAP_HTABLE_SIZE );
  212.     create_htable( &net->ip_map, NAMEMAP_HTABLE_SIZE );
  213.     /*
  214.     **      Now to create nodes for each of the subnets and enter
  215.     **      them in the map from internal node representations.
  216.     */
  217.     cur_ifc = subnets->first;
  218.     for( i = 0; i < subnets->number; i++, cur_ifc = cur_ifc->next )
  219.        {
  220.        insert_htable( &net->name_map, cur_ifc->name, i, (long *)cur_ifc, NULL );
  221.        if( find_ip_name( cur_ifc->name, ip_name ))
  222.           insert_htable( &net->ip_map, ip_name, i, (long *)cur_ifc, cur_ifc->name );
  223.        net->adj_list[i].type = SUBNET;
  224.        }
  225.     /*
  226.     **      Now to create the mapping from IP names to my
  227.     **      own internal node representations.  Since the IP
  228.     **      names are not consecutive, they are stored in a
  229.     **      hash table. Also create edges to the subnets for
  230.     **      each of the interfaces that have a subnet.  Assume
  231.     **      for now these edges have metric = 1 and threshold = 1.
  232.     */
  233.     cur_ifc = names.first;
  234.     for( i = subnets->number; i < (names.number+subnets->number); i++ )
  235.         {
  236.         temp_ifc = find_subnet( cur_ifc->name, subnets );
  237.         insert_htable( &net->name_map, cur_ifc->name, i, (long *)temp_ifc, NULL  );
  238.         if( find_ip_name( cur_ifc->name, ip_name ))
  239.            insert_htable( &net->ip_map, ip_name, i, (long *)temp_ifc, cur_ifc->name );
  240.         net->adj_list[i].type = ROUTER;
  241.         if( temp_ifc != NULL )
  242.            {
  243.            /* Add the edge to the subnet node */
  244.            add_ifc( net, cur_ifc->name,  temp_ifc->name, "[1/1/suspect]", TRUE );
  245.            add_ifc( net, temp_ifc->name, cur_ifc->name, "[0/0]", FALSE);
  246.            }
  247.         
  248.         /*
  249.         ** start with the assumption that subnet interfaces are suspect
  250.         ** until find an input line indicating otherwise
  251.         */
  252.         temp_ifc = cur_ifc;
  253.         cur_ifc = cur_ifc->next;
  254.         free( temp_ifc );
  255.         }
  256.     names.first = NULL;
  257.     /*
  258.     **    Now to add the mapping entries for the equivalent IP names
  259.     */
  260.     for( cur_equiv = first_equiv; cur_equiv != NULL; cur_equiv = next_equiv)
  261.        {
  262.        if( cur_equiv->ifcs.first != NULL )
  263.           {
  264.           ht_entry_p = lookup_htable( &net->name_map, cur_equiv->ifcs.first->name );
  265.           for( cur_ifc = cur_equiv->ifcs.first->next; cur_ifc != NULL;
  266.            cur_ifc = temp_ifc )
  267.          {
  268.          if( lookup_htable( &net->name_map, cur_ifc->name ) != NULL )
  269.             printf( "This entry already exists?\n");
  270.          back_ifc = find_subnet( cur_ifc->name, subnets );
  271.          insert_htable( &net->name_map, cur_ifc->name, ht_entry_p->index,
  272.                     (long *)back_ifc, NULL );
  273.          if( find_ip_name( cur_ifc->name, ip_name ))
  274.            insert_htable( &net->ip_map, ip_name, ht_entry_p->index,
  275.                   (long *)back_ifc, cur_ifc->name );
  276.          temp_ifc = cur_ifc->next;
  277.          if( back_ifc != NULL )
  278.             {
  279.             /* Add the edge to the subnet node */
  280.             add_ifc( net, cur_ifc->name, back_ifc->name, "[1/1/suspect]", TRUE );
  281.             add_ifc( net, back_ifc->name, cur_ifc->name, "[0/0]", FALSE);
  282.             }
  283.          free( cur_ifc );
  284.              }
  285.           free( cur_equiv->ifcs.first );
  286.           }
  287.        next_equiv = cur_equiv->next;
  288.        free( cur_equiv );
  289.        }
  290.         
  291.     /*print_htable( &net->name_map );*/
  292.  
  293. }
  294.  
  295.  
  296.  
  297. /*****************************************************************************
  298. **
  299.         PROGRAM:   build_adj( file, network )
  300.  
  301.     DESCRIPTION:
  302.         This program rereads the network description and
  303.         builds the adjacency list.  Interfaces specified as 0.0.0.0
  304.         are assumed not to exist.  Each tunnel is treated
  305.         as a separate interface for symmetry in using the
  306.         adjacency list later.  The program assumes that neighbors
  307.         on each subnet are enumerated in the edge descriptions.
  308.  
  309. *******************************************************************************/
  310. void    build_adj( char *edge_fl, Network *net, FILE *out )
  311. {
  312.         int          args;
  313.     FILE        *edge_list;
  314.     char         cur_line[MAXLINE];
  315.     char         line_type, other[MAXLINE];
  316.     NAME         frm_ip_name, ip_name, temp_name;
  317.     HENTRY_t    *ht_entry_p;
  318.     Interface   *frm_ifc, *to_ifc;
  319.  
  320.     /****** reopen the edge file *****/
  321.     if( !(edge_list = fopen( edge_fl, "r" )))
  322.                 {
  323.                 printf( "ERROR: Unable to open input file named %s\n", edge_fl);
  324.                 exit(-1);
  325.                 }
  326.  
  327.     while( fgets( cur_line, MAXLINE, edge_list ) != NULL )
  328.         {
  329.         args = sscanf( cur_line, "%c", &line_type );
  330.         if( args < 1 )
  331.            continue;
  332.         if( line_type == '>' )
  333.            {/*
  334.             **   Find the interface associated with the from address
  335.             */
  336.            sscanf( cur_line, "%c%s%s%s", &line_type, frm_ip_name, ip_name, other );
  337.  
  338.            /*
  339.            **      If this edge has a 0.0.0.0 address as its to end,
  340.            **      then do not add it to the graph.  It was simply used
  341.            **      to register the fact that this interface is a querier
  342.            **      for the subnet.
  343.            */
  344.            if( !find_ip_name( ip_name, temp_name ))
  345.               strcpy( temp_name, ip_name );
  346.            if( !strcmp( temp_name, "0.0.0.0" ))
  347.               {
  348.               ht_entry_p =  lookup_htable( &net->name_map, frm_ip_name );
  349.               to_ifc = (Interface *)ht_entry_p->subnet;
  350.               if( to_ifc == NULL )
  351.              {
  352.              if( verbose )
  353.                 printf( "subnet for %s unknown\n", frm_ip_name );
  354.              continue;
  355.                  }
  356.               frm_ifc = find_ifc( net, NULL, frm_ip_name, to_ifc->name );
  357.               frm_ifc->type &= ~SUSPECT;
  358.               sscanf( other, "[%ld/%ld", &frm_ifc->metric, &frm_ifc->threshold );
  359.               /*printf( "other = %s\n", other );*/
  360.               if( strstr( other, "querier" ) != NULL )
  361.              frm_ifc->type |= QUERIER;
  362.               if( strstr( other, "down" ) != NULL )
  363.              frm_ifc->type |= DOWN;
  364.               if( strstr( other, "disabled" ) != NULL )
  365.              frm_ifc->type |= DISABLED;
  366.               continue;
  367.               }
  368.            /*
  369.            **     Try to add this edge to the network as not suspect
  370.            **     if a NULL is returned, the edge is already in the
  371.            **     network.
  372.            */
  373.            frm_ifc = add_ifc( net, frm_ip_name, ip_name, other, FALSE );
  374.            if( frm_ifc == NULL )
  375.               continue;
  376.  
  377.            if( find_name( &invisib_ifcs, frm_ifc->to_name ) &&
  378.                (frm_ifc->type & TUNNEL))
  379.               {/*
  380.                **    This interface did not respond to the mapper
  381.                **    query so add the edge the other direction with
  382.                **    unknown metric and threshold.
  383.                */
  384.                to_ifc = add_ifc( net, ip_name, frm_ip_name, other, TRUE );
  385.                }
  386.            }
  387.             }
  388.     fclose( edge_list );
  389.     fflush( stdout );
  390. }
  391.  
  392. /******************************************************************************
  393.  
  394.     PROCEDURE:  Print_adj( net, out )
  395.  
  396.     DESCRIPTION:
  397.         This routine prints out the adjacency list of the given graph.
  398.         The form it uses is node -> node, node, node, . . .
  399.         It will print it using the original node numbers provided with
  400.         the graph.  It will break long lines at 10 nodes.
  401.  
  402. *******************************************************************************/
  403. void    Print_adj( Network *net_p, FILE *out )
  404. {
  405.     int          i;
  406.  
  407.     for( i=0; i< net_p->no_nodes;i++)
  408.         print_node( net_p, i, out );
  409.  }
  410. /*******************************************************************************
  411.  
  412.   FUNCTION: print_node( net, node, out )
  413.  
  414.   DESCRIPTION:
  415.        This function prints out the adjacency list for the specified node.
  416.  
  417. *********************************************************************************/
  418.  
  419. void  print_node( Network *net_p, int i, FILE *out )
  420. {  
  421.     Interface   *curifc_p;
  422.  
  423.  
  424.     fprintf(out, "\nNODE %d: distance = %ld", i, net_p->adj_list[i].dist_vects.distance );
  425.     for( curifc_p = net_p->adj_list[i].interfaces.first; curifc_p != NULL;
  426.     curifc_p = curifc_p->next )
  427.        {
  428.        fprintf( out, "\nname=%s mask=%x type=%x m/t=%ld/%ld, ",
  429.             curifc_p->name, curifc_p->mask,
  430.             curifc_p->type, curifc_p->metric, curifc_p->threshold );
  431.        fprintf( out, "->");
  432.        fprintf( out, ", %s", curifc_p->to_name);
  433.        }
  434.     fprintf( out, "\n");
  435.     return;
  436. }
  437.  
  438. /****************************************************************
  439.  
  440.   This procedure finds the appropriate subnet associated with the
  441.   address passed in and returns a pointer to the subnet interface.  If
  442.   multiple subnets match this address, the longest fit will be returned.
  443.   A value of NULL is returned if no match is found.
  444.  
  445. *****************************************************************/
  446.  
  447. Interface  *find_subnet( NAME name, Ifc_list *subnets )
  448. {
  449.    Interface *cur_ifc;
  450.    ADDRESS    address, mask;
  451.  
  452.    inet_parse( name, &address, &mask );
  453.    for( cur_ifc = subnets->first; cur_ifc != NULL; cur_ifc = cur_ifc->next)
  454.       {
  455.       if( (cur_ifc->mask & address) == cur_ifc->address )
  456.      return  cur_ifc;
  457.       }
  458.    return NULL;
  459. }
  460.  
  461. /**************************************************************************
  462.  
  463.   FUNCTION:  add_equivalence( Equivalence *equivs, NAME name1, NAME name2 )
  464.  
  465.   DESCRIPTION:
  466.         This function adds an equivalence relation to the list of equivalent
  467.     interfaces.  Each node has an equivalence structure that contains
  468.     a lisked list of interfaces that are equivalent.  When a new equivalence
  469.     is to be added, the lists are first searched to determine if this is
  470.     a redundant entry.
  471.  
  472. ****************************************************************************/
  473.  
  474. void   add_equivalence( Equivalence **equivs, NAME name1, NAME name2 )
  475. {
  476.    Equivalence   *equiv1, *equiv2;
  477.    Interface     *cur_ifc, *nxt_ifc;
  478.  
  479.    equiv1 = NULL;
  480.    equiv2 = NULL;
  481.  
  482.    /*
  483.    **     Determine if either name1 or name2 are already listed in
  484.    **     one of the equivalence structures.  
  485.    */
  486.    for( equiv1 = *equivs; equiv1 != NULL; equiv1 = equiv1->next )
  487.       if( find_name( &equiv1->ifcs, name1 ))
  488.      break;
  489.    for( equiv2 = *equivs; equiv2 != NULL; equiv2 = equiv2->next )
  490.       if( find_name( &equiv2->ifcs, name2 ))
  491.      break;
  492.  
  493.    if( equiv1 != NULL )
  494.       {/*
  495.        **   Name 1 is already listed as having at least one equivalent interface
  496.        */
  497.       if( equiv1 == equiv2 )
  498.      /*
  499.      **     This equivalence information is redundant
  500.      */
  501.      return;
  502.       if( equiv2 != NULL )
  503.      {/*
  504.       **     The two equivalence lists need to be combined.
  505.       */
  506.      for( cur_ifc = equiv2->ifcs.first; cur_ifc != NULL; )
  507.         {
  508.         nxt_ifc = cur_ifc->next;
  509.         insert_ifc( &equiv1->ifcs, cur_ifc );
  510.         cur_ifc = nxt_ifc;
  511.         }
  512.      equiv2->ifcs.first = NULL;
  513.      equiv2->ifcs.number = 0;
  514.          }
  515.       else
  516.      /*
  517.      **   name 2 is not in any equivalence lists so add it to
  518.      **   node 1's list.
  519.      */
  520.      insert_name( &equiv1->ifcs, name2 );
  521.       }
  522.    else if( equiv2 != NULL )
  523.       /*
  524.       **    name 2 has at least one equiv. interface but name 1 had none
  525.       **    so add name 1 to the list containing name 2.
  526.       */
  527.       insert_name( &equiv2->ifcs, name1 );
  528.    else
  529.       {/*
  530.        **   This equivalence represents a new node so either
  531.        **   find an empty equivalence structure in the linked
  532.        **   list or allocate a new equivalence structure
  533.        **   and put the two names in its list.
  534.        */
  535.       for( equiv1 = *equivs; equiv1 != NULL; equiv1 = equiv1->next )
  536.      if( equiv1->ifcs.number == 0 )
  537.         break;
  538.       if( equiv1 == NULL )
  539.      {
  540.      equiv1 = (Equivalence *)calloc( 1, sizeof( Equivalence ));
  541.      equiv1->next = *equivs;
  542.      *equivs = equiv1;
  543.          }
  544.       insert_name( &equiv1->ifcs, name1 );
  545.       insert_name( &equiv1->ifcs, name2 );
  546.       }
  547.    return;
  548. }
  549.      
  550. /*************************************************************************
  551.  
  552.   FUNCTION: add_ifc( net, frm_ifc, node1, ip_name, type )
  553.  
  554.   DESCRIPTION:
  555.        This function adds an interface to the network if it did not already
  556.        exist.
  557.  
  558. **************************************************************************/
  559.  
  560. Interface   *add_ifc( Network *net, NAME frm_name, NAME to_name, char *type, int suspect )
  561. {
  562.    long ifc_type, ifc_metric, ifc_thresh;
  563.    ADDRESS      to_addr, frm_addr, mask;
  564.    HENTRY_t    *ht_entry_p;
  565.    Interface *new_ifc, *to_sub, *temp_ifc;
  566.    Node       *node1;
  567.    
  568.    /*
  569.    **    Create a new edge and copy the information to it
  570.    */
  571.    sscanf( type, "[%ld/%ld", &ifc_metric, &ifc_thresh );
  572.    ifc_type = 0;
  573.    if( strstr( type, "tunnel" ) != NULL )
  574.       ifc_type |= TUNNEL;
  575.    if( strstr( type, "querier" ) != NULL )
  576.       ifc_type |= QUERIER;
  577.    if( strstr( type, "down" ) != NULL )
  578.       ifc_type |= DOWN;
  579.    if( strstr( type, "disabled" ) != NULL )
  580.       ifc_type |= DISABLED;
  581.    if( strstr( type, "srcrt" ) != NULL)
  582.       ifc_type |= SRCRT;
  583.    if( strstr( type, "suspect" ) != NULL || suspect == TRUE )
  584.       ifc_type |= SUSPECT;
  585.    /*
  586.     **    If the other end of this edge is not on the same subnet
  587.     **    as this interface, assume it is a tunnel even if it wasn't
  588.     **    explicitly marked as a tunnel.
  589.     */
  590.    
  591.    ht_entry_p =  lookup_htable( &net->name_map, to_name );
  592.    if( ht_entry_p == NULL )
  593.       {
  594.       printf( "Invalid interface specified %s\n", to_name );
  595.       return NULL;
  596.       }
  597.    to_sub = (Interface *)ht_entry_p->subnet;
  598.    if( to_sub == NULL )
  599.       mask = 0xffffffff;
  600.    else
  601.       mask = to_sub->mask;
  602.    inet_parse( to_name, &to_addr, NULL );
  603.    inet_parse( frm_name, &frm_addr, NULL );
  604.    if( !(ifc_type & TUNNEL) && !((frm_addr & mask)
  605.                  == (to_addr & mask)))
  606.       {
  607.      ifc_type |= ASSUMED;
  608.      ifc_type |= TUNNEL;
  609.       }
  610.  
  611.    if( ifc_type & TUNNEL )
  612.       {
  613.       temp_ifc = find_ifc( net, NULL, frm_name, to_name );
  614.       if( temp_ifc != NULL )
  615.      {/*
  616.       **      This tunnel already exists but before returning
  617.       **      mark it as no longer suspect or down if this call
  618.       **      did not mark it.
  619.       */
  620.      if( !suspect )
  621.         temp_ifc->type &= ~SUSPECT;
  622.      if( !(ifc_type & (DOWN | DISABLED)))
  623.         temp_ifc->type &= ~(DOWN | DISABLED );
  624.      return NULL;
  625.          }
  626.  
  627.       else
  628.      {
  629.      /*  This edge is a tunnel so allocate a new interface
  630.       **  because the first interface with this
  631.       **  address is always the subnet interface.
  632.       */
  633.      new_ifc = (Interface *)calloc( 1, sizeof( Interface ));
  634.      strcpy( new_ifc->name, frm_name );
  635.      new_ifc->address = frm_addr;
  636.      new_ifc->mask = 0xffffffff;
  637.      strcpy( new_ifc->to_name, to_name);
  638.          new_ifc->to_node = ht_entry_p->index;
  639.      new_ifc->to_addr = to_addr;
  640.      ht_entry_p = lookup_htable( &net->name_map, frm_name );
  641.      if( ht_entry_p == NULL )
  642.         {
  643.         printf( "Invalid interface specified %s\n", frm_name );
  644.         return NULL;
  645.         }
  646.      /*printf( "adding ifc %s to %s, frm_node = %ld, to_node = %ld\n",
  647.         frm_name, to_name, ht_entry_p->index, new_ifc->to_node );*/
  648.      node1 = &(net->adj_list[ht_entry_p->index]);
  649.      insert_ifc( &(node1->interfaces), new_ifc );
  650.      node1->degree++;
  651.          }
  652.       }
  653.    else
  654.       {/*
  655.        **   This is a subnet connection so if the edge is already there
  656.        **   to the subnet then we don't need this one.  Just set the
  657.        **   metric and threshold.
  658.        */
  659.       new_ifc = find_ifc( net, NULL, frm_name, to_sub->name );
  660.       if( new_ifc == NULL )
  661.      {
  662.      new_ifc = (Interface *)calloc( 1, sizeof( Interface ));
  663.      strcpy( new_ifc->name, frm_name );
  664.      new_ifc->address = frm_addr;
  665.      new_ifc->mask = to_sub->mask;
  666.      strcpy( new_ifc->to_name, to_name);
  667.      ht_entry_p =  lookup_htable( &net->name_map, to_name );
  668.          new_ifc->to_node = ht_entry_p->index;
  669.      new_ifc->to_addr = to_addr;
  670.      ht_entry_p = lookup_htable( &net->name_map, frm_name );
  671.      if( ht_entry_p == NULL )
  672.         {
  673.         printf( "Invalid interface specified %s\n", frm_name );
  674.         return NULL;
  675.         }
  676.      node1 = &(net->adj_list[ht_entry_p->index]);
  677.      /*
  678.      **      Only mark the edges going into the subnet node as
  679.      **      subnet interfaces.
  680.      */
  681.      if( !(node1->type & SUBNET ))
  682.         ifc_type |= SUBNET;
  683.      insert_ifc( &(node1->interfaces), new_ifc );
  684.      node1->degree++;
  685.          }
  686.       if( !suspect )
  687.      new_ifc->type &= ~SUSPECT;
  688.       }
  689.    new_ifc->type |= ifc_type;
  690.    new_ifc->metric = ifc_metric;
  691.    new_ifc->threshold = ifc_thresh;
  692.    return new_ifc;
  693. }
  694.  
  695. /*********************************************************************
  696.  
  697.   FUNCTION:  add_new_node()
  698.  
  699.   DESCRIPTION:
  700.        This function is called whenever a new previously unknown
  701.        interface name is specified by the user for addition to the
  702.        network.
  703.  
  704. ***********************************************************************/
  705. int   add_new_node( Network *net, NAME new_name, Ifc_list *subnets )
  706. {
  707.    int         args, index;
  708.    Interface  *cur_ifc;
  709.    char        cur_input[MAXLINE];
  710.    char        ans;
  711.    NAME        equiv_name, new_ip_name;
  712.    HENTRY_t   *ht_entry_p;
  713.  
  714.    printf( "Add interface %s (y/n)? ", new_name);
  715.    gets( cur_input );
  716.    sscanf( cur_input, "%c", &ans );
  717.    if( ans == 'n' )
  718.       return FALSE;
  719.    printf( "At an existing router? If so, enter equivalent interface: ");
  720.    gets( cur_input );
  721.    args = sscanf( cur_input, "%s", &equiv_name );
  722.    ht_entry_p = NULL;
  723.    if( args == 1 )
  724.       ht_entry_p = find_actual_name( net, equiv_name, subnets );
  725.    if( ht_entry_p != NULL )
  726.       {
  727.       index = ht_entry_p->index;
  728.       }
  729.    else
  730.       {
  731.       if( net->no_alloc <= net->no_nodes )
  732.      {
  733.      if( verbose )
  734.         printf( "\nNo more room in network for new nodes, rerun mrdebug with -a option\n");
  735.      return FALSE;
  736.          }
  737.       index = net->no_nodes;
  738.       net->no_nodes++;
  739.       }
  740.    cur_ifc = find_subnet( new_name, subnets );
  741.    insert_htable( &net->name_map, new_name, index, (long *)cur_ifc,
  742.           NULL );
  743.    if( find_ip_name( new_name, new_ip_name ))
  744.       insert_htable( &net->ip_map, new_ip_name, index, (long *)cur_ifc,
  745.              new_name );
  746.    if( cur_ifc != NULL )
  747.       {
  748.       /* Add the edge to the subnet node */
  749.       add_ifc( net, new_name, cur_ifc->name, "[1/1/suspect]", TRUE );
  750.       ht_entry_p = lookup_htable( &net->name_map, cur_ifc->name );
  751.       add_ifc( net, cur_ifc->name, new_name, "[0/0]", FALSE);
  752.       }
  753.    return TRUE;
  754. }
  755.  
  756.  
  757.  
  758.