Annotation of embedaddon/quagga/isisd/isis_spf.c, revision 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>