Annotation of embedaddon/quagga/ospf6d/ospf6_spf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2003 Yasuhiro Ohara
! 3: *
! 4: * This file is part of GNU Zebra.
! 5: *
! 6: * GNU Zebra is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2, or (at your option) any
! 9: * later version.
! 10: *
! 11: * GNU Zebra is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: * General Public License for more details.
! 15: *
! 16: * You should have received a copy of the GNU General Public License
! 17: * along with GNU Zebra; see the file COPYING. If not, write to the
! 18: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
! 19: * Boston, MA 02111-1307, USA.
! 20: */
! 21:
! 22: /* Shortest Path First calculation for OSPFv3 */
! 23:
! 24: #include <zebra.h>
! 25:
! 26: #include "log.h"
! 27: #include "memory.h"
! 28: #include "command.h"
! 29: #include "vty.h"
! 30: #include "prefix.h"
! 31: #include "pqueue.h"
! 32: #include "linklist.h"
! 33: #include "thread.h"
! 34:
! 35: #include "ospf6_lsa.h"
! 36: #include "ospf6_lsdb.h"
! 37: #include "ospf6_route.h"
! 38: #include "ospf6_area.h"
! 39: #include "ospf6_spf.h"
! 40: #include "ospf6_intra.h"
! 41: #include "ospf6_interface.h"
! 42: #include "ospf6d.h"
! 43:
! 44: unsigned char conf_debug_ospf6_spf = 0;
! 45:
! 46: static int
! 47: ospf6_vertex_cmp (void *a, void *b)
! 48: {
! 49: struct ospf6_vertex *va = (struct ospf6_vertex *) a;
! 50: struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
! 51:
! 52: /* ascending order */
! 53: if (va->cost != vb->cost)
! 54: return (va->cost - vb->cost);
! 55: return (va->hops - vb->hops);
! 56: }
! 57:
! 58: static int
! 59: ospf6_vertex_id_cmp (void *a, void *b)
! 60: {
! 61: struct ospf6_vertex *va = (struct ospf6_vertex *) a;
! 62: struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
! 63: int ret = 0;
! 64:
! 65: ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
! 66: ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
! 67: if (ret)
! 68: return ret;
! 69:
! 70: ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
! 71: ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
! 72: return ret;
! 73: }
! 74:
! 75: static struct ospf6_vertex *
! 76: ospf6_vertex_create (struct ospf6_lsa *lsa)
! 77: {
! 78: struct ospf6_vertex *v;
! 79: int i;
! 80:
! 81: v = (struct ospf6_vertex *)
! 82: XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
! 83:
! 84: /* type */
! 85: if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
! 86: v->type = OSPF6_VERTEX_TYPE_ROUTER;
! 87: else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
! 88: v->type = OSPF6_VERTEX_TYPE_NETWORK;
! 89: else
! 90: assert (0);
! 91:
! 92: /* vertex_id */
! 93: ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
! 94: &v->vertex_id);
! 95:
! 96: /* name */
! 97: ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
! 98:
! 99: /* Associated LSA */
! 100: v->lsa = lsa;
! 101:
! 102: /* capability bits + options */
! 103: v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
! 104: v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
! 105: v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
! 106: v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
! 107:
! 108: for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
! 109: ospf6_nexthop_clear (&v->nexthop[i]);
! 110:
! 111: v->parent = NULL;
! 112: v->child_list = list_new ();
! 113: v->child_list->cmp = ospf6_vertex_id_cmp;
! 114:
! 115: return v;
! 116: }
! 117:
! 118: static void
! 119: ospf6_vertex_delete (struct ospf6_vertex *v)
! 120: {
! 121: list_delete (v->child_list);
! 122: XFREE (MTYPE_OSPF6_VERTEX, v);
! 123: }
! 124:
! 125: static struct ospf6_lsa *
! 126: ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
! 127: {
! 128: struct ospf6_lsa *lsa;
! 129: u_int16_t type = 0;
! 130: u_int32_t id = 0, adv_router = 0;
! 131:
! 132: if (VERTEX_IS_TYPE (NETWORK, v))
! 133: {
! 134: type = htons (OSPF6_LSTYPE_ROUTER);
! 135: id = htonl (0);
! 136: adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
! 137: }
! 138: else
! 139: {
! 140: if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
! 141: {
! 142: type = htons (OSPF6_LSTYPE_ROUTER);
! 143: id = htonl (0);
! 144: adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
! 145: }
! 146: else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
! 147: {
! 148: type = htons (OSPF6_LSTYPE_NETWORK);
! 149: id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
! 150: adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
! 151: }
! 152: }
! 153:
! 154: lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
! 155:
! 156: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 157: {
! 158: char ibuf[16], abuf[16];
! 159: inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
! 160: inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
! 161: if (lsa)
! 162: zlog_debug (" Link to: %s", lsa->name);
! 163: else
! 164: zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
! 165: ospf6_lstype_name (type), ibuf, abuf);
! 166: }
! 167:
! 168: return lsa;
! 169: }
! 170:
! 171: static char *
! 172: ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
! 173: caddr_t lsdesc, struct ospf6_vertex *v)
! 174: {
! 175: caddr_t backlink, found = NULL;
! 176: int size;
! 177:
! 178: size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
! 179: sizeof (struct ospf6_router_lsdesc) :
! 180: sizeof (struct ospf6_network_lsdesc));
! 181: for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
! 182: backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
! 183: {
! 184: assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
! 185: VERTEX_IS_TYPE (NETWORK, v)));
! 186:
! 187: if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
! 188: NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
! 189: == v->lsa->header->adv_router)
! 190: found = backlink;
! 191: else if (VERTEX_IS_TYPE (NETWORK, v) &&
! 192: ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
! 193: ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
! 194: == v->lsa->header->adv_router &&
! 195: ROUTER_LSDESC_GET_NBR_IFID (backlink)
! 196: == ntohl (v->lsa->header->id))
! 197: found = backlink;
! 198: else
! 199: {
! 200: if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
! 201: ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
! 202: continue;
! 203: if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
! 204: ROUTER_LSDESC_GET_IFID (lsdesc) ||
! 205: ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
! 206: ROUTER_LSDESC_GET_IFID (backlink))
! 207: continue;
! 208: if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
! 209: v->lsa->header->adv_router ||
! 210: ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
! 211: lsa->header->adv_router)
! 212: continue;
! 213: found = backlink;
! 214: }
! 215: }
! 216:
! 217: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 218: zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
! 219:
! 220: return found;
! 221: }
! 222:
! 223: static void
! 224: ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
! 225: caddr_t lsdesc)
! 226: {
! 227: int i, ifindex;
! 228: struct ospf6_interface *oi;
! 229: u_int16_t type;
! 230: u_int32_t adv_router;
! 231: struct ospf6_lsa *lsa;
! 232: struct ospf6_link_lsa *link_lsa;
! 233: char buf[64];
! 234:
! 235: assert (VERTEX_IS_TYPE (ROUTER, w));
! 236: ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
! 237: ROUTER_LSDESC_GET_IFID (lsdesc));
! 238: oi = ospf6_interface_lookup_by_ifindex (ifindex);
! 239: if (oi == NULL)
! 240: {
! 241: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 242: zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
! 243: return;
! 244: }
! 245:
! 246: type = htons (OSPF6_LSTYPE_LINK);
! 247: adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
! 248: NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
! 249: ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
! 250:
! 251: i = 0;
! 252: for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
! 253: lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
! 254: {
! 255: if (VERTEX_IS_TYPE (ROUTER, v) &&
! 256: htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
! 257: continue;
! 258:
! 259: link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
! 260: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 261: {
! 262: inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
! 263: zlog_debug (" nexthop %s from %s", buf, lsa->name);
! 264: }
! 265:
! 266: if (i < OSPF6_MULTI_PATH_LIMIT)
! 267: {
! 268: memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
! 269: sizeof (struct in6_addr));
! 270: w->nexthop[i].ifindex = ifindex;
! 271: i++;
! 272: }
! 273: }
! 274:
! 275: if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
! 276: zlog_debug ("No nexthop for %s found", w->name);
! 277: }
! 278:
! 279: static int
! 280: ospf6_spf_install (struct ospf6_vertex *v,
! 281: struct ospf6_route_table *result_table)
! 282: {
! 283: struct ospf6_route *route;
! 284: int i, j;
! 285: struct ospf6_vertex *prev;
! 286:
! 287: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 288: zlog_debug ("SPF install %s hops %d cost %d",
! 289: v->name, v->hops, v->cost);
! 290:
! 291: route = ospf6_route_lookup (&v->vertex_id, result_table);
! 292: if (route && route->path.cost < v->cost)
! 293: {
! 294: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 295: zlog_debug (" already installed with lower cost (%d), ignore",
! 296: route->path.cost);
! 297: ospf6_vertex_delete (v);
! 298: return -1;
! 299: }
! 300: else if (route && route->path.cost == v->cost)
! 301: {
! 302: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 303: zlog_debug (" another path found, merge");
! 304:
! 305: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
! 306: i < OSPF6_MULTI_PATH_LIMIT; i++)
! 307: {
! 308: for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
! 309: {
! 310: if (ospf6_nexthop_is_set (&route->nexthop[j]))
! 311: {
! 312: if (ospf6_nexthop_is_same (&route->nexthop[j],
! 313: &v->nexthop[i]))
! 314: break;
! 315: else
! 316: continue;
! 317: }
! 318: ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
! 319: break;
! 320: }
! 321: }
! 322:
! 323: prev = (struct ospf6_vertex *) route->route_option;
! 324: assert (prev->hops <= v->hops);
! 325: ospf6_vertex_delete (v);
! 326:
! 327: return -1;
! 328: }
! 329:
! 330: /* There should be no case where candidate being installed (variable
! 331: "v") is closer than the one in the SPF tree (variable "route").
! 332: In the case something has gone wrong with the behavior of
! 333: Priority-Queue. */
! 334:
! 335: /* the case where the route exists already is handled and returned
! 336: up to here. */
! 337: assert (route == NULL);
! 338:
! 339: route = ospf6_route_create ();
! 340: memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
! 341: route->type = OSPF6_DEST_TYPE_LINKSTATE;
! 342: route->path.type = OSPF6_PATH_TYPE_INTRA;
! 343: route->path.origin.type = v->lsa->header->type;
! 344: route->path.origin.id = v->lsa->header->id;
! 345: route->path.origin.adv_router = v->lsa->header->adv_router;
! 346: route->path.metric_type = 1;
! 347: route->path.cost = v->cost;
! 348: route->path.cost_e2 = v->hops;
! 349: route->path.router_bits = v->capability;
! 350: route->path.options[0] = v->options[0];
! 351: route->path.options[1] = v->options[1];
! 352: route->path.options[2] = v->options[2];
! 353:
! 354: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
! 355: i < OSPF6_MULTI_PATH_LIMIT; i++)
! 356: ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
! 357:
! 358: if (v->parent)
! 359: listnode_add_sort (v->parent->child_list, v);
! 360: route->route_option = v;
! 361:
! 362: ospf6_route_add (route, result_table);
! 363: return 0;
! 364: }
! 365:
! 366: void
! 367: ospf6_spf_table_finish (struct ospf6_route_table *result_table)
! 368: {
! 369: struct ospf6_route *route;
! 370: struct ospf6_vertex *v;
! 371: for (route = ospf6_route_head (result_table); route;
! 372: route = ospf6_route_next (route))
! 373: {
! 374: v = (struct ospf6_vertex *) route->route_option;
! 375: ospf6_vertex_delete (v);
! 376: ospf6_route_remove (route, result_table);
! 377: }
! 378: }
! 379:
! 380: /* RFC2328 16.1. Calculating the shortest-path tree for an area */
! 381: /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
! 382: void
! 383: ospf6_spf_calculation (u_int32_t router_id,
! 384: struct ospf6_route_table *result_table,
! 385: struct ospf6_area *oa)
! 386: {
! 387: struct pqueue *candidate_list;
! 388: struct ospf6_vertex *root, *v, *w;
! 389: int i;
! 390: int size;
! 391: caddr_t lsdesc;
! 392: struct ospf6_lsa *lsa;
! 393:
! 394: /* Install the calculating router itself as the root of the SPF tree */
! 395: /* construct root vertex */
! 396: lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
! 397: router_id, oa->lsdb);
! 398: if (lsa == NULL)
! 399: return;
! 400:
! 401: /* initialize */
! 402: candidate_list = pqueue_create ();
! 403: candidate_list->cmp = ospf6_vertex_cmp;
! 404:
! 405: ospf6_spf_table_finish (result_table);
! 406:
! 407: root = ospf6_vertex_create (lsa);
! 408: root->area = oa;
! 409: root->cost = 0;
! 410: root->hops = 0;
! 411: root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
! 412: inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
! 413:
! 414: /* Actually insert root to the candidate-list as the only candidate */
! 415: pqueue_enqueue (root, candidate_list);
! 416:
! 417: /* Iterate until candidate-list becomes empty */
! 418: while (candidate_list->size)
! 419: {
! 420: /* get closest candidate from priority queue */
! 421: v = pqueue_dequeue (candidate_list);
! 422:
! 423: /* installing may result in merging or rejecting of the vertex */
! 424: if (ospf6_spf_install (v, result_table) < 0)
! 425: continue;
! 426:
! 427: /* For each LS description in the just-added vertex V's LSA */
! 428: size = (VERTEX_IS_TYPE (ROUTER, v) ?
! 429: sizeof (struct ospf6_router_lsdesc) :
! 430: sizeof (struct ospf6_network_lsdesc));
! 431: for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
! 432: lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
! 433: {
! 434: lsa = ospf6_lsdesc_lsa (lsdesc, v);
! 435: if (lsa == NULL)
! 436: continue;
! 437:
! 438: if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
! 439: continue;
! 440:
! 441: w = ospf6_vertex_create (lsa);
! 442: w->area = oa;
! 443: w->parent = v;
! 444: if (VERTEX_IS_TYPE (ROUTER, v))
! 445: {
! 446: w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
! 447: w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
! 448: }
! 449: else /* NETWORK */
! 450: {
! 451: w->cost = v->cost;
! 452: w->hops = v->hops + 1;
! 453: }
! 454:
! 455: /* nexthop calculation */
! 456: if (w->hops == 0)
! 457: w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
! 458: else if (w->hops == 1 && v->hops == 0)
! 459: ospf6_nexthop_calc (w, v, lsdesc);
! 460: else
! 461: {
! 462: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
! 463: i < OSPF6_MULTI_PATH_LIMIT; i++)
! 464: ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
! 465: }
! 466:
! 467: /* add new candidate to the candidate_list */
! 468: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 469: zlog_debug (" New candidate: %s hops %d cost %d",
! 470: w->name, w->hops, w->cost);
! 471: pqueue_enqueue (w, candidate_list);
! 472: }
! 473: }
! 474:
! 475: pqueue_delete (candidate_list);
! 476: }
! 477:
! 478: static void
! 479: ospf6_spf_log_database (struct ospf6_area *oa)
! 480: {
! 481: char *p, *end, buffer[256];
! 482: struct listnode *node;
! 483: struct ospf6_interface *oi;
! 484:
! 485: p = buffer;
! 486: end = buffer + sizeof (buffer);
! 487:
! 488: snprintf (p, end - p, "SPF on DB (#LSAs):");
! 489: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
! 490: snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
! 491: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
! 492:
! 493: for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
! 494: {
! 495: snprintf (p, end - p, " I/F %s: %d",
! 496: oi->interface->name, oi->lsdb->count);
! 497: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
! 498: }
! 499:
! 500: zlog_debug ("%s", buffer);
! 501: }
! 502:
! 503: static int
! 504: ospf6_spf_calculation_thread (struct thread *t)
! 505: {
! 506: struct ospf6_area *oa;
! 507: struct timeval start, end, runtime;
! 508:
! 509: oa = (struct ospf6_area *) THREAD_ARG (t);
! 510: oa->thread_spf_calculation = NULL;
! 511:
! 512: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 513: zlog_debug ("SPF calculation for Area %s", oa->name);
! 514: if (IS_OSPF6_DEBUG_SPF (DATABASE))
! 515: ospf6_spf_log_database (oa);
! 516:
! 517: /* execute SPF calculation */
! 518: quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
! 519: ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa);
! 520: quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
! 521: timersub (&end, &start, &runtime);
! 522:
! 523: if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
! 524: zlog_debug ("SPF runtime: %ld sec %ld usec",
! 525: runtime.tv_sec, runtime.tv_usec);
! 526:
! 527: ospf6_intra_route_calculation (oa);
! 528: ospf6_intra_brouter_calculation (oa);
! 529:
! 530: return 0;
! 531: }
! 532:
! 533: void
! 534: ospf6_spf_schedule (struct ospf6_area *oa)
! 535: {
! 536: if (oa->thread_spf_calculation)
! 537: return;
! 538: oa->thread_spf_calculation =
! 539: thread_add_event (master, ospf6_spf_calculation_thread, oa, 0);
! 540: }
! 541:
! 542: void
! 543: ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
! 544: struct ospf6_vertex *v)
! 545: {
! 546: struct listnode *node, *nnode;
! 547: struct ospf6_vertex *c;
! 548: char *next_prefix;
! 549: int len;
! 550: int restnum;
! 551:
! 552: /* "prefix" is the space prefix of the display line */
! 553: vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
! 554:
! 555: len = strlen (prefix) + 4;
! 556: next_prefix = (char *) malloc (len);
! 557: if (next_prefix == NULL)
! 558: {
! 559: vty_out (vty, "malloc failed%s", VNL);
! 560: return;
! 561: }
! 562: snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
! 563:
! 564: restnum = listcount (v->child_list);
! 565: for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
! 566: {
! 567: restnum--;
! 568: ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
! 569: }
! 570:
! 571: free (next_prefix);
! 572: }
! 573:
! 574: DEFUN (debug_ospf6_spf_process,
! 575: debug_ospf6_spf_process_cmd,
! 576: "debug ospf6 spf process",
! 577: DEBUG_STR
! 578: OSPF6_STR
! 579: "Debug SPF Calculation\n"
! 580: "Debug Detailed SPF Process\n"
! 581: )
! 582: {
! 583: unsigned char level = 0;
! 584: level = OSPF6_DEBUG_SPF_PROCESS;
! 585: OSPF6_DEBUG_SPF_ON (level);
! 586: return CMD_SUCCESS;
! 587: }
! 588:
! 589: DEFUN (debug_ospf6_spf_time,
! 590: debug_ospf6_spf_time_cmd,
! 591: "debug ospf6 spf time",
! 592: DEBUG_STR
! 593: OSPF6_STR
! 594: "Debug SPF Calculation\n"
! 595: "Measure time taken by SPF Calculation\n"
! 596: )
! 597: {
! 598: unsigned char level = 0;
! 599: level = OSPF6_DEBUG_SPF_TIME;
! 600: OSPF6_DEBUG_SPF_ON (level);
! 601: return CMD_SUCCESS;
! 602: }
! 603:
! 604: DEFUN (debug_ospf6_spf_database,
! 605: debug_ospf6_spf_database_cmd,
! 606: "debug ospf6 spf database",
! 607: DEBUG_STR
! 608: OSPF6_STR
! 609: "Debug SPF Calculation\n"
! 610: "Log number of LSAs at SPF Calculation time\n"
! 611: )
! 612: {
! 613: unsigned char level = 0;
! 614: level = OSPF6_DEBUG_SPF_DATABASE;
! 615: OSPF6_DEBUG_SPF_ON (level);
! 616: return CMD_SUCCESS;
! 617: }
! 618:
! 619: DEFUN (no_debug_ospf6_spf_process,
! 620: no_debug_ospf6_spf_process_cmd,
! 621: "no debug ospf6 spf process",
! 622: NO_STR
! 623: DEBUG_STR
! 624: OSPF6_STR
! 625: "Quit Debugging SPF Calculation\n"
! 626: "Quit Debugging Detailed SPF Process\n"
! 627: )
! 628: {
! 629: unsigned char level = 0;
! 630: level = OSPF6_DEBUG_SPF_PROCESS;
! 631: OSPF6_DEBUG_SPF_OFF (level);
! 632: return CMD_SUCCESS;
! 633: }
! 634:
! 635: DEFUN (no_debug_ospf6_spf_time,
! 636: no_debug_ospf6_spf_time_cmd,
! 637: "no debug ospf6 spf time",
! 638: NO_STR
! 639: DEBUG_STR
! 640: OSPF6_STR
! 641: "Quit Debugging SPF Calculation\n"
! 642: "Quit Measuring time taken by SPF Calculation\n"
! 643: )
! 644: {
! 645: unsigned char level = 0;
! 646: level = OSPF6_DEBUG_SPF_TIME;
! 647: OSPF6_DEBUG_SPF_OFF (level);
! 648: return CMD_SUCCESS;
! 649: }
! 650:
! 651: DEFUN (no_debug_ospf6_spf_database,
! 652: no_debug_ospf6_spf_database_cmd,
! 653: "no debug ospf6 spf database",
! 654: NO_STR
! 655: DEBUG_STR
! 656: OSPF6_STR
! 657: "Debug SPF Calculation\n"
! 658: "Quit Logging number of LSAs at SPF Calculation time\n"
! 659: )
! 660: {
! 661: unsigned char level = 0;
! 662: level = OSPF6_DEBUG_SPF_DATABASE;
! 663: OSPF6_DEBUG_SPF_OFF (level);
! 664: return CMD_SUCCESS;
! 665: }
! 666:
! 667: int
! 668: config_write_ospf6_debug_spf (struct vty *vty)
! 669: {
! 670: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 671: vty_out (vty, "debug ospf6 spf process%s", VNL);
! 672: if (IS_OSPF6_DEBUG_SPF (TIME))
! 673: vty_out (vty, "debug ospf6 spf time%s", VNL);
! 674: if (IS_OSPF6_DEBUG_SPF (DATABASE))
! 675: vty_out (vty, "debug ospf6 spf database%s", VNL);
! 676: return 0;
! 677: }
! 678:
! 679: void
! 680: install_element_ospf6_debug_spf (void)
! 681: {
! 682: install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
! 683: install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
! 684: install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
! 685: install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
! 686: install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
! 687: install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
! 688: install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
! 689: install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
! 690: install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
! 691: install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
! 692: install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
! 693: install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
! 694: }
! 695:
! 696: void
! 697: ospf6_spf_init (void)
! 698: {
! 699: }
! 700:
! 701:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>