Annotation of embedaddon/quagga/isisd/isis_spf.c, revision 1.1.1.1

1.1       misho       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>