File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ospf6d / ospf6_spf.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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: #include "ospf6_abr.h"
   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: {
  228:   int i;
  229:   ifindex_t ifindex;
  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 :
  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:   
  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: 
  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: 
  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: 
  429:   ospf6_spf_table_finish (result_table);
  430: 
  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: 
  462:       /* Skip overloaded routers */
  463:       if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
  464: 	   ospf6_router_is_stub_router (v->lsa)))
  465: 	continue;
  466: 
  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);
  516: 
  517:   oa->spf_calculation++;
  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;
  549:   struct ospf6 *ospf6;
  550:   struct timeval start, end, runtime;
  551:   struct listnode *node;
  552:   struct ospf6_route *route;
  553:   int areas_processed = 0;
  554:   char rbuf[32];
  555: 
  556:   ospf6 = (struct ospf6 *)THREAD_ARG (t);
  557:   ospf6->t_spf_calc = NULL;
  558: 
  559:   /* execute SPF calculation */
  560:   quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
  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: 
  600:   quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
  601:   timersub (&end, &start, &runtime);
  602: 
  603:   ospf6->ts_spf_duration = runtime;
  604: 
  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);
  610: 
  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);
  617:   return 0;
  618: }
  619: 
  620: /* Add schedule for SPF calculation.  To avoid frequenst SPF calc, we
  621:    set timer for SPF calc. */
  622: void
  623: ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
  624: {
  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)
  639:     return;
  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);
  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: 
  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: 
  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
  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
  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: {
  915:   install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
  916:   install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
  917: }

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