Annotation of embedaddon/quagga/ospf6d/ospf6_spf.c, revision 1.1.1.4
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"
1.1.1.4 ! misho 43: #include "ospf6_abr.h"
1.1 misho 44:
45: unsigned char conf_debug_ospf6_spf = 0;
46:
47: static int
48: ospf6_vertex_cmp (void *a, void *b)
49: {
50: struct ospf6_vertex *va = (struct ospf6_vertex *) a;
51: struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
52:
53: /* ascending order */
54: if (va->cost != vb->cost)
55: return (va->cost - vb->cost);
56: return (va->hops - vb->hops);
57: }
58:
59: static int
60: ospf6_vertex_id_cmp (void *a, void *b)
61: {
62: struct ospf6_vertex *va = (struct ospf6_vertex *) a;
63: struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
64: int ret = 0;
65:
66: ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
67: ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
68: if (ret)
69: return ret;
70:
71: ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
72: ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
73: return ret;
74: }
75:
76: static struct ospf6_vertex *
77: ospf6_vertex_create (struct ospf6_lsa *lsa)
78: {
79: struct ospf6_vertex *v;
80: int i;
81:
82: v = (struct ospf6_vertex *)
83: XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
84:
85: /* type */
86: if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
87: v->type = OSPF6_VERTEX_TYPE_ROUTER;
88: else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
89: v->type = OSPF6_VERTEX_TYPE_NETWORK;
90: else
91: assert (0);
92:
93: /* vertex_id */
94: ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
95: &v->vertex_id);
96:
97: /* name */
98: ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
99:
100: /* Associated LSA */
101: v->lsa = lsa;
102:
103: /* capability bits + options */
104: v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
105: v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
106: v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
107: v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
108:
109: for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
110: ospf6_nexthop_clear (&v->nexthop[i]);
111:
112: v->parent = NULL;
113: v->child_list = list_new ();
114: v->child_list->cmp = ospf6_vertex_id_cmp;
115:
116: return v;
117: }
118:
119: static void
120: ospf6_vertex_delete (struct ospf6_vertex *v)
121: {
122: list_delete (v->child_list);
123: XFREE (MTYPE_OSPF6_VERTEX, v);
124: }
125:
126: static struct ospf6_lsa *
127: ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
128: {
129: struct ospf6_lsa *lsa;
130: u_int16_t type = 0;
131: u_int32_t id = 0, adv_router = 0;
132:
133: if (VERTEX_IS_TYPE (NETWORK, v))
134: {
135: type = htons (OSPF6_LSTYPE_ROUTER);
136: id = htonl (0);
137: adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
138: }
139: else
140: {
141: if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
142: {
143: type = htons (OSPF6_LSTYPE_ROUTER);
144: id = htonl (0);
145: adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
146: }
147: else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
148: {
149: type = htons (OSPF6_LSTYPE_NETWORK);
150: id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
151: adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
152: }
153: }
154:
155: lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
156:
157: if (IS_OSPF6_DEBUG_SPF (PROCESS))
158: {
159: char ibuf[16], abuf[16];
160: inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
161: inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
162: if (lsa)
163: zlog_debug (" Link to: %s", lsa->name);
164: else
165: zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
166: ospf6_lstype_name (type), ibuf, abuf);
167: }
168:
169: return lsa;
170: }
171:
172: static char *
173: ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
174: caddr_t lsdesc, struct ospf6_vertex *v)
175: {
176: caddr_t backlink, found = NULL;
177: int size;
178:
179: size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
180: sizeof (struct ospf6_router_lsdesc) :
181: sizeof (struct ospf6_network_lsdesc));
182: for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
183: backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
184: {
185: assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
186: VERTEX_IS_TYPE (NETWORK, v)));
187:
188: if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
189: NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
190: == v->lsa->header->adv_router)
191: found = backlink;
192: else if (VERTEX_IS_TYPE (NETWORK, v) &&
193: ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
194: ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
195: == v->lsa->header->adv_router &&
196: ROUTER_LSDESC_GET_NBR_IFID (backlink)
197: == ntohl (v->lsa->header->id))
198: found = backlink;
199: else
200: {
201: if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
202: ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
203: continue;
204: if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
205: ROUTER_LSDESC_GET_IFID (lsdesc) ||
206: ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
207: ROUTER_LSDESC_GET_IFID (backlink))
208: continue;
209: if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
210: v->lsa->header->adv_router ||
211: ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
212: lsa->header->adv_router)
213: continue;
214: found = backlink;
215: }
216: }
217:
218: if (IS_OSPF6_DEBUG_SPF (PROCESS))
219: zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
220:
221: return found;
222: }
223:
224: static void
225: ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
226: caddr_t lsdesc)
227: {
1.1.1.4 ! misho 228: int i;
! 229: ifindex_t ifindex;
1.1 misho 230: struct ospf6_interface *oi;
231: u_int16_t type;
232: u_int32_t adv_router;
233: struct ospf6_lsa *lsa;
234: struct ospf6_link_lsa *link_lsa;
235: char buf[64];
236:
237: assert (VERTEX_IS_TYPE (ROUTER, w));
238: ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
1.1.1.4 ! misho 239: /* v is the local router & the interface_id is a local ifindex */
! 240: (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc));
! 241: assert (ifindex >= 0);
! 242:
1.1 misho 243: oi = ospf6_interface_lookup_by_ifindex (ifindex);
244: if (oi == NULL)
245: {
246: if (IS_OSPF6_DEBUG_SPF (PROCESS))
247: zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
248: return;
249: }
250:
251: type = htons (OSPF6_LSTYPE_LINK);
252: adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
253: NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
254: ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
255:
256: i = 0;
257: for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
258: lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
259: {
260: if (VERTEX_IS_TYPE (ROUTER, v) &&
261: htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
262: continue;
263:
264: link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
265: if (IS_OSPF6_DEBUG_SPF (PROCESS))
266: {
267: inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
268: zlog_debug (" nexthop %s from %s", buf, lsa->name);
269: }
270:
271: if (i < OSPF6_MULTI_PATH_LIMIT)
272: {
273: memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
274: sizeof (struct in6_addr));
275: w->nexthop[i].ifindex = ifindex;
276: i++;
277: }
278: }
279:
280: if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
281: zlog_debug ("No nexthop for %s found", w->name);
282: }
283:
284: static int
285: ospf6_spf_install (struct ospf6_vertex *v,
286: struct ospf6_route_table *result_table)
287: {
288: struct ospf6_route *route;
289: int i, j;
290: struct ospf6_vertex *prev;
291:
292: if (IS_OSPF6_DEBUG_SPF (PROCESS))
293: zlog_debug ("SPF install %s hops %d cost %d",
294: v->name, v->hops, v->cost);
295:
296: route = ospf6_route_lookup (&v->vertex_id, result_table);
297: if (route && route->path.cost < v->cost)
298: {
299: if (IS_OSPF6_DEBUG_SPF (PROCESS))
300: zlog_debug (" already installed with lower cost (%d), ignore",
301: route->path.cost);
302: ospf6_vertex_delete (v);
303: return -1;
304: }
305: else if (route && route->path.cost == v->cost)
306: {
307: if (IS_OSPF6_DEBUG_SPF (PROCESS))
308: zlog_debug (" another path found, merge");
309:
310: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
311: i < OSPF6_MULTI_PATH_LIMIT; i++)
312: {
313: for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
314: {
315: if (ospf6_nexthop_is_set (&route->nexthop[j]))
316: {
317: if (ospf6_nexthop_is_same (&route->nexthop[j],
318: &v->nexthop[i]))
319: break;
320: else
321: continue;
322: }
323: ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
324: break;
325: }
326: }
327:
328: prev = (struct ospf6_vertex *) route->route_option;
329: assert (prev->hops <= v->hops);
330: ospf6_vertex_delete (v);
331:
332: return -1;
333: }
334:
335: /* There should be no case where candidate being installed (variable
336: "v") is closer than the one in the SPF tree (variable "route").
337: In the case something has gone wrong with the behavior of
338: Priority-Queue. */
339:
340: /* the case where the route exists already is handled and returned
341: up to here. */
342: assert (route == NULL);
343:
344: route = ospf6_route_create ();
345: memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
346: route->type = OSPF6_DEST_TYPE_LINKSTATE;
347: route->path.type = OSPF6_PATH_TYPE_INTRA;
348: route->path.origin.type = v->lsa->header->type;
349: route->path.origin.id = v->lsa->header->id;
350: route->path.origin.adv_router = v->lsa->header->adv_router;
351: route->path.metric_type = 1;
352: route->path.cost = v->cost;
353: route->path.cost_e2 = v->hops;
354: route->path.router_bits = v->capability;
355: route->path.options[0] = v->options[0];
356: route->path.options[1] = v->options[1];
357: route->path.options[2] = v->options[2];
358:
359: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
360: i < OSPF6_MULTI_PATH_LIMIT; i++)
361: ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
362:
363: if (v->parent)
364: listnode_add_sort (v->parent->child_list, v);
365: route->route_option = v;
366:
367: ospf6_route_add (route, result_table);
368: return 0;
369: }
370:
371: void
372: ospf6_spf_table_finish (struct ospf6_route_table *result_table)
373: {
374: struct ospf6_route *route;
375: struct ospf6_vertex *v;
376: for (route = ospf6_route_head (result_table); route;
377: route = ospf6_route_next (route))
378: {
379: v = (struct ospf6_vertex *) route->route_option;
380: ospf6_vertex_delete (v);
381: ospf6_route_remove (route, result_table);
382: }
383: }
384:
1.1.1.4 ! misho 385: static const char *ospf6_spf_reason_str[] =
! 386: {
! 387: "R+",
! 388: "R-",
! 389: "N+",
! 390: "N-",
! 391: "L+",
! 392: "L-",
! 393: "R*",
! 394: "N*",
! 395: };
! 396:
! 397: void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
! 398: {
! 399: size_t bit;
! 400: int len = 0;
! 401:
! 402: if (!buf)
! 403: return;
! 404:
! 405: for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++)
! 406: {
! 407: if ((reason & (1 << bit)) && (len < size))
! 408: {
! 409: len += snprintf((buf + len), (size - len), "%s%s",
! 410: (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]);
! 411: }
! 412: }
! 413: }
! 414:
1.1 misho 415: /* RFC2328 16.1. Calculating the shortest-path tree for an area */
416: /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
417: void
418: ospf6_spf_calculation (u_int32_t router_id,
419: struct ospf6_route_table *result_table,
420: struct ospf6_area *oa)
421: {
422: struct pqueue *candidate_list;
423: struct ospf6_vertex *root, *v, *w;
424: int i;
425: int size;
426: caddr_t lsdesc;
427: struct ospf6_lsa *lsa;
428:
1.1.1.2 misho 429: ospf6_spf_table_finish (result_table);
430:
1.1 misho 431: /* Install the calculating router itself as the root of the SPF tree */
432: /* construct root vertex */
433: lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
434: router_id, oa->lsdb);
435: if (lsa == NULL)
436: return;
437:
438: /* initialize */
439: candidate_list = pqueue_create ();
440: candidate_list->cmp = ospf6_vertex_cmp;
441:
442: root = ospf6_vertex_create (lsa);
443: root->area = oa;
444: root->cost = 0;
445: root->hops = 0;
446: root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
447: inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
448:
449: /* Actually insert root to the candidate-list as the only candidate */
450: pqueue_enqueue (root, candidate_list);
451:
452: /* Iterate until candidate-list becomes empty */
453: while (candidate_list->size)
454: {
455: /* get closest candidate from priority queue */
456: v = pqueue_dequeue (candidate_list);
457:
458: /* installing may result in merging or rejecting of the vertex */
459: if (ospf6_spf_install (v, result_table) < 0)
460: continue;
461:
1.1.1.4 ! misho 462: /* Skip overloaded routers */
! 463: if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
! 464: ospf6_router_is_stub_router (v->lsa)))
! 465: continue;
! 466:
1.1 misho 467: /* For each LS description in the just-added vertex V's LSA */
468: size = (VERTEX_IS_TYPE (ROUTER, v) ?
469: sizeof (struct ospf6_router_lsdesc) :
470: sizeof (struct ospf6_network_lsdesc));
471: for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
472: lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
473: {
474: lsa = ospf6_lsdesc_lsa (lsdesc, v);
475: if (lsa == NULL)
476: continue;
477:
478: if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
479: continue;
480:
481: w = ospf6_vertex_create (lsa);
482: w->area = oa;
483: w->parent = v;
484: if (VERTEX_IS_TYPE (ROUTER, v))
485: {
486: w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
487: w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
488: }
489: else /* NETWORK */
490: {
491: w->cost = v->cost;
492: w->hops = v->hops + 1;
493: }
494:
495: /* nexthop calculation */
496: if (w->hops == 0)
497: w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
498: else if (w->hops == 1 && v->hops == 0)
499: ospf6_nexthop_calc (w, v, lsdesc);
500: else
501: {
502: for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
503: i < OSPF6_MULTI_PATH_LIMIT; i++)
504: ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
505: }
506:
507: /* add new candidate to the candidate_list */
508: if (IS_OSPF6_DEBUG_SPF (PROCESS))
509: zlog_debug (" New candidate: %s hops %d cost %d",
510: w->name, w->hops, w->cost);
511: pqueue_enqueue (w, candidate_list);
512: }
513: }
514:
515: pqueue_delete (candidate_list);
1.1.1.3 misho 516:
517: oa->spf_calculation++;
1.1 misho 518: }
519:
520: static void
521: ospf6_spf_log_database (struct ospf6_area *oa)
522: {
523: char *p, *end, buffer[256];
524: struct listnode *node;
525: struct ospf6_interface *oi;
526:
527: p = buffer;
528: end = buffer + sizeof (buffer);
529:
530: snprintf (p, end - p, "SPF on DB (#LSAs):");
531: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
532: snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
533: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
534:
535: for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
536: {
537: snprintf (p, end - p, " I/F %s: %d",
538: oi->interface->name, oi->lsdb->count);
539: p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
540: }
541:
542: zlog_debug ("%s", buffer);
543: }
544:
545: static int
546: ospf6_spf_calculation_thread (struct thread *t)
547: {
548: struct ospf6_area *oa;
1.1.1.4 ! misho 549: struct ospf6 *ospf6;
1.1 misho 550: struct timeval start, end, runtime;
1.1.1.4 ! misho 551: struct listnode *node;
! 552: struct ospf6_route *route;
! 553: int areas_processed = 0;
! 554: char rbuf[32];
1.1 misho 555:
1.1.1.4 ! misho 556: ospf6 = (struct ospf6 *)THREAD_ARG (t);
! 557: ospf6->t_spf_calc = NULL;
1.1 misho 558:
559: /* execute SPF calculation */
560: quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
1.1.1.4 ! misho 561:
! 562: for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
! 563: {
! 564:
! 565: if (oa == ospf6->backbone)
! 566: continue;
! 567:
! 568: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 569: zlog_debug ("SPF calculation for Area %s", oa->name);
! 570: if (IS_OSPF6_DEBUG_SPF (DATABASE))
! 571: ospf6_spf_log_database (oa);
! 572:
! 573: ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
! 574: ospf6_intra_route_calculation (oa);
! 575: ospf6_intra_brouter_calculation (oa);
! 576:
! 577: areas_processed++;
! 578: }
! 579:
! 580: if (ospf6->backbone)
! 581: {
! 582: if (IS_OSPF6_DEBUG_SPF (PROCESS))
! 583: zlog_debug ("SPF calculation for Backbone area %s",
! 584: ospf6->backbone->name);
! 585: if (IS_OSPF6_DEBUG_SPF (DATABASE))
! 586: ospf6_spf_log_database(ospf6->backbone);
! 587:
! 588: ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
! 589: ospf6->backbone);
! 590: ospf6_intra_route_calculation(ospf6->backbone);
! 591: ospf6_intra_brouter_calculation(ospf6->backbone);
! 592: areas_processed++;
! 593: }
! 594:
! 595: /* Redo summaries if required */
! 596: for (route = ospf6_route_head (ospf6->route_table); route;
! 597: route = ospf6_route_next (route))
! 598: ospf6_abr_originate_summary(route);
! 599:
1.1 misho 600: quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
601: timersub (&end, &start, &runtime);
602:
1.1.1.4 ! misho 603: ospf6->ts_spf_duration = runtime;
1.1 misho 604:
1.1.1.4 ! misho 605: ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
! 606:
! 607: if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
! 608: zlog_debug ("SPF runtime: %lld sec %lld usec",
! 609: (long long)runtime.tv_sec, (long long)runtime.tv_usec);
1.1 misho 610:
1.1.1.4 ! misho 611: zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
! 612: "Reason: %s\n", areas_processed,
! 613: (long long)runtime.tv_sec, (long long)runtime.tv_usec,
! 614: rbuf);
! 615: ospf6->last_spf_reason = ospf6->spf_reason;
! 616: ospf6_reset_spf_reason(ospf6);
1.1 misho 617: return 0;
618: }
619:
1.1.1.4 ! misho 620: /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
! 621: set timer for SPF calc. */
1.1 misho 622: void
1.1.1.4 ! misho 623: ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
1.1 misho 624: {
1.1.1.4 ! misho 625: unsigned long delay, elapsed, ht;
! 626: struct timeval now, result;
! 627:
! 628: ospf6_set_spf_reason(ospf6, reason);
! 629:
! 630: if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
! 631: {
! 632: char rbuf[32];
! 633: ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
! 634: zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
! 635: }
! 636:
! 637: /* OSPF instance does not exist. */
! 638: if (ospf6 == NULL)
1.1 misho 639: return;
1.1.1.4 ! misho 640:
! 641: /* SPF calculation timer is already scheduled. */
! 642: if (ospf6->t_spf_calc)
! 643: {
! 644: if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
! 645: zlog_debug ("SPF: calculation timer is already scheduled: %p",
! 646: (void *)ospf6->t_spf_calc);
! 647: return;
! 648: }
! 649:
! 650: /* XXX Monotic timers: we only care about relative time here. */
! 651: now = recent_relative_time ();
! 652: timersub (&now, &ospf6->ts_spf, &result);
! 653:
! 654: elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
! 655: ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
! 656:
! 657: if (ht > ospf6->spf_max_holdtime)
! 658: ht = ospf6->spf_max_holdtime;
! 659:
! 660: /* Get SPF calculation delay time. */
! 661: if (elapsed < ht)
! 662: {
! 663: /* Got an event within the hold time of last SPF. We need to
! 664: * increase the hold_multiplier, if it's not already at/past
! 665: * maximum value, and wasn't already increased..
! 666: */
! 667: if (ht < ospf6->spf_max_holdtime)
! 668: ospf6->spf_hold_multiplier++;
! 669:
! 670: /* always honour the SPF initial delay */
! 671: if ( (ht - elapsed) < ospf6->spf_delay)
! 672: delay = ospf6->spf_delay;
! 673: else
! 674: delay = ht - elapsed;
! 675: }
! 676: else
! 677: {
! 678: /* Event is past required hold-time of last SPF */
! 679: delay = ospf6->spf_delay;
! 680: ospf6->spf_hold_multiplier = 1;
! 681: }
! 682:
! 683: if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
! 684: zlog_debug ("SPF: calculation timer delay = %ld", delay);
! 685:
! 686: zlog_info ("SPF: Scheduled in %ld msec", delay);
! 687:
! 688: ospf6->t_spf_calc =
! 689: thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
1.1 misho 690: }
691:
692: void
693: ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
694: struct ospf6_vertex *v)
695: {
696: struct listnode *node, *nnode;
697: struct ospf6_vertex *c;
698: char *next_prefix;
699: int len;
700: int restnum;
701:
702: /* "prefix" is the space prefix of the display line */
703: vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
704:
705: len = strlen (prefix) + 4;
706: next_prefix = (char *) malloc (len);
707: if (next_prefix == NULL)
708: {
709: vty_out (vty, "malloc failed%s", VNL);
710: return;
711: }
712: snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
713:
714: restnum = listcount (v->child_list);
715: for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
716: {
717: restnum--;
718: ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
719: }
720:
721: free (next_prefix);
722: }
723:
724: DEFUN (debug_ospf6_spf_process,
725: debug_ospf6_spf_process_cmd,
726: "debug ospf6 spf process",
727: DEBUG_STR
728: OSPF6_STR
729: "Debug SPF Calculation\n"
730: "Debug Detailed SPF Process\n"
731: )
732: {
733: unsigned char level = 0;
734: level = OSPF6_DEBUG_SPF_PROCESS;
735: OSPF6_DEBUG_SPF_ON (level);
736: return CMD_SUCCESS;
737: }
738:
739: DEFUN (debug_ospf6_spf_time,
740: debug_ospf6_spf_time_cmd,
741: "debug ospf6 spf time",
742: DEBUG_STR
743: OSPF6_STR
744: "Debug SPF Calculation\n"
745: "Measure time taken by SPF Calculation\n"
746: )
747: {
748: unsigned char level = 0;
749: level = OSPF6_DEBUG_SPF_TIME;
750: OSPF6_DEBUG_SPF_ON (level);
751: return CMD_SUCCESS;
752: }
753:
754: DEFUN (debug_ospf6_spf_database,
755: debug_ospf6_spf_database_cmd,
756: "debug ospf6 spf database",
757: DEBUG_STR
758: OSPF6_STR
759: "Debug SPF Calculation\n"
760: "Log number of LSAs at SPF Calculation time\n"
761: )
762: {
763: unsigned char level = 0;
764: level = OSPF6_DEBUG_SPF_DATABASE;
765: OSPF6_DEBUG_SPF_ON (level);
766: return CMD_SUCCESS;
767: }
768:
769: DEFUN (no_debug_ospf6_spf_process,
770: no_debug_ospf6_spf_process_cmd,
771: "no debug ospf6 spf process",
772: NO_STR
773: DEBUG_STR
774: OSPF6_STR
775: "Quit Debugging SPF Calculation\n"
776: "Quit Debugging Detailed SPF Process\n"
777: )
778: {
779: unsigned char level = 0;
780: level = OSPF6_DEBUG_SPF_PROCESS;
781: OSPF6_DEBUG_SPF_OFF (level);
782: return CMD_SUCCESS;
783: }
784:
785: DEFUN (no_debug_ospf6_spf_time,
786: no_debug_ospf6_spf_time_cmd,
787: "no debug ospf6 spf time",
788: NO_STR
789: DEBUG_STR
790: OSPF6_STR
791: "Quit Debugging SPF Calculation\n"
792: "Quit Measuring time taken by SPF Calculation\n"
793: )
794: {
795: unsigned char level = 0;
796: level = OSPF6_DEBUG_SPF_TIME;
797: OSPF6_DEBUG_SPF_OFF (level);
798: return CMD_SUCCESS;
799: }
800:
801: DEFUN (no_debug_ospf6_spf_database,
802: no_debug_ospf6_spf_database_cmd,
803: "no debug ospf6 spf database",
804: NO_STR
805: DEBUG_STR
806: OSPF6_STR
807: "Debug SPF Calculation\n"
808: "Quit Logging number of LSAs at SPF Calculation time\n"
809: )
810: {
811: unsigned char level = 0;
812: level = OSPF6_DEBUG_SPF_DATABASE;
813: OSPF6_DEBUG_SPF_OFF (level);
814: return CMD_SUCCESS;
815: }
816:
1.1.1.4 ! misho 817: static int
! 818: ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
! 819: unsigned int hold,
! 820: unsigned int max)
! 821: {
! 822: struct ospf6 *ospf = vty->index;
! 823:
! 824: ospf->spf_delay = delay;
! 825: ospf->spf_holdtime = hold;
! 826: ospf->spf_max_holdtime = max;
! 827:
! 828: return CMD_SUCCESS;
! 829: }
! 830:
! 831: DEFUN (ospf6_timers_throttle_spf,
! 832: ospf6_timers_throttle_spf_cmd,
! 833: "timers throttle spf <0-600000> <0-600000> <0-600000>",
! 834: "Adjust routing timers\n"
! 835: "Throttling adaptive timer\n"
! 836: "OSPF6 SPF timers\n"
! 837: "Delay (msec) from first change received till SPF calculation\n"
! 838: "Initial hold time (msec) between consecutive SPF calculations\n"
! 839: "Maximum hold time (msec)\n")
! 840: {
! 841: unsigned int delay, hold, max;
! 842:
! 843: if (argc != 3)
! 844: {
! 845: vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
! 846: return CMD_WARNING;
! 847: }
! 848:
! 849: VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
! 850: VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
! 851: VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
! 852:
! 853: return ospf6_timers_spf_set (vty, delay, hold, max);
! 854: }
! 855:
! 856: DEFUN (no_ospf6_timers_throttle_spf,
! 857: no_ospf6_timers_throttle_spf_cmd,
! 858: "no timers throttle spf",
! 859: NO_STR
! 860: "Adjust routing timers\n"
! 861: "Throttling adaptive timer\n"
! 862: "OSPF6 SPF timers\n")
! 863: {
! 864: return ospf6_timers_spf_set (vty,
! 865: OSPF_SPF_DELAY_DEFAULT,
! 866: OSPF_SPF_HOLDTIME_DEFAULT,
! 867: OSPF_SPF_MAX_HOLDTIME_DEFAULT);
! 868: }
! 869:
1.1 misho 870: int
871: config_write_ospf6_debug_spf (struct vty *vty)
872: {
873: if (IS_OSPF6_DEBUG_SPF (PROCESS))
874: vty_out (vty, "debug ospf6 spf process%s", VNL);
875: if (IS_OSPF6_DEBUG_SPF (TIME))
876: vty_out (vty, "debug ospf6 spf time%s", VNL);
877: if (IS_OSPF6_DEBUG_SPF (DATABASE))
878: vty_out (vty, "debug ospf6 spf database%s", VNL);
879: return 0;
880: }
881:
882: void
1.1.1.4 ! misho 883: ospf6_spf_config_write (struct vty *vty)
! 884: {
! 885:
! 886: if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
! 887: ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
! 888: ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
! 889: vty_out (vty, " timers throttle spf %d %d %d%s",
! 890: ospf6->spf_delay, ospf6->spf_holdtime,
! 891: ospf6->spf_max_holdtime, VTY_NEWLINE);
! 892:
! 893: }
! 894:
! 895: void
1.1 misho 896: install_element_ospf6_debug_spf (void)
897: {
898: install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
899: install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
900: install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
901: install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
902: install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
903: install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
904: install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
905: install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
906: install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
907: install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
908: install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
909: install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
910: }
911:
912: void
913: ospf6_spf_init (void)
914: {
1.1.1.4 ! misho 915: install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
! 916: install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
1.1 misho 917: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>