File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_spf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    1: /*
    2:  * IS-IS Rout(e)ing protocol                  - isis_spf.c
    3:  *                                              The SPT algorithm
    4:  *
    5:  * Copyright (C) 2001,2002   Sampo Saaristo
    6:  *                           Tampere University of Technology      
    7:  *                           Institute of Communications Engineering
    8:  *
    9:  * This program is free software; you can redistribute it and/or modify it 
   10:  * under the terms of the GNU General Public Licenseas published by the Free 
   11:  * Software Foundation; either version 2 of the License, or (at your option) 
   12:  * any later version.
   13:  *
   14:  * This program is distributed in the hope that it will be useful,but WITHOUT 
   15:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
   16:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
   17:  * more details.
   18: 
   19:  * You should have received a copy of the GNU General Public License along 
   20:  * with this program; if not, write to the Free Software Foundation, Inc., 
   21:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   22:  */
   23: 
   24: #include <zebra.h>
   25: 
   26: #include "thread.h"
   27: #include "linklist.h"
   28: #include "vty.h"
   29: #include "log.h"
   30: #include "command.h"
   31: #include "memory.h"
   32: #include "prefix.h"
   33: #include "hash.h"
   34: #include "if.h"
   35: #include "table.h"
   36: 
   37: #include "isis_constants.h"
   38: #include "isis_common.h"
   39: #include "dict.h"
   40: #include "isisd.h"
   41: #include "isis_misc.h"
   42: #include "isis_adjacency.h"
   43: #include "isis_circuit.h"
   44: #include "isis_tlv.h"
   45: #include "isis_pdu.h"
   46: #include "isis_lsp.h"
   47: #include "isis_dynhn.h"
   48: #include "isis_spf.h"
   49: #include "isis_route.h"
   50: #include "isis_csm.h"
   51: 
   52: extern struct isis *isis;
   53: extern struct thread_master *master;
   54: extern struct host host;
   55: 
   56: int isis_run_spf_l1 (struct thread *thread);
   57: int isis_run_spf_l2 (struct thread *thread);
   58: 
   59: /* 7.2.7 */
   60: static void
   61: remove_excess_adjs (struct list *adjs)
   62: {
   63:   struct listnode *node, *excess = NULL;
   64:   struct isis_adjacency *adj, *candidate = NULL;
   65:   int comp;
   66: 
   67:   for (ALL_LIST_ELEMENTS_RO (adjs, node, adj)) 
   68:     {
   69:       if (excess == NULL)
   70: 	excess = node;
   71:       candidate = listgetdata (excess);
   72: 
   73:       if (candidate->sys_type < adj->sys_type)
   74: 	{
   75: 	  excess = node;
   76: 	  candidate = adj;
   77: 	  continue;
   78: 	}
   79:       if (candidate->sys_type > adj->sys_type)
   80: 	continue;
   81: 
   82:       comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
   83:       if (comp > 0)
   84: 	{
   85: 	  excess = node;
   86: 	  candidate = adj;
   87: 	  continue;
   88: 	}
   89:       if (comp < 0)
   90: 	continue;
   91: 
   92:       if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
   93: 	{
   94: 	  excess = node;
   95: 	  candidate = adj;
   96: 	  continue;
   97: 	}
   98: 
   99:       if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
  100: 	continue;
  101: 
  102:       comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
  103:       if (comp > 0)
  104: 	{
  105: 	  excess = node;
  106: 	  candidate = adj;
  107: 	  continue;
  108: 	}
  109:     }
  110: 
  111:   list_delete_node (adjs, excess);
  112: 
  113:   return;
  114: }
  115: 
  116: #ifdef EXTREME_DEBUG
  117: static const char *
  118: vtype2string (enum vertextype vtype)
  119: {
  120:   switch (vtype)
  121:     {
  122:     case VTYPE_PSEUDO_IS:
  123:       return "pseudo_IS";
  124:       break;
  125:     case VTYPE_PSEUDO_TE_IS:
  126:       return "pseudo_TE-IS";
  127:       break;
  128:     case VTYPE_NONPSEUDO_IS:
  129:       return "IS";
  130:       break;
  131:     case VTYPE_NONPSEUDO_TE_IS:
  132:       return "TE-IS";
  133:       break;
  134:     case VTYPE_ES:
  135:       return "ES";
  136:       break;
  137:     case VTYPE_IPREACH_INTERNAL:
  138:       return "IP internal";
  139:       break;
  140:     case VTYPE_IPREACH_EXTERNAL:
  141:       return "IP external";
  142:       break;
  143:     case VTYPE_IPREACH_TE:
  144:       return "IP TE";
  145:       break;
  146: #ifdef HAVE_IPV6
  147:     case VTYPE_IP6REACH_INTERNAL:
  148:       return "IP6 internal";
  149:       break;
  150:     case VTYPE_IP6REACH_EXTERNAL:
  151:       return "IP6 external";
  152:       break;
  153: #endif /* HAVE_IPV6 */
  154:     default:
  155:       return "UNKNOWN";
  156:     }
  157:   return NULL;			/* Not reached */
  158: }
  159: 
  160: static const char *
  161: vid2string (struct isis_vertex *vertex, u_char * buff)
  162: {
  163:   switch (vertex->type)
  164:     {
  165:     case VTYPE_PSEUDO_IS:
  166:     case VTYPE_PSEUDO_TE_IS:
  167:       return rawlspid_print (vertex->N.id);
  168:       break;
  169:     case VTYPE_NONPSEUDO_IS:
  170:     case VTYPE_NONPSEUDO_TE_IS:
  171:     case VTYPE_ES:
  172:       return sysid_print (vertex->N.id);
  173:       break;
  174:     case VTYPE_IPREACH_INTERNAL:
  175:     case VTYPE_IPREACH_EXTERNAL:
  176:     case VTYPE_IPREACH_TE:
  177: #ifdef HAVE_IPV6
  178:     case VTYPE_IP6REACH_INTERNAL:
  179:     case VTYPE_IP6REACH_EXTERNAL:
  180: #endif /* HAVE_IPV6 */
  181:       prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ);
  182:       break;
  183:     default:
  184:       return "UNKNOWN";
  185:     }
  186: 
  187:   return (char *) buff;
  188: }
  189: #endif /* EXTREME_DEBUG */
  190: 
  191: static struct isis_spftree *
  192: isis_spftree_new ()
  193: {
  194:   struct isis_spftree *tree;
  195: 
  196:   tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
  197:   if (tree == NULL)
  198:     {
  199:       zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
  200:       return NULL;
  201:     }
  202: 
  203:   tree->tents = list_new ();
  204:   tree->paths = list_new ();
  205:   return tree;
  206: }
  207: 
  208: static void
  209: isis_vertex_del (struct isis_vertex *vertex)
  210: {
  211:   list_delete (vertex->Adj_N);
  212: 
  213:   XFREE (MTYPE_ISIS_VERTEX, vertex);
  214: 
  215:   return;
  216: }
  217: 
  218: #if 0 /* HT: Not used yet. */
  219: static void
  220: isis_spftree_del (struct isis_spftree *spftree)
  221: {
  222:   spftree->tents->del = (void (*)(void *)) isis_vertex_del;
  223:   list_delete (spftree->tents);
  224: 
  225:   spftree->paths->del = (void (*)(void *)) isis_vertex_del;
  226:   list_delete (spftree->paths);
  227: 
  228:   XFREE (MTYPE_ISIS_SPFTREE, spftree);
  229: 
  230:   return;
  231: }
  232: #endif 
  233: 
  234: void
  235: spftree_area_init (struct isis_area *area)
  236: {
  237:   if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL)
  238:     {
  239:       area->spftree[0] = isis_spftree_new ();
  240: #ifdef HAVE_IPV6
  241:       area->spftree6[0] = isis_spftree_new ();
  242: #endif
  243: 
  244:       /*    thread_add_timer (master, isis_run_spf_l1, area, 
  245:          isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
  246:     }
  247: 
  248:   if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL)
  249:     {
  250:       area->spftree[1] = isis_spftree_new ();
  251: #ifdef HAVE_IPV6
  252:       area->spftree6[1] = isis_spftree_new ();
  253: #endif
  254:       /*    thread_add_timer (master, isis_run_spf_l2, area, 
  255:          isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
  256:     }
  257: 
  258:   return;
  259: }
  260: 
  261: static struct isis_vertex *
  262: isis_vertex_new (void *id, enum vertextype vtype)
  263: {
  264:   struct isis_vertex *vertex;
  265: 
  266:   vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
  267:   if (vertex == NULL)
  268:     {
  269:       zlog_err ("isis_vertex_new Out of memory!");
  270:       return NULL;
  271:     }
  272: 
  273:   vertex->type = vtype;
  274:   switch (vtype)
  275:     {
  276:     case VTYPE_ES:
  277:     case VTYPE_NONPSEUDO_IS:
  278:     case VTYPE_NONPSEUDO_TE_IS:
  279:       memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
  280:       break;
  281:     case VTYPE_PSEUDO_IS:
  282:     case VTYPE_PSEUDO_TE_IS:
  283:       memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
  284:       break;
  285:     case VTYPE_IPREACH_INTERNAL:
  286:     case VTYPE_IPREACH_EXTERNAL:
  287:     case VTYPE_IPREACH_TE:
  288: #ifdef HAVE_IPV6
  289:     case VTYPE_IP6REACH_INTERNAL:
  290:     case VTYPE_IP6REACH_EXTERNAL:
  291: #endif /* HAVE_IPV6 */
  292:       memcpy (&vertex->N.prefix, (struct prefix *) id,
  293: 	      sizeof (struct prefix));
  294:       break;
  295:     default:
  296:       zlog_err ("WTF!");
  297:     }
  298: 
  299:   vertex->Adj_N = list_new ();
  300: 
  301:   return vertex;
  302: }
  303: 
  304: /*
  305:  * Add this IS to the root of SPT
  306:  */
  307: static void
  308: isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
  309: 		   int level)
  310: {
  311:   struct isis_vertex *vertex;
  312:   struct isis_lsp *lsp;
  313:   u_char lspid[ISIS_SYS_ID_LEN + 2];
  314: #ifdef EXTREME_DEBUG
  315:   u_char buff[BUFSIZ];
  316: #endif /* EXTREME_DEBUG */
  317:   memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
  318:   LSP_PSEUDO_ID (lspid) = 0;
  319:   LSP_FRAGMENT (lspid) = 0;
  320: 
  321:   lsp = lsp_search (lspid, area->lspdb[level - 1]);
  322: 
  323:   if (lsp == NULL)
  324:     zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
  325: 
  326:   if (!area->oldmetric)
  327:     vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS);
  328:   else
  329:     vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
  330: 
  331:   vertex->lsp = lsp;
  332: 
  333:   listnode_add (spftree->paths, vertex);
  334: 
  335: #ifdef EXTREME_DEBUG
  336:   zlog_debug ("ISIS-Spf: added this IS  %s %s depth %d dist %d to PATHS",
  337: 	      vtype2string (vertex->type), vid2string (vertex, buff),
  338: 	      vertex->depth, vertex->d_N);
  339: #endif /* EXTREME_DEBUG */
  340: 
  341:   return;
  342: }
  343: 
  344: static struct isis_vertex *
  345: isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
  346: {
  347:   struct listnode *node;
  348:   struct isis_vertex *vertex;
  349:   struct prefix *p1, *p2;
  350: 
  351:   for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
  352:     {
  353:       if (vertex->type != vtype)
  354: 	continue;
  355:       switch (vtype)
  356: 	{
  357: 	case VTYPE_ES:
  358: 	case VTYPE_NONPSEUDO_IS:
  359: 	case VTYPE_NONPSEUDO_TE_IS:
  360: 	  if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
  361: 	    return vertex;
  362: 	  break;
  363: 	case VTYPE_PSEUDO_IS:
  364: 	case VTYPE_PSEUDO_TE_IS:
  365: 	  if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
  366: 	    return vertex;
  367: 	  break;
  368: 	case VTYPE_IPREACH_INTERNAL:
  369: 	case VTYPE_IPREACH_EXTERNAL:
  370: 	case VTYPE_IPREACH_TE:
  371: #ifdef HAVE_IPV6
  372: 	case VTYPE_IP6REACH_INTERNAL:
  373: 	case VTYPE_IP6REACH_EXTERNAL:
  374: #endif /* HAVE_IPV6 */
  375: 	  p1 = (struct prefix *) id;
  376: 	  p2 = (struct prefix *) &vertex->N.id;
  377: 	  if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
  378: 	      memcmp (&p1->u.prefix, &p2->u.prefix,
  379: 		      PSIZE (p1->prefixlen)) == 0)
  380: 	    return vertex;
  381: 	  break;
  382: 	}
  383:     }
  384: 
  385:   return NULL;
  386: }
  387: 
  388: /*
  389:  * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
  390:  */
  391: static struct isis_vertex *
  392: isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
  393: 		   void *id, struct isis_adjacency *adj, u_int32_t cost,
  394: 		   int depth, int family)
  395: {
  396:   struct isis_vertex *vertex, *v;
  397:   struct listnode *node;
  398: #ifdef EXTREME_DEBUG
  399:   u_char buff[BUFSIZ];
  400: #endif
  401: 
  402:   vertex = isis_vertex_new (id, vtype);
  403:   vertex->d_N = cost;
  404:   vertex->depth = depth;
  405: 
  406:   if (adj)
  407:     listnode_add (vertex->Adj_N, adj);
  408: #ifdef EXTREME_DEBUG
  409:   zlog_debug ("ISIS-Spf: add to TENT  %s %s depth %d dist %d",
  410: 	      vtype2string (vertex->type), vid2string (vertex, buff),
  411: 	      vertex->depth, vertex->d_N);
  412: #endif /* EXTREME_DEBUG */
  413:   listnode_add (spftree->tents, vertex);
  414:   if (list_isempty (spftree->tents))
  415:     {
  416:       listnode_add (spftree->tents, vertex);
  417:       return vertex;
  418:     }
  419:   
  420:   /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */
  421:   for (node = listhead (spftree->tents); node; node = listnextnode (node))
  422:     {
  423:       v = listgetdata (node);
  424:       if (v->d_N > vertex->d_N)
  425: 	{
  426: 	  list_add_node_prev (spftree->tents, node, vertex);
  427: 	  break;
  428: 	}
  429:       else if (v->d_N == vertex->d_N)
  430: 	{
  431: 	  /*  Tie break, add according to type */
  432: 	  while (v && v->d_N == vertex->d_N && v->type > vertex->type)
  433: 	    {
  434: 	      if (v->type > vertex->type)
  435: 		{
  436: 		  break;
  437: 		}
  438:               /* XXX: this seems dubious, node is the loop iterator */
  439: 	      node = listnextnode (node);
  440: 	      (node) ? (v = listgetdata (node)) : (v = NULL);
  441: 	    }
  442: 	  list_add_node_prev (spftree->tents, node, vertex);
  443: 	  break;
  444: 	}
  445:       else if (node->next == NULL)
  446: 	{
  447: 	  list_add_node_next (spftree->tents, node, vertex);
  448: 	  break;
  449: 	}
  450:     }
  451:   return vertex;
  452: }
  453: 
  454: static struct isis_vertex *
  455: isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
  456: 		    void *id, struct isis_adjacency *adj, u_int32_t cost,
  457: 		    int family)
  458: {
  459:   struct isis_vertex *vertex;
  460: 
  461:   vertex = isis_find_vertex (spftree->tents, id, vtype);
  462: 
  463:   if (vertex)
  464:     {
  465:       /* C.2.5   c) */
  466:       if (vertex->d_N == cost)
  467: 	{
  468: 	  if (adj)
  469: 	    listnode_add (vertex->Adj_N, adj);
  470: 	  /*       d) */
  471: 	  if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
  472: 	    remove_excess_adjs (vertex->Adj_N);
  473: 	}
  474:       /*         f) */
  475:       else if (vertex->d_N > cost)
  476: 	{
  477: 	  listnode_delete (spftree->tents, vertex);
  478: 	  goto add2tent;
  479: 	}
  480:       /*       e) do nothing */
  481:       return vertex;
  482:     }
  483: 
  484: add2tent:
  485:   return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
  486: }
  487: 
  488: static void
  489: process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
  490: 	   u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
  491: 	   int family)
  492: {
  493:   struct isis_vertex *vertex;
  494: #ifdef EXTREME_DEBUG
  495:   u_char buff[255];
  496: #endif
  497: 
  498:   /* C.2.6 b)    */
  499:   if (dist > MAX_PATH_METRIC)
  500:     return;
  501:   /*       c)    */
  502:   vertex = isis_find_vertex (spftree->paths, id, vtype);
  503:   if (vertex)
  504:     {
  505: #ifdef EXTREME_DEBUG
  506:       zlog_debug ("ISIS-Spf: process_N  %s %s dist %d already found from PATH",
  507: 		  vtype2string (vtype), vid2string (vertex, buff), dist);
  508: #endif /* EXTREME_DEBUG */
  509:       assert (dist >= vertex->d_N);
  510:       return;
  511:     }
  512: 
  513:   vertex = isis_find_vertex (spftree->tents, id, vtype);
  514:   /*       d)    */
  515:   if (vertex)
  516:     {
  517:       /*        1) */
  518: #ifdef EXTREME_DEBUG
  519:       zlog_debug ("ISIS-Spf: process_N  %s %s dist %d",
  520: 		  vtype2string (vtype), vid2string (vertex, buff), dist);
  521: #endif /* EXTREME_DEBUG */
  522:       if (vertex->d_N == dist)
  523: 	{
  524: 	  if (adj)
  525: 	    listnode_add (vertex->Adj_N, adj);
  526: 	  /*      2) */
  527: 	  if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
  528: 	    remove_excess_adjs (vertex->Adj_N);
  529: 	  /*      3) */
  530: 	  return;
  531: 	}
  532:       else if (vertex->d_N < dist)
  533: 	{
  534: 	  return;
  535: 	  /*      4) */
  536: 	}
  537:       else
  538: 	{
  539: 	  listnode_delete (spftree->tents, vertex);
  540: 	}
  541:     }
  542: 
  543:   isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
  544:   return;
  545: }
  546: 
  547: /*
  548:  * C.2.6 Step 1
  549:  */
  550: static int
  551: isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
  552: 		      uint32_t cost, uint16_t depth, int family)
  553: {
  554:   struct listnode *node, *fragnode = NULL;
  555:   u_int16_t dist;
  556:   struct is_neigh *is_neigh;
  557:   struct te_is_neigh *te_is_neigh;
  558:   struct ipv4_reachability *ipreach;
  559:   struct te_ipv4_reachability *te_ipv4_reach;
  560:   enum vertextype vtype;
  561:   struct prefix prefix;
  562: #ifdef HAVE_IPV6
  563:   struct ipv6_reachability *ip6reach;
  564: #endif /* HAVE_IPV6 */
  565: 
  566: 
  567:   if (!lsp->adj)
  568:     return ISIS_WARNING;
  569:   if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
  570:     return ISIS_OK;
  571: 
  572: lspfragloop:
  573:   if (lsp->lsp_header->seq_num == 0)
  574:     {
  575:       zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
  576: 		 " - do not process");
  577:       return ISIS_WARNING;
  578:     }
  579: 
  580:   if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
  581:     {
  582:       if (lsp->tlv_data.is_neighs)
  583: 	{
  584:           for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
  585: 	    {
  586: 	      /* C.2.6 a) */
  587: 	      /* Two way connectivity */
  588: 	      if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
  589: 		continue;
  590: 	      dist = cost + is_neigh->metrics.metric_default;
  591: 	      vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
  592: 		: VTYPE_NONPSEUDO_IS;
  593: 	      process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
  594: 			 depth + 1, lsp->adj, family);
  595: 	    }
  596: 	}
  597:       if (lsp->tlv_data.te_is_neighs)
  598: 	{
  599: 	  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
  600: 				     te_is_neigh))
  601: 	    {
  602: 	      uint32_t metric;
  603: 	      if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
  604: 		continue;
  605: 	      memcpy (&metric, te_is_neigh->te_metric, 3);
  606: 	      dist = cost + ntohl (metric << 8);
  607: 	      vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
  608: 		: VTYPE_NONPSEUDO_TE_IS;
  609: 	      process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
  610: 			 depth + 1, lsp->adj, family);
  611: 	    }
  612: 	}
  613:       if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
  614: 	{
  615: 	  prefix.family = AF_INET;
  616:           for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, 
  617:                                      node, ipreach))
  618: 	    {
  619: 	      dist = cost + ipreach->metrics.metric_default;
  620: 	      vtype = VTYPE_IPREACH_INTERNAL;
  621: 	      prefix.u.prefix4 = ipreach->prefix;
  622: 	      prefix.prefixlen = ip_masklen (ipreach->mask);
  623: 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
  624: 			 lsp->adj, family);
  625: 	    }
  626: 	}
  627: 
  628:       if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
  629: 	{
  630: 	  prefix.family = AF_INET;
  631:           for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs,
  632:                                      node, ipreach))
  633: 	    {
  634: 	      dist = cost + ipreach->metrics.metric_default;
  635: 	      vtype = VTYPE_IPREACH_EXTERNAL;
  636: 	      prefix.u.prefix4 = ipreach->prefix;
  637: 	      prefix.prefixlen = ip_masklen (ipreach->mask);
  638: 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
  639: 			 lsp->adj, family);
  640: 	    }
  641: 	}
  642:       if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
  643: 	{
  644: 	  prefix.family = AF_INET;
  645: 	  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
  646: 				     node, te_ipv4_reach))
  647: 	    {
  648: 	      dist = cost + ntohl (te_ipv4_reach->te_metric);
  649: 	      vtype = VTYPE_IPREACH_TE;
  650: 	      prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
  651: 						   te_ipv4_reach->control);
  652: 	      prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
  653: 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
  654: 			 lsp->adj, family);
  655: 	    }
  656: 	}
  657: #ifdef HAVE_IPV6
  658:       if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
  659: 	{
  660: 	  prefix.family = AF_INET6;
  661:           for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, 
  662:                                      node, ip6reach))
  663: 	    {
  664: 	      dist = cost + ip6reach->metric;
  665: 	      vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
  666: 		VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
  667: 	      prefix.prefixlen = ip6reach->prefix_len;
  668: 	      memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
  669: 		      PSIZE (ip6reach->prefix_len));
  670: 	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
  671: 			 lsp->adj, family);
  672: 	    }
  673: 	}
  674: #endif /* HAVE_IPV6 */
  675:     }
  676: 
  677:   if (fragnode == NULL)
  678:     fragnode = listhead (lsp->lspu.frags);
  679:   else
  680:     fragnode = listnextnode (fragnode);
  681: 
  682:   if (fragnode)
  683:     {
  684:       lsp = listgetdata (fragnode);
  685:       goto lspfragloop;
  686:     }
  687: 
  688:   return ISIS_OK;
  689: }
  690: 
  691: static int
  692: isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
  693: 			     struct isis_lsp *lsp, uint16_t cost,
  694: 			     uint16_t depth, int family)
  695: {
  696:   struct listnode *node, *fragnode = NULL;
  697:   struct is_neigh *is_neigh;
  698:   struct te_is_neigh *te_is_neigh;
  699:   enum vertextype vtype;
  700: 
  701: pseudofragloop:
  702: 
  703:   if (lsp->lsp_header->seq_num == 0)
  704:     {
  705:       zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
  706: 		 " - do not process");
  707:       return ISIS_WARNING;
  708:     }
  709: 
  710:   if (lsp->tlv_data.is_neighs)
  711:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
  712:       {
  713: 	vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
  714: 	  : VTYPE_NONPSEUDO_IS;
  715: 	/* Two way connectivity */
  716: 	if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
  717: 	  continue;
  718: 	if (isis_find_vertex
  719: 	    (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL
  720: 	    && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id,
  721: 			       vtype) == NULL)
  722: 	  {
  723: 	    /* C.2.5 i) */
  724: 	    isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
  725: 			     cost, depth, family);
  726: 	  }
  727:       }
  728:   if (lsp->tlv_data.te_is_neighs)
  729:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
  730:       {
  731: 	vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
  732: 	  : VTYPE_NONPSEUDO_TE_IS;
  733: 	/* Two way connectivity */
  734: 	if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
  735: 	  continue;
  736: 	if (isis_find_vertex
  737: 	    (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL
  738: 	    && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id,
  739: 				 vtype) == NULL)
  740: 	  {
  741: 	    /* C.2.5 i) */
  742: 	    isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, lsp->adj,
  743: 			       cost, depth, family);
  744: 	  }
  745:       }
  746: 
  747:   if (fragnode == NULL)
  748:     fragnode = listhead (lsp->lspu.frags);
  749:   else
  750:     fragnode = listnextnode (fragnode);
  751: 
  752:   if (fragnode)
  753:     {
  754:       lsp = listgetdata (fragnode);
  755:       goto pseudofragloop;
  756:     }
  757: 
  758:   return ISIS_OK;
  759: }
  760: 
  761: static int
  762: isis_spf_preload_tent (struct isis_spftree *spftree,
  763: 		       struct isis_area *area, int level, int family)
  764: {
  765:   struct isis_vertex *vertex;
  766:   struct isis_circuit *circuit;
  767:   struct listnode *cnode, *anode, *ipnode;
  768:   struct isis_adjacency *adj;
  769:   struct isis_lsp *lsp;
  770:   struct list *adj_list;
  771:   struct list *adjdb;
  772:   struct prefix_ipv4 *ipv4;
  773:   struct prefix prefix;
  774:   int retval = ISIS_OK;
  775:   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
  776: #ifdef HAVE_IPV6
  777:   struct prefix_ipv6 *ipv6;
  778: #endif /* HAVE_IPV6 */
  779: 
  780:   for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
  781:     {
  782:       if (circuit->state != C_STATE_UP)
  783: 	continue;
  784:       if (!(circuit->circuit_is_type & level))
  785: 	continue;
  786:       if (family == AF_INET && !circuit->ip_router)
  787: 	continue;
  788: #ifdef HAVE_IPV6
  789:       if (family == AF_INET6 && !circuit->ipv6_router)
  790: 	continue;
  791: #endif /* HAVE_IPV6 */
  792:       /* 
  793:        * Add IP(v6) addresses of this circuit
  794:        */
  795:       if (family == AF_INET)
  796: 	{
  797: 	  prefix.family = AF_INET;
  798:           for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
  799: 	    {
  800: 	      prefix.u.prefix4 = ipv4->prefix;
  801: 	      prefix.prefixlen = ipv4->prefixlen;
  802: 	      isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
  803: 				  NULL, 0, family);
  804: 	    }
  805: 	}
  806: #ifdef HAVE_IPV6
  807:       if (family == AF_INET6)
  808: 	{
  809: 	  prefix.family = AF_INET6;
  810: 	  for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
  811: 	    {
  812: 	      prefix.prefixlen = ipv6->prefixlen;
  813: 	      prefix.u.prefix6 = ipv6->prefix;
  814: 	      isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
  815: 				  &prefix, NULL, 0, family);
  816: 	    }
  817: 	}
  818: #endif /* HAVE_IPV6 */
  819:       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  820: 	{
  821: 	  /*
  822: 	   * Add the adjacencies
  823: 	   */
  824: 	  adj_list = list_new ();
  825: 	  adjdb = circuit->u.bc.adjdb[level - 1];
  826: 	  isis_adj_build_up_list (adjdb, adj_list);
  827: 	  if (listcount (adj_list) == 0)
  828: 	    {
  829: 	      list_delete (adj_list);
  830: 	      if (isis->debugs & DEBUG_SPF_EVENTS)
  831: 		zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
  832: 			    level, circuit->interface->name);
  833: 	      continue;
  834: 	    }
  835: 	  anode = listhead (adj_list);
  836: 	  while (anode)
  837: 	    {
  838: 	      adj = listgetdata (anode);
  839: 	      if (!speaks (&adj->nlpids, family))
  840: 		{
  841: 		  anode = listnextnode (anode);
  842: 		  continue;
  843: 		}
  844: 	      switch (adj->sys_type)
  845: 		{
  846: 		case ISIS_SYSTYPE_ES:
  847: 		  isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
  848: 				      circuit->te_metric[level - 1], family);
  849: 		  break;
  850: 		case ISIS_SYSTYPE_IS:
  851: 		case ISIS_SYSTYPE_L1_IS:
  852: 		case ISIS_SYSTYPE_L2_IS:
  853: 		  vertex =
  854: 		    isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
  855: 					adj->sysid, adj,
  856: 					circuit->te_metric[level - 1], family);
  857: 		  memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
  858: 		  LSP_PSEUDO_ID (lsp_id) = 0;
  859: 		  LSP_FRAGMENT (lsp_id) = 0;
  860: 		  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
  861: 		  if (!lsp)
  862: 		    zlog_warn ("No lsp found for IS adjacency");
  863: 		  /*          else {
  864: 		     isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
  865: 		     } */
  866: 		  break;
  867: 		case ISIS_SYSTYPE_UNKNOWN:
  868: 		default:
  869: 		  zlog_warn ("isis_spf_preload_tent unknow adj type");
  870: 		}
  871: 	      anode = listnextnode (anode);
  872: 	    }
  873: 	  list_delete (adj_list);
  874: 	  /*
  875: 	   * Add the pseudonode 
  876: 	   */
  877: 	  if (level == 1)
  878: 	    memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
  879: 	  else
  880: 	    memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
  881: 	  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
  882: 	  adj = isis_adj_lookup (lsp_id, adjdb);
  883: 	  /* if no adj, we are the dis or error */
  884: 	  if (!adj && !circuit->u.bc.is_dr[level - 1])
  885: 	    {
  886: 	      zlog_warn ("ISIS-Spf: No adjacency found for DR");
  887: 	    }
  888: 	  if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
  889: 	    {
  890: 	      zlog_warn ("ISIS-Spf: No lsp found for DR");
  891: 	    }
  892: 	  else
  893: 	    {
  894: 	      isis_spf_process_pseudo_lsp (spftree, lsp,
  895: 				  circuit->te_metric[level - 1], 0, family);
  896: 
  897: 	    }
  898: 	}
  899:       else if (circuit->circ_type == CIRCUIT_T_P2P)
  900: 	{
  901: 	  adj = circuit->u.p2p.neighbor;
  902: 	  if (!adj)
  903: 	    continue;
  904: 	  switch (adj->sys_type)
  905: 	    {
  906: 	    case ISIS_SYSTYPE_ES:
  907: 	      isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
  908: 				  circuit->te_metric[level - 1], family);
  909: 	      break;
  910: 	    case ISIS_SYSTYPE_IS:
  911: 	    case ISIS_SYSTYPE_L1_IS:
  912: 	    case ISIS_SYSTYPE_L2_IS:
  913: 	      if (speaks (&adj->nlpids, family))
  914: 		isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
  915: 				    adj, circuit->te_metric[level - 1],
  916: 				    family);
  917: 	      break;
  918: 	    case ISIS_SYSTYPE_UNKNOWN:
  919: 	    default:
  920: 	      zlog_warn ("isis_spf_preload_tent unknow adj type");
  921: 	      break;
  922: 	    }
  923: 	}
  924:       else
  925: 	{
  926: 	  zlog_warn ("isis_spf_preload_tent unsupported media");
  927: 	  retval = ISIS_WARNING;
  928: 	}
  929: 
  930:     }
  931: 
  932:   return retval;
  933: }
  934: 
  935: /*
  936:  * The parent(s) for vertex is set when added to TENT list
  937:  * now we just put the child pointer(s) in place
  938:  */
  939: static void
  940: add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
  941: 	      struct isis_area *area, int level)
  942: {
  943: #ifdef EXTREME_DEBUG
  944:   u_char buff[BUFSIZ];
  945: #endif /* EXTREME_DEBUG */
  946:   listnode_add (spftree->paths, vertex);
  947: 
  948: #ifdef EXTREME_DEBUG
  949:   zlog_debug ("ISIS-Spf: added  %s %s depth %d dist %d to PATHS",
  950: 	      vtype2string (vertex->type), vid2string (vertex, buff),
  951: 	      vertex->depth, vertex->d_N);
  952: #endif /* EXTREME_DEBUG */
  953:   if (vertex->type > VTYPE_ES)
  954:     {
  955:       if (listcount (vertex->Adj_N) > 0)
  956: 	isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
  957: 			   vertex->depth, vertex->Adj_N, area, level);
  958:       else if (isis->debugs & DEBUG_SPF_EVENTS)
  959: 	zlog_debug ("ISIS-Spf: no adjacencies do not install route");
  960:     }
  961: 
  962:   return;
  963: }
  964: 
  965: static void
  966: init_spt (struct isis_spftree *spftree)
  967: {
  968:   spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
  969:   list_delete_all_node (spftree->tents);
  970:   list_delete_all_node (spftree->paths);
  971:   spftree->tents->del = spftree->paths->del = NULL;
  972: 
  973:   return;
  974: }
  975: 
  976: static int
  977: isis_run_spf (struct isis_area *area, int level, int family)
  978: {
  979:   int retval = ISIS_OK;
  980:   struct listnode *node;
  981:   struct isis_vertex *vertex;
  982:   struct isis_spftree *spftree = NULL;
  983:   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
  984:   struct isis_lsp *lsp;
  985:   struct route_table *table = NULL;
  986:   struct route_node *rode;
  987:   struct isis_route_info *rinfo;
  988: 
  989:   if (family == AF_INET)
  990:     spftree = area->spftree[level - 1];
  991: #ifdef HAVE_IPV6
  992:   else if (family == AF_INET6)
  993:     spftree = area->spftree6[level - 1];
  994: #endif
  995: 
  996:   assert (spftree);
  997: 
  998:   /* Make all routes in current route table inactive. */
  999:   if (family == AF_INET)
 1000:     table = area->route_table[level - 1];
 1001: #ifdef HAVE_IPV6
 1002:   else if (family == AF_INET6)
 1003:     table = area->route_table6[level - 1];
 1004: #endif
 1005: 
 1006:   for (rode = route_top (table); rode; rode = route_next (rode))
 1007:     {
 1008:       if (rode->info == NULL)
 1009:         continue;
 1010:       rinfo = rode->info;
 1011: 
 1012:       UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
 1013:     }
 1014: 
 1015:   /*
 1016:    * C.2.5 Step 0
 1017:    */
 1018:   init_spt (spftree);
 1019:   /*              a) */
 1020:   isis_spf_add_self (spftree, area, level);
 1021:   /*              b) */
 1022:   retval = isis_spf_preload_tent (spftree, area, level, family);
 1023: 
 1024:   /*
 1025:    * C.2.7 Step 2
 1026:    */
 1027:   if (listcount (spftree->tents) == 0)
 1028:     {
 1029:       zlog_warn ("ISIS-Spf: TENT is empty");
 1030:       goto out;
 1031:     }
 1032: 
 1033:   while (listcount (spftree->tents) > 0)
 1034:     {
 1035:       node = listhead (spftree->tents);
 1036:       vertex = listgetdata (node);
 1037:       /* Remove from tent list */
 1038:       list_delete_node (spftree->tents, node);
 1039:       if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
 1040: 	continue;
 1041:       add_to_paths (spftree, vertex, area, level);
 1042:       if (vertex->type == VTYPE_PSEUDO_IS ||
 1043: 	  vertex->type == VTYPE_NONPSEUDO_IS)
 1044: 	{
 1045: 	  memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
 1046: 	  LSP_FRAGMENT (lsp_id) = 0;
 1047: 	  lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
 1048: 	  if (lsp)
 1049: 	    {
 1050: 	      if (LSP_PSEUDO_ID (lsp_id))
 1051: 		{
 1052: 		  isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
 1053: 					       vertex->depth, family);
 1054: 
 1055: 		}
 1056: 	      else
 1057: 		{
 1058: 		  isis_spf_process_lsp (spftree, lsp, vertex->d_N,
 1059: 					vertex->depth, family);
 1060: 		}
 1061: 	    }
 1062: 	  else
 1063: 	    {
 1064: 	      zlog_warn ("ISIS-Spf: No LSP found for %s",
 1065: 			 rawlspid_print (lsp_id));
 1066: 	    }
 1067: 	}
 1068:     }
 1069: 
 1070: out:
 1071:   thread_add_event (master, isis_route_validate, area, 0);
 1072:   spftree->lastrun = time (NULL);
 1073:   spftree->pending = 0;
 1074: 
 1075:   return retval;
 1076: }
 1077: 
 1078: int
 1079: isis_run_spf_l1 (struct thread *thread)
 1080: {
 1081:   struct isis_area *area;
 1082:   int retval = ISIS_OK;
 1083: 
 1084:   area = THREAD_ARG (thread);
 1085:   assert (area);
 1086: 
 1087:   area->spftree[0]->t_spf = NULL;
 1088: 
 1089:   if (!(area->is_type & IS_LEVEL_1))
 1090:     {
 1091:       if (isis->debugs & DEBUG_SPF_EVENTS)
 1092: 	zlog_warn ("ISIS-SPF (%s) area does not share level",
 1093: 		   area->area_tag);
 1094:       return ISIS_WARNING;
 1095:     }
 1096: 
 1097:   if (isis->debugs & DEBUG_SPF_EVENTS)
 1098:     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
 1099: 
 1100:   if (area->ip_circuits)
 1101:     retval = isis_run_spf (area, 1, AF_INET);
 1102: 
 1103:   THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
 1104: 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1105: 
 1106:   return retval;
 1107: }
 1108: 
 1109: int
 1110: isis_run_spf_l2 (struct thread *thread)
 1111: {
 1112:   struct isis_area *area;
 1113:   int retval = ISIS_OK;
 1114: 
 1115:   area = THREAD_ARG (thread);
 1116:   assert (area);
 1117: 
 1118:   area->spftree[1]->t_spf = NULL;
 1119: 
 1120:   if (!(area->is_type & IS_LEVEL_2))
 1121:     {
 1122:       if (isis->debugs & DEBUG_SPF_EVENTS)
 1123: 	zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
 1124:       return ISIS_WARNING;
 1125:     }
 1126: 
 1127:   if (isis->debugs & DEBUG_SPF_EVENTS)
 1128:     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
 1129: 
 1130:   if (area->ip_circuits)
 1131:     retval = isis_run_spf (area, 2, AF_INET);
 1132: 
 1133:   THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
 1134: 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1135: 
 1136:   return retval;
 1137: }
 1138: 
 1139: int
 1140: isis_spf_schedule (struct isis_area *area, int level)
 1141: {
 1142:   int retval = ISIS_OK;
 1143:   struct isis_spftree *spftree = area->spftree[level - 1];
 1144:   time_t diff, now = time (NULL);
 1145: 
 1146:   if (spftree->pending)
 1147:     return retval;
 1148: 
 1149:   diff = now - spftree->lastrun;
 1150: 
 1151:   /* FIXME: let's wait a minute before doing the SPF */
 1152:   if (now - isis->uptime < 60 || isis->uptime == 0)
 1153:     {
 1154:       if (level == 1)
 1155: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
 1156:       else
 1157: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
 1158: 
 1159:       spftree->pending = 1;
 1160:       return retval;
 1161:     }
 1162: 
 1163:   THREAD_TIMER_OFF (spftree->t_spf);
 1164: 
 1165:   if (diff < MINIMUM_SPF_INTERVAL)
 1166:     {
 1167:       if (level == 1)
 1168: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
 1169: 			 MINIMUM_SPF_INTERVAL - diff);
 1170:       else
 1171: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
 1172: 			 MINIMUM_SPF_INTERVAL - diff);
 1173: 
 1174:       spftree->pending = 1;
 1175:     }
 1176:   else
 1177:     {
 1178:       spftree->pending = 0;
 1179:       retval = isis_run_spf (area, level, AF_INET);
 1180:       if (level == 1)
 1181: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
 1182: 			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1183:       else
 1184: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
 1185: 			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1186:     }
 1187: 
 1188:   return retval;
 1189: }
 1190: 
 1191: #ifdef HAVE_IPV6
 1192: static int
 1193: isis_run_spf6_l1 (struct thread *thread)
 1194: {
 1195:   struct isis_area *area;
 1196:   int retval = ISIS_OK;
 1197: 
 1198:   area = THREAD_ARG (thread);
 1199:   assert (area);
 1200: 
 1201:   area->spftree6[0]->t_spf = NULL;
 1202: 
 1203:   if (!(area->is_type & IS_LEVEL_1))
 1204:     {
 1205:       if (isis->debugs & DEBUG_SPF_EVENTS)
 1206: 	zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
 1207:       return ISIS_WARNING;
 1208:     }
 1209: 
 1210:   if (isis->debugs & DEBUG_SPF_EVENTS)
 1211:     zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
 1212: 
 1213:   if (area->ipv6_circuits)
 1214:     retval = isis_run_spf (area, 1, AF_INET6);
 1215: 
 1216:   THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
 1217: 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1218: 
 1219:   return retval;
 1220: }
 1221: 
 1222: static int
 1223: isis_run_spf6_l2 (struct thread *thread)
 1224: {
 1225:   struct isis_area *area;
 1226:   int retval = ISIS_OK;
 1227: 
 1228:   area = THREAD_ARG (thread);
 1229:   assert (area);
 1230: 
 1231:   area->spftree6[1]->t_spf = NULL;
 1232: 
 1233:   if (!(area->is_type & IS_LEVEL_2))
 1234:     {
 1235:       if (isis->debugs & DEBUG_SPF_EVENTS)
 1236:         zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
 1237:       return ISIS_WARNING;
 1238:     }
 1239: 
 1240:   if (isis->debugs & DEBUG_SPF_EVENTS)
 1241:     zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
 1242: 
 1243:   if (area->ipv6_circuits)
 1244:     retval = isis_run_spf (area, 2, AF_INET6);
 1245: 
 1246:   THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
 1247: 		   isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1248: 
 1249:   return retval;
 1250: }
 1251: 
 1252: int
 1253: isis_spf_schedule6 (struct isis_area *area, int level)
 1254: {
 1255:   int retval = ISIS_OK;
 1256:   struct isis_spftree *spftree = area->spftree6[level - 1];
 1257:   time_t diff, now = time (NULL);
 1258: 
 1259:   if (spftree->pending)
 1260:     return retval;
 1261: 
 1262:   diff = now - spftree->lastrun;
 1263: 
 1264:   /* FIXME: let's wait a minute before doing the SPF */
 1265:   if (now - isis->uptime < 60 || isis->uptime == 0)
 1266:     {
 1267:       if (level == 1)
 1268: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60);
 1269:       else
 1270: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60);
 1271: 
 1272:       spftree->pending = 1;
 1273:       return retval;
 1274:     }
 1275:   
 1276:   THREAD_TIMER_OFF (spftree->t_spf);
 1277: 
 1278:   if (diff < MINIMUM_SPF_INTERVAL)
 1279:     {
 1280:       if (level == 1)
 1281: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
 1282: 			 MINIMUM_SPF_INTERVAL - diff);
 1283:       else
 1284: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
 1285: 			 MINIMUM_SPF_INTERVAL - diff);
 1286: 
 1287:       spftree->pending = 1;
 1288:     }
 1289:   else
 1290:     {
 1291:       spftree->pending = 0;
 1292:       retval = isis_run_spf (area, level, AF_INET6);
 1293: 
 1294:       if (level == 1)
 1295: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
 1296: 			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1297:       else
 1298: 	THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
 1299: 			 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
 1300:     }
 1301: 
 1302:   return retval;
 1303: }
 1304: #endif
 1305: 
 1306: static void
 1307: isis_print_paths (struct vty *vty, struct list *paths)
 1308: {
 1309:   struct listnode *node;
 1310:   struct isis_vertex *vertex;
 1311:   struct isis_dynhn *dyn, *nh_dyn = NULL;
 1312:   struct isis_adjacency *adj;
 1313: #if 0
 1314:   u_char buff[255];
 1315: #endif /* 0 */
 1316: 
 1317:   vty_out (vty, "System Id            Metric     Next-Hop"
 1318: 	   "             Interface   SNPA%s", VTY_NEWLINE);
 1319: 
 1320:   for (ALL_LIST_ELEMENTS_RO (paths, node, vertex))
 1321:     {
 1322:       if (vertex->type != VTYPE_NONPSEUDO_IS)
 1323: 	continue;
 1324:       if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
 1325: 	{
 1326: 	  vty_out (vty, "%s             --%s", host.name?host.name:"",
 1327: 		   VTY_NEWLINE);
 1328: 	}
 1329:       else
 1330: 	{
 1331: 	  dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
 1332: 	  adj = listgetdata (listhead (vertex->Adj_N));
 1333: 	  if (adj)
 1334: 	    {
 1335: 	      nh_dyn = dynhn_find_by_id (adj->sysid);
 1336: 	      vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
 1337: 		       (dyn != NULL) ? dyn->name.name :
 1338: 		       (const u_char *)rawlspid_print ((u_char *) vertex->N.id),
 1339: 		       vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
 1340: 		       (const u_char *)rawlspid_print (adj->sysid),
 1341: 		       adj->circuit->interface->name,
 1342: 		       snpa_print (adj->snpa), VTY_NEWLINE);
 1343: 	    }
 1344: 	  else
 1345: 	    {
 1346: 	      vty_out (vty, "%s              %u %s", dyn ? dyn->name.name :
 1347: 		       (const u_char *) rawlspid_print (vertex->N.id),
 1348: 		       vertex->d_N, VTY_NEWLINE);
 1349: 	    }
 1350: 	}
 1351: #if 0
 1352:       vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
 1353: 	       vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
 1354: #endif
 1355:     }
 1356: }
 1357: 
 1358: DEFUN (show_isis_topology,
 1359:        show_isis_topology_cmd,
 1360:        "show isis topology",
 1361:        SHOW_STR
 1362:        "IS-IS information\n"
 1363:        "IS-IS paths to Intermediate Systems\n")
 1364: {
 1365:   struct listnode *node;
 1366:   struct isis_area *area;
 1367:   int level;
 1368: 
 1369:   if (!isis->area_list || isis->area_list->count == 0)
 1370:     return CMD_SUCCESS;
 1371: 
 1372:   for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
 1373:     {
 1374:       vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
 1375: 	       VTY_NEWLINE);
 1376: 
 1377:       for (level = 0; level < ISIS_LEVELS; level++)
 1378: 	{
 1379: 	  if (area->ip_circuits > 0 && area->spftree[level]
 1380: 	      && area->spftree[level]->paths->count > 0)
 1381: 	    {
 1382: 	      vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
 1383: 		       level + 1, VTY_NEWLINE);
 1384: 	      isis_print_paths (vty, area->spftree[level]->paths);
 1385: 	    }
 1386: #ifdef HAVE_IPV6
 1387: 	  if (area->ipv6_circuits > 0 && area->spftree6[level]
 1388: 	      && area->spftree6[level]->paths->count > 0)
 1389: 	    {
 1390: 	      vty_out (vty,
 1391: 		       "IS-IS paths to level-%d routers that speak IPv6%s",
 1392: 		       level + 1, VTY_NEWLINE);
 1393: 	      isis_print_paths (vty, area->spftree6[level]->paths);
 1394: 	    }
 1395: #endif /* HAVE_IPV6 */
 1396: 	}
 1397:     }
 1398: 
 1399:   return CMD_SUCCESS;
 1400: }
 1401: 
 1402: DEFUN (show_isis_topology_l1,
 1403:        show_isis_topology_l1_cmd,
 1404:        "show isis topology level-1",
 1405:        SHOW_STR
 1406:        "IS-IS information\n"
 1407:        "IS-IS paths to Intermediate Systems\n"
 1408:        "Paths to all level-1 routers in the area\n")
 1409: {
 1410:   struct listnode *node;
 1411:   struct isis_area *area;
 1412: 
 1413:   if (!isis->area_list || isis->area_list->count == 0)
 1414:     return CMD_SUCCESS;
 1415: 
 1416:   for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
 1417:     {
 1418:       vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
 1419: 	       VTY_NEWLINE);
 1420: 
 1421:       if (area->ip_circuits > 0 && area->spftree[0]
 1422: 	  && area->spftree[0]->paths->count > 0)
 1423: 	{
 1424: 	  vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
 1425: 		   VTY_NEWLINE);
 1426: 	  isis_print_paths (vty, area->spftree[0]->paths);
 1427: 	}
 1428: #ifdef HAVE_IPV6
 1429:       if (area->ipv6_circuits > 0 && area->spftree6[0]
 1430: 	  && area->spftree6[0]->paths->count > 0)
 1431: 	{
 1432: 	  vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
 1433: 		   VTY_NEWLINE);
 1434: 	  isis_print_paths (vty, area->spftree6[0]->paths);
 1435: 	}
 1436: #endif /* HAVE_IPV6 */
 1437:     }
 1438: 
 1439:   return CMD_SUCCESS;
 1440: }
 1441: 
 1442: DEFUN (show_isis_topology_l2,
 1443:        show_isis_topology_l2_cmd,
 1444:        "show isis topology level-2",
 1445:        SHOW_STR
 1446:        "IS-IS information\n"
 1447:        "IS-IS paths to Intermediate Systems\n"
 1448:        "Paths to all level-2 routers in the domain\n")
 1449: {
 1450:   struct listnode *node;
 1451:   struct isis_area *area;
 1452: 
 1453:   if (!isis->area_list || isis->area_list->count == 0)
 1454:     return CMD_SUCCESS;
 1455: 
 1456:   for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
 1457:     {
 1458:       vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
 1459: 	       VTY_NEWLINE);
 1460: 
 1461:       if (area->ip_circuits > 0 && area->spftree[1]
 1462: 	  && area->spftree[1]->paths->count > 0)
 1463: 	{
 1464: 	  vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
 1465: 		   VTY_NEWLINE);
 1466: 	  isis_print_paths (vty, area->spftree[1]->paths);
 1467: 	}
 1468: #ifdef HAVE_IPV6
 1469:       if (area->ipv6_circuits > 0 && area->spftree6[1]
 1470: 	  && area->spftree6[1]->paths->count > 0)
 1471: 	{
 1472: 	  vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
 1473: 		   VTY_NEWLINE);
 1474: 	  isis_print_paths (vty, area->spftree6[1]->paths);
 1475: 	}
 1476: #endif /* HAVE_IPV6 */
 1477:     }
 1478: 
 1479:   return CMD_SUCCESS;
 1480: }
 1481: 
 1482: void
 1483: isis_spf_cmds_init ()
 1484: {
 1485:   install_element (VIEW_NODE, &show_isis_topology_cmd);
 1486:   install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
 1487:   install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
 1488: 
 1489:   install_element (ENABLE_NODE, &show_isis_topology_cmd);
 1490:   install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
 1491:   install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
 1492: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>