back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_spf.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 450 665 67.7 %
Date: 2023-02-24 19:38:44 Functions: 28 39 71.8 %

          Line data    Source code
       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 along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : /* Shortest Path First calculation for OSPFv3 */
      22             : 
      23             : #include <zebra.h>
      24             : 
      25             : #include "log.h"
      26             : #include "memory.h"
      27             : #include "command.h"
      28             : #include "vty.h"
      29             : #include "prefix.h"
      30             : #include "linklist.h"
      31             : #include "thread.h"
      32             : #include "lib_errors.h"
      33             : 
      34             : #include "ospf6_lsa.h"
      35             : #include "ospf6_lsdb.h"
      36             : #include "ospf6_route.h"
      37             : #include "ospf6_area.h"
      38             : #include "ospf6_proto.h"
      39             : #include "ospf6_abr.h"
      40             : #include "ospf6_asbr.h"
      41             : #include "ospf6_spf.h"
      42             : #include "ospf6_intra.h"
      43             : #include "ospf6_interface.h"
      44             : #include "ospf6d.h"
      45             : #include "ospf6_abr.h"
      46             : #include "ospf6_nssa.h"
      47             : #include "ospf6_zebra.h"
      48             : #include "ospf6_vlink.h"
      49             : 
      50          48 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
      51             : 
      52             : unsigned char conf_debug_ospf6_spf = 0;
      53             : 
      54         444 : static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route *rt,
      55             :                                              struct ospf6_vertex *v)
      56             : {
      57         444 :         if (rt && v)
      58         444 :                 ospf6_copy_nexthops(rt->nh_list, v->nh_list);
      59         444 : }
      60             : 
      61           6 : static void ospf6_spf_merge_nexthops_to_route(struct ospf6_route *rt,
      62             :                                               struct ospf6_vertex *v)
      63             : {
      64           6 :         if (rt && v)
      65           6 :                 ospf6_merge_nexthops(rt->nh_list, v->nh_list);
      66           6 : }
      67             : 
      68         169 : static unsigned int ospf6_spf_get_ifindex_from_nh(struct ospf6_vertex *v)
      69             : {
      70         169 :         struct ospf6_nexthop *nh;
      71         169 :         struct listnode *node;
      72             : 
      73         169 :         if (v) {
      74         169 :                 node = listhead(v->nh_list);
      75         169 :                 if (node) {
      76         169 :                         nh = listgetdata(node);
      77         169 :                         if (nh)
      78         169 :                                 return (nh->ifindex);
      79             :                 }
      80             :         }
      81             :         return 0;
      82             : }
      83             : 
      84        1205 : static int ospf6_vertex_cmp(const struct ospf6_vertex *va,
      85             :                 const struct ospf6_vertex *vb)
      86             : {
      87             :         /* ascending order */
      88        1205 :         if (va->cost != vb->cost)
      89         235 :                 return (va->cost - vb->cost);
      90         970 :         if (va->hops != vb->hops)
      91         173 :                 return (va->hops - vb->hops);
      92             :         return 0;
      93             : }
      94        4093 : DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct ospf6_vertex, pqi,
      95             :                 ospf6_vertex_cmp);
      96             : 
      97          55 : static int ospf6_vertex_id_cmp(void *a, void *b)
      98             : {
      99          55 :         struct ospf6_vertex *va = (struct ospf6_vertex *)a;
     100          55 :         struct ospf6_vertex *vb = (struct ospf6_vertex *)b;
     101          55 :         int ret = 0;
     102             : 
     103          55 :         ret = ntohl(ospf6_linkstate_prefix_adv_router(&va->vertex_id))
     104          55 :               - ntohl(ospf6_linkstate_prefix_adv_router(&vb->vertex_id));
     105          55 :         if (ret)
     106             :                 return ret;
     107             : 
     108          10 :         ret = ntohl(ospf6_linkstate_prefix_id(&va->vertex_id))
     109          10 :               - ntohl(ospf6_linkstate_prefix_id(&vb->vertex_id));
     110          10 :         return ret;
     111             : }
     112             : 
     113         757 : static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
     114             : {
     115         757 :         struct ospf6_vertex *v;
     116             : 
     117         757 :         v = XMALLOC(MTYPE_OSPF6_VERTEX, sizeof(struct ospf6_vertex));
     118             : 
     119             :         /* type */
     120         757 :         if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
     121         517 :                 v->type = OSPF6_VERTEX_TYPE_ROUTER;
     122             :                 /* Router LSA use Link ID 0 as base in vertex_id */
     123         517 :                 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0),
     124             :                                        &v->vertex_id);
     125         240 :         } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) {
     126         240 :                 v->type = OSPF6_VERTEX_TYPE_NETWORK;
     127             :                 /* vertex_id */
     128         240 :                 ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id,
     129             :                                        &v->vertex_id);
     130             :         } else
     131           0 :                 assert(0);
     132             : 
     133             :         /* name */
     134         757 :         ospf6_linkstate_prefix2str(&v->vertex_id, v->name, sizeof(v->name));
     135             : 
     136         757 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
     137           0 :                 zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s",
     138             :                            __func__, v->name,
     139             :                            ((ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER)
     140             :                                     ? "Router"
     141             :                                     : "N/W"),
     142             :                            ntohs(lsa->header->type), lsa->name);
     143             : 
     144             : 
     145             :         /* Associated LSA */
     146         757 :         v->lsa = lsa;
     147             : 
     148             :         /* capability bits + options */
     149         757 :         v->capability = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header));
     150         757 :         v->options[0] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 1);
     151         757 :         v->options[1] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 2);
     152         757 :         v->options[2] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
     153             : 
     154         757 :         v->nh_list = list_new();
     155         757 :         v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
     156         757 :         v->nh_list->del = (void (*)(void *))ospf6_nexthop_delete;
     157             : 
     158         757 :         v->parent = NULL;
     159         757 :         v->child_list = list_new();
     160         757 :         v->child_list->cmp = ospf6_vertex_id_cmp;
     161             : 
     162         757 :         return v;
     163             : }
     164             : 
     165         757 : static void ospf6_vertex_delete(struct ospf6_vertex *v)
     166             : {
     167         757 :         list_delete(&v->nh_list);
     168         757 :         list_delete(&v->child_list);
     169         757 :         XFREE(MTYPE_OSPF6_VERTEX, v);
     170         757 : }
     171             : 
     172         672 : static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
     173             :                                           struct ospf6_vertex *v)
     174             : {
     175         672 :         struct ospf6_lsa *lsa = NULL;
     176         672 :         uint16_t type = 0;
     177         672 :         uint32_t id = 0, adv_router = 0;
     178             : 
     179         672 :         if (VERTEX_IS_TYPE(NETWORK, v)) {
     180         295 :                 type = htons(OSPF6_LSTYPE_ROUTER);
     181         295 :                 id = htonl(0);
     182         295 :                 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc);
     183             :         } else {
     184         377 :                 if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) {
     185         125 :                         type = htons(OSPF6_LSTYPE_ROUTER);
     186         125 :                         id = htonl(0);
     187         125 :                         adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
     188         252 :                 } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) {
     189         252 :                         type = htons(OSPF6_LSTYPE_NETWORK);
     190         252 :                         id = htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc));
     191         252 :                         adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
     192             :                 }
     193             :         }
     194             : 
     195         420 :         if (type == htons(OSPF6_LSTYPE_NETWORK))
     196         252 :                 lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
     197             :         else
     198         420 :                 lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb,
     199             :                                                      adv_router);
     200         672 :         if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
     201           0 :                 char ibuf[16], abuf[16];
     202           0 :                 inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf));
     203           0 :                 inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf));
     204           0 :                 if (lsa)
     205           0 :                         zlog_debug("  Link to: %s len %u, V %s", lsa->name,
     206             :                                    ntohs(lsa->header->length), v->name);
     207             :                 else
     208           0 :                         zlog_debug("  Link to: [%s Id:%s Adv:%s] No LSA , V %s",
     209             :                                    ospf6_lstype_name(type), ibuf, abuf,
     210             :                                    v->name);
     211             :         }
     212             : 
     213         672 :         return lsa;
     214             : }
     215             : 
     216         660 : static char *ospf6_lsdesc_backlink(struct ospf6_lsa *lsa, caddr_t lsdesc,
     217             :                                    struct ospf6_vertex *v)
     218             : {
     219         660 :         caddr_t backlink, found = NULL;
     220         660 :         int size;
     221             : 
     222         660 :         size = (OSPF6_LSA_IS_TYPE(ROUTER, lsa)
     223             :                         ? sizeof(struct ospf6_router_lsdesc)
     224             :                         : sizeof(struct ospf6_network_lsdesc));
     225         660 :         for (backlink = OSPF6_LSA_HEADER_END(lsa->header) + 4;
     226        1845 :              backlink + size <= OSPF6_LSA_END(lsa->header); backlink += size) {
     227        1185 :                 assert(!(OSPF6_LSA_IS_TYPE(NETWORK, lsa)
     228             :                          && VERTEX_IS_TYPE(NETWORK, v)));
     229             : 
     230        1185 :                 if (OSPF6_LSA_IS_TYPE(NETWORK, lsa)) {
     231         550 :                         if (NETWORK_LSDESC_GET_NBR_ROUTERID(backlink)
     232         550 :                             == v->lsa->header->adv_router)
     233        1185 :                                 found = backlink;
     234         635 :                 } else if (VERTEX_IS_TYPE(NETWORK, v)) {
     235         400 :                         if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink)
     236         370 :                             && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
     237         370 :                                        == v->lsa->header->adv_router
     238         311 :                             && ROUTER_LSDESC_GET_NBR_IFID(backlink)
     239         311 :                                        == ntohl(v->lsa->header->id))
     240         240 :                                 found = backlink;
     241             :                 } else {
     242         235 :                         assert(OSPF6_LSA_IS_TYPE(ROUTER, lsa)
     243             :                                && VERTEX_IS_TYPE(ROUTER, v));
     244             : 
     245         235 :                         if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, backlink)
     246         210 :                             || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc))
     247          25 :                                 continue;
     248             : 
     249         210 :                         if (ROUTER_LSDESC_GET_NBR_IFID(backlink)
     250         210 :                                     != ROUTER_LSDESC_GET_IFID(lsdesc)
     251         210 :                             || ROUTER_LSDESC_GET_NBR_IFID(lsdesc)
     252         210 :                                        != ROUTER_LSDESC_GET_IFID(backlink))
     253           0 :                                 continue;
     254         312 :                         if (ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
     255         210 :                                     != v->lsa->header->adv_router
     256         108 :                             || ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc)
     257         108 :                                        != lsa->header->adv_router)
     258         102 :                                 continue;
     259             :                         found = backlink;
     260             :                 }
     261             :         }
     262             : 
     263         660 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
     264           0 :                 zlog_debug("Vertex %s Lsa %s Backlink %s", v->name, lsa->name,
     265             :                            (found ? "OK" : "FAIL"));
     266             : 
     267         660 :         return found;
     268             : }
     269             : 
     270         204 : static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
     271             :                                caddr_t lsdesc, struct ospf6 *ospf6)
     272             : {
     273         204 :         int i;
     274         204 :         ifindex_t ifindex;
     275         204 :         struct ospf6_interface *oi;
     276         204 :         uint16_t type;
     277         204 :         uint32_t adv_router;
     278         204 :         struct ospf6_lsa *lsa;
     279         204 :         struct ospf6_link_lsa *link_lsa;
     280         204 :         char buf[64];
     281             : 
     282         204 :         assert(VERTEX_IS_TYPE(ROUTER, w));
     283         169 :         ifindex = (VERTEX_IS_TYPE(NETWORK, v) ? ospf6_spf_get_ifindex_from_nh(v)
     284         373 :                                               : ROUTER_LSDESC_GET_IFID(lsdesc));
     285         204 :         if (ifindex == 0) {
     286           0 :                 flog_err(EC_LIB_DEVELOPMENT, "No nexthop ifindex at vertex %s",
     287             :                          v->name);
     288           0 :                 return;
     289             :         }
     290             : 
     291         204 :         oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
     292         204 :         if (oi == NULL) {
     293           0 :                 zlog_warn("Can't find interface in SPF: ifindex %d", ifindex);
     294           0 :                 return;
     295             :         }
     296             : 
     297         204 :         type = htons(OSPF6_LSTYPE_LINK);
     298         408 :         adv_router = (VERTEX_IS_TYPE(NETWORK, v)
     299             :                               ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc)
     300         204 :                               : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc));
     301             : 
     302         204 :         i = 0;
     303         408 :         for (ALL_LSDB_TYPED_ADVRTR(oi->lsdb, type, adv_router, lsa)) {
     304         204 :                 if (VERTEX_IS_TYPE(ROUTER, v)
     305          35 :                     && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc))
     306          35 :                                != lsa->header->id)
     307           0 :                         continue;
     308             : 
     309         204 :                 link_lsa = (struct ospf6_link_lsa *)OSPF6_LSA_HEADER_END(
     310             :                         lsa->header);
     311         204 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
     312           0 :                         inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
     313             :                                   sizeof(buf));
     314           0 :                         zlog_debug("  nexthop %s from %s", buf, lsa->name);
     315             :                 }
     316             : 
     317         204 :                 ospf6_add_nexthop(w->nh_list, ifindex,
     318             :                                   &link_lsa->linklocal_addr);
     319         204 :                 i++;
     320             :         }
     321             : 
     322         204 :         if (i == 0 && IS_OSPF6_DEBUG_SPF(PROCESS))
     323         204 :                 zlog_debug("No nexthop for %s found", w->name);
     324             : }
     325             : 
     326         757 : static int ospf6_spf_install(struct ospf6_vertex *v,
     327             :                              struct ospf6_route_table *result_table)
     328             : {
     329         757 :         struct ospf6_route *route, *parent_route;
     330         757 :         struct ospf6_vertex *prev;
     331             : 
     332         757 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
     333           0 :                 zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v->name,
     334             :                            v->lsa->name, v->hops, v->cost);
     335             : 
     336         757 :         route = ospf6_route_lookup(&v->vertex_id, result_table);
     337         757 :         if (route && route->path.cost < v->cost) {
     338         307 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
     339           0 :                         zlog_debug(
     340             :                                 "  already installed with lower cost (%d), ignore",
     341             :                                 route->path.cost);
     342         307 :                 ospf6_vertex_delete(v);
     343         307 :                 return -1;
     344           6 :         } else if (route && route->path.cost == v->cost) {
     345           6 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
     346           0 :                         zlog_debug(
     347             :                                 "  another path found to route %pFX lsa %s, merge",
     348             :                                 &route->prefix, v->lsa->name);
     349           6 :                 ospf6_spf_merge_nexthops_to_route(route, v);
     350             : 
     351           6 :                 prev = (struct ospf6_vertex *)route->route_option;
     352           6 :                 assert(prev->hops <= v->hops);
     353             : 
     354           6 :                 if ((VERTEX_IS_TYPE(ROUTER, v)
     355           2 :                      && route->path.origin.id != v->lsa->header->id)) {
     356           0 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
     357           0 :                                 zlog_debug(
     358             :                                         "%s: V lsa %s id %u, route id %u are different",
     359             :                                         __func__, v->lsa->name,
     360             :                                         ntohl(v->lsa->header->id),
     361             :                                         ntohl(route->path.origin.id));
     362             :                         }
     363           0 :                         return 0;
     364             :                 }
     365             : 
     366           6 :                 ospf6_vertex_delete(v);
     367           6 :                 return -1;
     368             :         }
     369             : 
     370             :         /* There should be no case where candidate being installed (variable
     371             :            "v") is closer than the one in the SPF tree (variable "route").
     372             :            In the case something has gone wrong with the behavior of
     373             :            Priority-Queue. */
     374             : 
     375             :         /* the case where the route exists already is handled and returned
     376             :            up to here. */
     377         444 :         assert(route == NULL);
     378             : 
     379         444 :         route = ospf6_route_create(v->area->ospf6);
     380         444 :         memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
     381         444 :         route->type = OSPF6_DEST_TYPE_LINKSTATE;
     382         444 :         route->path.type = OSPF6_PATH_TYPE_INTRA;
     383         444 :         route->path.origin.type = v->lsa->header->type;
     384         444 :         route->path.origin.id = v->lsa->header->id;
     385         444 :         route->path.origin.adv_router = v->lsa->header->adv_router;
     386         444 :         route->path.metric_type = 1;
     387         444 :         route->path.cost = v->cost;
     388         444 :         route->path.u.cost_e2 = v->hops;
     389         444 :         route->path.router_bits = v->capability;
     390         444 :         route->path.options[0] = v->options[0];
     391         444 :         route->path.options[1] = v->options[1];
     392         444 :         route->path.options[2] = v->options[2];
     393             : 
     394         444 :         ospf6_spf_copy_nexthops_to_route(route, v);
     395             : 
     396             :         /*
     397             :          * The SPF logic implementation does not transfer the multipathing
     398             :          * properties
     399             :          * of a parent to a child node. Thus if there was a 3-way multipath to a
     400             :          * node's parent and a single hop from the parent to the child, the
     401             :          * logic of
     402             :          * creating new vertices and computing next hops prevents there from
     403             :          * being 3
     404             :          * paths to the child node. This is primarily because the resolution of
     405             :          * multipath is done in this routine, not in the main spf loop.
     406             :          *
     407             :          * The following logic addresses that problem by merging the parent's
     408             :          * nexthop
     409             :          * information with the child's, if the parent is not the root of the
     410             :          * tree.
     411             :          * This is based on the assumption that before a node's route is
     412             :          * installed,
     413             :          * its parent's route's nexthops have already been installed.
     414             :          */
     415         444 :         if (v->parent && v->parent->hops) {
     416          71 :                 parent_route =
     417          71 :                         ospf6_route_lookup(&v->parent->vertex_id, result_table);
     418          71 :                 if (parent_route) {
     419          71 :                         ospf6_route_merge_nexthops(route, parent_route);
     420             :                 }
     421             :         }
     422             : 
     423         444 :         if (v->parent)
     424         275 :                 listnode_add_sort(v->parent->child_list, v);
     425         444 :         route->route_option = v;
     426             : 
     427         444 :         ospf6_route_add(route, result_table);
     428         444 :         return 0;
     429             : }
     430             : 
     431         224 : void ospf6_spf_table_finish(struct ospf6_route_table *result_table)
     432             : {
     433         224 :         struct ospf6_route *route, *nroute;
     434         224 :         struct ospf6_vertex *v;
     435         668 :         for (route = ospf6_route_head(result_table); route; route = nroute) {
     436         444 :                 nroute = ospf6_route_next(route);
     437         444 :                 v = (struct ospf6_vertex *)route->route_option;
     438         444 :                 ospf6_vertex_delete(v);
     439         444 :                 ospf6_route_remove(route, result_table);
     440             :         }
     441         224 : }
     442             : 
     443             : static const char *const ospf6_spf_reason_str[] = {
     444             :         "R+", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED */
     445             :         "R-", /* OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED */
     446             :         "N+", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED */
     447             :         "N-", /* OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED */
     448             :         "L+", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_ADDED */
     449             :         "L-", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_REMOVED */
     450             :         "R*", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED */
     451             :         "N*", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED */
     452             :         "C",  /* OSPF6_SPF_FLAGS_CONFIG_CHANGE */
     453             :         "A",  /* OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE */
     454             :         "GR", /* OSPF6_SPF_FLAGS_GR_FINISH */
     455             : };
     456             : 
     457         139 : void ospf6_spf_reason_string(uint32_t reason, char *buf, int size)
     458             : {
     459         139 :         uint32_t bit;
     460         139 :         int len = 0;
     461             : 
     462         139 :         if (!buf)
     463             :                 return;
     464             : 
     465         139 :         if (!reason) {
     466           3 :                 buf[0] = '\0';
     467           3 :                 return;
     468             :         }
     469        1632 :         for (bit = 0; bit < array_size(ospf6_spf_reason_str); bit++) {
     470        1496 :                 if ((reason & (1 << bit)) && (len < size)) {
     471         301 :                         len += snprintf((buf + len), (size - len), "%s%s",
     472             :                                         (len > 0) ? ", " : "",
     473         301 :                                         ospf6_spf_reason_str[bit]);
     474             :                 }
     475             :         }
     476             : }
     477             : 
     478             : /* RFC2328 16.1.  Calculating the shortest-path tree for an area */
     479             : /* RFC2740 3.8.1.  Calculating the shortest path tree for an area */
     480         172 : void ospf6_spf_calculation(uint32_t router_id,
     481             :                            struct ospf6_route_table *result_table,
     482             :                            struct ospf6_area *oa)
     483             : {
     484         172 :         struct vertex_pqueue_head candidate_list;
     485         172 :         struct ospf6_vertex *root, *v, *w;
     486         172 :         int size;
     487         172 :         caddr_t lsdesc;
     488         172 :         struct ospf6_lsa *lsa;
     489         172 :         struct in6_addr address;
     490             : 
     491         172 :         ospf6_spf_table_finish(result_table);
     492             : 
     493             :         /* Install the calculating router itself as the root of the SPF tree */
     494             :         /* construct root vertex */
     495         172 :         lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
     496         172 :         if (lsa == NULL) {
     497           3 :                 zlog_warn("%s: No router LSA for area %s", __func__, oa->name);
     498           3 :                 return;
     499             :         }
     500             : 
     501             :         /* initialize */
     502         169 :         vertex_pqueue_init(&candidate_list);
     503             : 
     504         169 :         root = ospf6_vertex_create(lsa);
     505         169 :         root->area = oa;
     506         169 :         root->cost = 0;
     507         169 :         root->hops = 0;
     508         169 :         root->link_id = lsa->header->id;
     509         169 :         inet_pton(AF_INET6, "::1", &address);
     510             : 
     511             :         /* Actually insert root to the candidate-list as the only candidate */
     512         169 :         vertex_pqueue_add(&candidate_list, root);
     513             : 
     514             :         /* Iterate until candidate-list becomes empty */
     515         926 :         while ((v = vertex_pqueue_pop(&candidate_list))) {
     516             :                 /* installing may result in merging or rejecting of the vertex
     517             :                  */
     518         757 :                 if (ospf6_spf_install(v, result_table) < 0)
     519         313 :                         continue;
     520             : 
     521             :                 /* Skip overloaded routers */
     522         444 :                 if ((OSPF6_LSA_IS_TYPE(ROUTER, v->lsa)
     523         308 :                      && ospf6_router_is_stub_router(v->lsa)))
     524           0 :                         continue;
     525             : 
     526             :                 /* For each LS description in the just-added vertex V's LSA */
     527         444 :                 size = (VERTEX_IS_TYPE(ROUTER, v)
     528             :                                 ? sizeof(struct ospf6_router_lsdesc)
     529             :                                 : sizeof(struct ospf6_network_lsdesc));
     530         444 :                 for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
     531        1116 :                      lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
     532             :                      lsdesc += size) {
     533         672 :                         lsa = ospf6_lsdesc_lsa(lsdesc, v);
     534         672 :                         if (lsa == NULL)
     535           7 :                                 continue;
     536             : 
     537         665 :                         if (OSPF6_LSA_IS_MAXAGE(lsa))
     538           5 :                                 continue;
     539             : 
     540         660 :                         if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
     541          72 :                                 continue;
     542             : 
     543         588 :                         w = ospf6_vertex_create(lsa);
     544         588 :                         w->area = oa;
     545         588 :                         w->parent = v;
     546         588 :                         if (VERTEX_IS_TYPE(ROUTER, v)) {
     547         348 :                                 w->cost = v->cost
     548         348 :                                           + ROUTER_LSDESC_GET_METRIC(lsdesc);
     549         348 :                                 w->hops =
     550         348 :                                         v->hops
     551         348 :                                         + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1);
     552             :                         } else {
     553             :                                 /* NETWORK */
     554         240 :                                 w->cost = v->cost;
     555         240 :                                 w->hops = v->hops + 1;
     556             :                         }
     557             : 
     558             :                         /* nexthop calculation */
     559         588 :                         if (w->hops == 0)
     560          98 :                                 ospf6_add_nexthop(
     561             :                                         w->nh_list,
     562          98 :                                         ROUTER_LSDESC_GET_IFID(lsdesc), NULL);
     563         490 :                         else if (w->hops == 1 && v->hops == 0)
     564         204 :                                 ospf6_nexthop_calc(w, v, lsdesc, oa->ospf6);
     565             :                         else
     566         286 :                                 ospf6_copy_nexthops(w->nh_list, v->nh_list);
     567             : 
     568             : 
     569             :                         /* add new candidate to the candidate_list */
     570         588 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS))
     571           0 :                                 zlog_debug(
     572             :                                         "  New candidate: %s hops %d cost %d",
     573             :                                         w->name, w->hops, w->cost);
     574         588 :                         vertex_pqueue_add(&candidate_list, w);
     575             :                 }
     576             :         }
     577             : 
     578             :         //vertex_pqueue_fini(&candidate_list);
     579             : 
     580         169 :         ospf6_remove_temp_router_lsa(oa);
     581             : 
     582         169 :         oa->spf_calculation++;
     583             : }
     584             : 
     585           0 : static void ospf6_spf_log_database(struct ospf6_area *oa)
     586             : {
     587           0 :         char *p, *end, buffer[256];
     588           0 :         struct listnode *node;
     589           0 :         struct ospf6_interface *oi;
     590             : 
     591           0 :         p = buffer;
     592           0 :         end = buffer + sizeof(buffer);
     593             : 
     594           0 :         snprintf(p, end - p, "SPF on DB (#LSAs):");
     595           0 :         p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer) : end);
     596           0 :         snprintf(p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
     597           0 :         p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer) : end);
     598             : 
     599           0 :         for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
     600           0 :                 snprintfrr(p, end - p, " I/F %pOI: %d", oi,
     601           0 :                          oi->lsdb ? (int)oi->lsdb->count : -1);
     602           0 :                 p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer)
     603             :                                                    : end);
     604             :         }
     605             : 
     606           0 :         zlog_debug("%s", buffer);
     607           0 : }
     608             : 
     609         139 : static void ospf6_spf_calculation_thread(struct thread *t)
     610             : {
     611         139 :         struct ospf6_area *oa;
     612         139 :         struct ospf6 *ospf6;
     613         139 :         struct timeval start, end, runtime;
     614         139 :         struct listnode *node;
     615         139 :         int areas_processed = 0;
     616         139 :         char rbuf[32];
     617             : 
     618         139 :         ospf6 = (struct ospf6 *)THREAD_ARG(t);
     619             : 
     620             :         /* execute SPF calculation */
     621         139 :         monotime(&start);
     622         139 :         ospf6->ts_spf = start;
     623             : 
     624         139 :         if (ospf6_check_and_set_router_abr(ospf6))
     625          23 :                 ospf6_abr_range_reset_cost(ospf6);
     626             : 
     627         450 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
     628             : 
     629         172 :                 if (oa == ospf6->backbone)
     630          86 :                         continue;
     631             : 
     632          86 :                 monotime(&oa->ts_spf);
     633          86 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
     634           0 :                         zlog_debug("SPF calculation for Area %s", oa->name);
     635          86 :                 if (IS_OSPF6_DEBUG_SPF(DATABASE))
     636           0 :                         ospf6_spf_log_database(oa);
     637             : 
     638          86 :                 ospf6_spf_calculation(ospf6->router_id, oa->spf_table, oa);
     639          86 :                 ospf6_intra_route_calculation(oa);
     640          86 :                 ospf6_intra_brouter_calculation(oa);
     641          86 :                 ospf6_vlink_area_calculation(oa);
     642             : 
     643          86 :                 areas_processed++;
     644             :         }
     645             : 
     646         139 :         if (ospf6->backbone) {
     647          86 :                 if (ospf6->backbone->thread_router_lsa) {
     648             :                         /* virtual links' costs are updated by the area SPF
     649             :                          * runs above and carried into the router LSA for the
     650             :                          * backbone area.  To avoid triggering a second SPF
     651             :                          * run, take care of this here and now
     652             :                          */
     653           8 :                         if (ospf6->backbone->thread_router_lsa) {
     654           8 :                                 THREAD_OFF(ospf6->backbone->thread_router_lsa);
     655           8 :                                 thread_execute(master,
     656             :                                                ospf6_router_lsa_originate,
     657             :                                                ospf6->backbone, 0);
     658             :                         }
     659             :                 }
     660             : 
     661          86 :                 monotime(&ospf6->backbone->ts_spf);
     662          86 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
     663           0 :                         zlog_debug("SPF calculation for Backbone area %s",
     664             :                                    ospf6->backbone->name);
     665          86 :                 if (IS_OSPF6_DEBUG_SPF(DATABASE))
     666           0 :                         ospf6_spf_log_database(ospf6->backbone);
     667             : 
     668          86 :                 ospf6_spf_calculation(ospf6->router_id,
     669             :                                       ospf6->backbone->spf_table,
     670             :                                       ospf6->backbone);
     671          86 :                 ospf6_intra_route_calculation(ospf6->backbone);
     672          86 :                 ospf6_intra_brouter_calculation(ospf6->backbone);
     673          86 :                 areas_processed++;
     674             :         }
     675             : 
     676             :         /* External LSA calculation */
     677         139 :         ospf6_ase_calculate_timer_add(ospf6);
     678             : 
     679         139 :         if (ospf6_check_and_set_router_abr(ospf6)) {
     680          23 :                 ospf6_abr_defaults_to_stub(ospf6);
     681          23 :                 ospf6_abr_nssa_type_7_defaults(ospf6);
     682             :         }
     683             : 
     684         139 :         monotime(&end);
     685         139 :         timersub(&end, &start, &runtime);
     686             : 
     687         139 :         ospf6->ts_spf_duration = runtime;
     688             : 
     689         139 :         ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
     690             : 
     691         139 :         if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
     692           0 :                 zlog_debug(
     693             :                         "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s",
     694             :                         areas_processed, (long long)runtime.tv_sec,
     695             :                         (long long)runtime.tv_usec, rbuf);
     696             : 
     697         139 :         ospf6->last_spf_reason = ospf6->spf_reason;
     698         139 :         ospf6_reset_spf_reason(ospf6);
     699         139 : }
     700             : 
     701             : /* Add schedule for SPF calculation.  To avoid frequenst SPF calc, we
     702             :    set timer for SPF calc. */
     703         631 : void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
     704             : {
     705         631 :         unsigned long delay, elapsed, ht;
     706             : 
     707             :         /* OSPF instance does not exist. */
     708         631 :         if (ospf6 == NULL)
     709             :                 return;
     710             : 
     711         631 :         ospf6_set_spf_reason(ospf6, reason);
     712             : 
     713         631 :         if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) {
     714           0 :                 char rbuf[32];
     715           0 :                 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
     716           0 :                 zlog_debug("SPF: calculation timer scheduled (reason %s)",
     717             :                            rbuf);
     718             :         }
     719             : 
     720             :         /* SPF calculation timer is already scheduled. */
     721         631 :         if (thread_is_scheduled(ospf6->t_spf_calc)) {
     722         476 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
     723           0 :                         zlog_debug(
     724             :                                 "SPF: calculation timer is already scheduled: %p",
     725             :                                 (void *)ospf6->t_spf_calc);
     726         476 :                 return;
     727             :         }
     728             : 
     729         155 :         elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
     730         155 :         ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
     731             : 
     732         155 :         if (ht > ospf6->spf_max_holdtime)
     733           0 :                 ht = ospf6->spf_max_holdtime;
     734             : 
     735             :         /* Get SPF calculation delay time. */
     736         155 :         if (elapsed < ht) {
     737             :                 /* Got an event within the hold time of last SPF. We need to
     738             :                  * increase the hold_multiplier, if it's not already at/past
     739             :                  * maximum value, and wasn't already increased..
     740             :                  */
     741          67 :                 if (ht < ospf6->spf_max_holdtime)
     742          67 :                         ospf6->spf_hold_multiplier++;
     743             : 
     744             :                 /* always honour the SPF initial delay */
     745          67 :                 if ((ht - elapsed) < ospf6->spf_delay)
     746             :                         delay = ospf6->spf_delay;
     747             :                 else
     748             :                         delay = ht - elapsed;
     749             :         } else {
     750             :                 /* Event is past required hold-time of last SPF */
     751          88 :                 delay = ospf6->spf_delay;
     752          88 :                 ospf6->spf_hold_multiplier = 1;
     753             :         }
     754             : 
     755         155 :         if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
     756           0 :                 zlog_debug("SPF: Rescheduling in %ld msec", delay);
     757             : 
     758         155 :         THREAD_OFF(ospf6->t_spf_calc);
     759         155 :         thread_add_timer_msec(master, ospf6_spf_calculation_thread, ospf6,
     760             :                               delay, &ospf6->t_spf_calc);
     761             : }
     762             : 
     763           0 : void ospf6_spf_display_subtree(struct vty *vty, const char *prefix, int rest,
     764             :                                struct ospf6_vertex *v, json_object *json_obj,
     765             :                                bool use_json)
     766             : {
     767           0 :         struct listnode *node, *nnode;
     768           0 :         struct ospf6_vertex *c;
     769           0 :         char *next_prefix;
     770           0 :         int len;
     771           0 :         int restnum;
     772           0 :         json_object *json_childs = NULL;
     773           0 :         json_object *json_child = NULL;
     774             : 
     775           0 :         if (use_json) {
     776           0 :                 json_childs = json_object_new_object();
     777           0 :                 json_object_int_add(json_obj, "cost", v->cost);
     778             :         } else {
     779             :                 /* "prefix" is the space prefix of the display line */
     780           0 :                 vty_out(vty, "%s+-%s [%d]\n", prefix, v->name, v->cost);
     781             :         }
     782             : 
     783           0 :         len = strlen(prefix) + 4;
     784           0 :         next_prefix = (char *)malloc(len);
     785           0 :         if (next_prefix == NULL) {
     786           0 :                 vty_out(vty, "malloc failed\n");
     787           0 :                 return;
     788             :         }
     789           0 :         snprintf(next_prefix, len, "%s%s", prefix, (rest ? "|  " : "   "));
     790             : 
     791           0 :         restnum = listcount(v->child_list);
     792           0 :         for (ALL_LIST_ELEMENTS(v->child_list, node, nnode, c)) {
     793           0 :                 if (use_json)
     794           0 :                         json_child = json_object_new_object();
     795             :                 else
     796           0 :                         restnum--;
     797             : 
     798           0 :                 ospf6_spf_display_subtree(vty, next_prefix, restnum, c,
     799             :                                           json_child, use_json);
     800             : 
     801           0 :                 if (use_json)
     802           0 :                         json_object_object_add(json_childs, c->name,
     803             :                                                json_child);
     804             :         }
     805           0 :         if (use_json) {
     806           0 :                 json_object_boolean_add(json_obj, "isLeafNode",
     807           0 :                                         !listcount(v->child_list));
     808           0 :                 if (listcount(v->child_list))
     809           0 :                         json_object_object_add(json_obj, "children",
     810             :                                                json_childs);
     811             :                 else
     812           0 :                         json_object_free(json_childs);
     813             :         }
     814           0 :         free(next_prefix);
     815             : }
     816             : 
     817           0 : DEFUN (debug_ospf6_spf_process,
     818             :        debug_ospf6_spf_process_cmd,
     819             :        "debug ospf6 spf process",
     820             :        DEBUG_STR
     821             :        OSPF6_STR
     822             :        "Debug SPF Calculation\n"
     823             :        "Debug Detailed SPF Process\n"
     824             :       )
     825             : {
     826           0 :         unsigned char level = 0;
     827           0 :         level = OSPF6_DEBUG_SPF_PROCESS;
     828           0 :         OSPF6_DEBUG_SPF_ON(level);
     829           0 :         return CMD_SUCCESS;
     830             : }
     831             : 
     832           0 : DEFUN (debug_ospf6_spf_time,
     833             :        debug_ospf6_spf_time_cmd,
     834             :        "debug ospf6 spf time",
     835             :        DEBUG_STR
     836             :        OSPF6_STR
     837             :        "Debug SPF Calculation\n"
     838             :        "Measure time taken by SPF Calculation\n"
     839             :       )
     840             : {
     841           0 :         unsigned char level = 0;
     842           0 :         level = OSPF6_DEBUG_SPF_TIME;
     843           0 :         OSPF6_DEBUG_SPF_ON(level);
     844           0 :         return CMD_SUCCESS;
     845             : }
     846             : 
     847           0 : DEFUN (debug_ospf6_spf_database,
     848             :        debug_ospf6_spf_database_cmd,
     849             :        "debug ospf6 spf database",
     850             :        DEBUG_STR
     851             :        OSPF6_STR
     852             :        "Debug SPF Calculation\n"
     853             :        "Log number of LSAs at SPF Calculation time\n"
     854             :       )
     855             : {
     856           0 :         unsigned char level = 0;
     857           0 :         level = OSPF6_DEBUG_SPF_DATABASE;
     858           0 :         OSPF6_DEBUG_SPF_ON(level);
     859           0 :         return CMD_SUCCESS;
     860             : }
     861             : 
     862           0 : DEFUN (no_debug_ospf6_spf_process,
     863             :        no_debug_ospf6_spf_process_cmd,
     864             :        "no debug ospf6 spf process",
     865             :        NO_STR
     866             :        DEBUG_STR
     867             :        OSPF6_STR
     868             :        "Quit Debugging SPF Calculation\n"
     869             :        "Quit Debugging Detailed SPF Process\n"
     870             :       )
     871             : {
     872           0 :         unsigned char level = 0;
     873           0 :         level = OSPF6_DEBUG_SPF_PROCESS;
     874           0 :         OSPF6_DEBUG_SPF_OFF(level);
     875           0 :         return CMD_SUCCESS;
     876             : }
     877             : 
     878           0 : DEFUN (no_debug_ospf6_spf_time,
     879             :        no_debug_ospf6_spf_time_cmd,
     880             :        "no debug ospf6 spf time",
     881             :        NO_STR
     882             :        DEBUG_STR
     883             :        OSPF6_STR
     884             :        "Quit Debugging SPF Calculation\n"
     885             :        "Quit Measuring time taken by SPF Calculation\n"
     886             :       )
     887             : {
     888           0 :         unsigned char level = 0;
     889           0 :         level = OSPF6_DEBUG_SPF_TIME;
     890           0 :         OSPF6_DEBUG_SPF_OFF(level);
     891           0 :         return CMD_SUCCESS;
     892             : }
     893             : 
     894           0 : DEFUN (no_debug_ospf6_spf_database,
     895             :        no_debug_ospf6_spf_database_cmd,
     896             :        "no debug ospf6 spf database",
     897             :        NO_STR
     898             :        DEBUG_STR
     899             :        OSPF6_STR
     900             :        "Debug SPF Calculation\n"
     901             :        "Quit Logging number of LSAs at SPF Calculation time\n"
     902             :       )
     903             : {
     904           0 :         unsigned char level = 0;
     905           0 :         level = OSPF6_DEBUG_SPF_DATABASE;
     906           0 :         OSPF6_DEBUG_SPF_OFF(level);
     907           0 :         return CMD_SUCCESS;
     908             : }
     909             : 
     910           4 : static int ospf6_timers_spf_set(struct vty *vty, unsigned int delay,
     911             :                                 unsigned int hold, unsigned int max)
     912             : {
     913           4 :         VTY_DECLVAR_CONTEXT(ospf6, ospf);
     914             : 
     915           4 :         ospf->spf_delay = delay;
     916           4 :         ospf->spf_holdtime = hold;
     917           4 :         ospf->spf_max_holdtime = max;
     918             : 
     919           4 :         return CMD_SUCCESS;
     920             : }
     921             : 
     922           4 : DEFUN (ospf6_timers_throttle_spf,
     923             :        ospf6_timers_throttle_spf_cmd,
     924             :        "timers throttle spf (0-600000) (0-600000) (0-600000)",
     925             :        "Adjust routing timers\n"
     926             :        "Throttling adaptive timer\n"
     927             :        "OSPF6 SPF timers\n"
     928             :        "Delay (msec) from first change received till SPF calculation\n"
     929             :        "Initial hold time (msec) between consecutive SPF calculations\n"
     930             :        "Maximum hold time (msec)\n")
     931             : {
     932           4 :         int idx_number = 3;
     933           4 :         int idx_number_2 = 4;
     934           4 :         int idx_number_3 = 5;
     935           4 :         unsigned int delay, hold, max;
     936             : 
     937           4 :         delay = strtoul(argv[idx_number]->arg, NULL, 10);
     938           4 :         hold = strtoul(argv[idx_number_2]->arg, NULL, 10);
     939           4 :         max = strtoul(argv[idx_number_3]->arg, NULL, 10);
     940             : 
     941           4 :         return ospf6_timers_spf_set(vty, delay, hold, max);
     942             : }
     943             : 
     944           0 : DEFUN (no_ospf6_timers_throttle_spf,
     945             :        no_ospf6_timers_throttle_spf_cmd,
     946             :        "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
     947             :        NO_STR
     948             :        "Adjust routing timers\n"
     949             :        "Throttling adaptive timer\n"
     950             :        "OSPF6 SPF timers\n"
     951             :        "Delay (msec) from first change received till SPF calculation\n"
     952             :        "Initial hold time (msec) between consecutive SPF calculations\n"
     953             :        "Maximum hold time (msec)\n")
     954             : {
     955           0 :         return ospf6_timers_spf_set(vty, OSPF_SPF_DELAY_DEFAULT,
     956             :                                     OSPF_SPF_HOLDTIME_DEFAULT,
     957             :                                     OSPF_SPF_MAX_HOLDTIME_DEFAULT);
     958             : }
     959             : 
     960             : 
     961           0 : int config_write_ospf6_debug_spf(struct vty *vty)
     962             : {
     963           0 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
     964           0 :                 vty_out(vty, "debug ospf6 spf process\n");
     965           0 :         if (IS_OSPF6_DEBUG_SPF(TIME))
     966           0 :                 vty_out(vty, "debug ospf6 spf time\n");
     967           0 :         if (IS_OSPF6_DEBUG_SPF(DATABASE))
     968           0 :                 vty_out(vty, "debug ospf6 spf database\n");
     969           0 :         return 0;
     970             : }
     971             : 
     972           0 : void ospf6_spf_config_write(struct vty *vty, struct ospf6 *ospf6)
     973             : {
     974             : 
     975           0 :         if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT
     976           0 :             || ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT
     977           0 :             || ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
     978           0 :                 vty_out(vty, " timers throttle spf %d %d %d\n",
     979             :                         ospf6->spf_delay, ospf6->spf_holdtime,
     980             :                         ospf6->spf_max_holdtime);
     981           0 : }
     982             : 
     983          16 : void install_element_ospf6_debug_spf(void)
     984             : {
     985          16 :         install_element(ENABLE_NODE, &debug_ospf6_spf_process_cmd);
     986          16 :         install_element(ENABLE_NODE, &debug_ospf6_spf_time_cmd);
     987          16 :         install_element(ENABLE_NODE, &debug_ospf6_spf_database_cmd);
     988          16 :         install_element(ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
     989          16 :         install_element(ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
     990          16 :         install_element(ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
     991          16 :         install_element(CONFIG_NODE, &debug_ospf6_spf_process_cmd);
     992          16 :         install_element(CONFIG_NODE, &debug_ospf6_spf_time_cmd);
     993          16 :         install_element(CONFIG_NODE, &debug_ospf6_spf_database_cmd);
     994          16 :         install_element(CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
     995          16 :         install_element(CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
     996          16 :         install_element(CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
     997          16 : }
     998             : 
     999          16 : void ospf6_spf_init(void)
    1000             : {
    1001          16 :         install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
    1002          16 :         install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
    1003          16 : }
    1004             : 
    1005             : /* Create Aggregated Large Router-LSA from multiple Link-State IDs
    1006             :  * RFC 5340 A 4.3:
    1007             :  * When more than one router-LSA is received from a single router,
    1008             :  * the links are processed as if concatenated into a single LSA.*/
    1009         592 : struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
    1010             :                                                  struct ospf6_lsdb *lsdb,
    1011             :                                                  uint32_t adv_router)
    1012             : {
    1013         592 :         struct ospf6_lsa *lsa = NULL;
    1014         592 :         struct ospf6_lsa *rtr_lsa = NULL;
    1015         592 :         struct ospf6_lsa_header *lsa_header = NULL;
    1016         592 :         uint8_t *new_header = NULL;
    1017         592 :         const struct route_node *end = NULL;
    1018         592 :         uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0;
    1019         592 :         uint16_t type = 0;
    1020         592 :         char ifbuf[16];
    1021         592 :         uint32_t interface_id;
    1022         592 :         caddr_t lsd;
    1023             : 
    1024         592 :         lsa_length = sizeof(struct ospf6_lsa_header)
    1025             :                      + sizeof(struct ospf6_router_lsa);
    1026         592 :         total_lsa_length = lsa_length;
    1027         592 :         type = htons(OSPF6_LSTYPE_ROUTER);
    1028             : 
    1029             :         /* First check Aggregated LSA formed earlier in Cache */
    1030         592 :         lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router,
    1031             :                                 area->temp_router_lsa_lsdb);
    1032         592 :         if (lsa)
    1033             :                 return lsa;
    1034             : 
    1035         592 :         inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf));
    1036             : 
    1037             :         /* Determine total LSA length from all link state ids */
    1038         592 :         end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
    1039        1181 :         while (rtr_lsa) {
    1040         589 :                 lsa = rtr_lsa;
    1041         589 :                 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
    1042           6 :                         rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
    1043           6 :                         continue;
    1044             :                 }
    1045         583 :                 lsa_header = rtr_lsa->header;
    1046         583 :                 total_lsa_length += (ntohs(lsa_header->length) - lsa_length);
    1047         583 :                 num_lsa++;
    1048         583 :                 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
    1049             :         }
    1050         592 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1051           0 :                 zlog_debug("%s: adv_router %s num_lsa %u to convert.", __func__,
    1052             :                            ifbuf, num_lsa);
    1053         592 :         if (num_lsa == 1)
    1054             :                 return lsa;
    1055             : 
    1056           9 :         if (num_lsa == 0) {
    1057           9 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1058           0 :                         zlog_debug("%s: adv_router %s not found in LSDB.",
    1059             :                                    __func__, ifbuf);
    1060           9 :                 return NULL;
    1061             :         }
    1062             : 
    1063           0 :         lsa = ospf6_lsa_alloc(total_lsa_length);
    1064           0 :         new_header = (uint8_t *)lsa->header;
    1065             : 
    1066           0 :         lsa->lsdb = area->temp_router_lsa_lsdb;
    1067             : 
    1068             :         /* Fill Larger LSA Payload */
    1069           0 :         end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
    1070             : 
    1071             :         /*
    1072             :          * We assume at this point in time that rtr_lsa is
    1073             :          * a valid pointer.
    1074             :          */
    1075           0 :         assert(rtr_lsa);
    1076           0 :         if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
    1077             :                 /* Append first Link State ID LSA */
    1078           0 :                 lsa_header = rtr_lsa->header;
    1079           0 :                 memcpy(new_header, lsa_header, ntohs(lsa_header->length));
    1080             :                 /* Assign new lsa length as aggregated length. */
    1081           0 :                 ((struct ospf6_lsa_header *)new_header)->length =
    1082           0 :                         htons(total_lsa_length);
    1083           0 :                 new_header += ntohs(lsa_header->length);
    1084           0 :                 num_lsa--;
    1085             :         }
    1086             : 
    1087             :         /* Print LSA Name */
    1088           0 :         ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
    1089             : 
    1090           0 :         rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
    1091           0 :         while (rtr_lsa) {
    1092           0 :                 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
    1093           0 :                         rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
    1094           0 :                         continue;
    1095             :                 }
    1096             : 
    1097           0 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
    1098           0 :                         lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4;
    1099           0 :                         interface_id = ROUTER_LSDESC_GET_IFID(lsd);
    1100           0 :                         inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf));
    1101           0 :                         zlog_debug(
    1102             :                                 "%s: Next Router LSA %s to aggreat with len %u interface_id %s",
    1103             :                                 __func__, rtr_lsa->name,
    1104             :                                 ntohs(lsa_header->length), ifbuf);
    1105             :                 }
    1106             : 
    1107             :                 /* Append Next Link State ID LSA */
    1108           0 :                 lsa_header = rtr_lsa->header;
    1109           0 :                 memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4),
    1110           0 :                        (ntohs(lsa_header->length) - lsa_length));
    1111           0 :                 new_header += (ntohs(lsa_header->length) - lsa_length);
    1112           0 :                 num_lsa--;
    1113             : 
    1114           0 :                 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
    1115             :         }
    1116             : 
    1117             :         /* Calculate birth of this lsa */
    1118           0 :         ospf6_lsa_age_set(lsa);
    1119             : 
    1120             :         /* Store Aggregated LSA into area temp lsdb */
    1121           0 :         ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb);
    1122             : 
    1123           0 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1124           0 :                 zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
    1125             :                            __func__, lsa->name, ntohl(lsa->header->id),
    1126             :                            ntohs(lsa->header->type), ntohs(lsa->header->length),
    1127             :                            num_lsa);
    1128             : 
    1129             :         return lsa;
    1130             : }
    1131             : 
    1132         169 : void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
    1133             : {
    1134         169 :         struct ospf6_lsa *lsa = NULL, *lsanext;
    1135             : 
    1136         169 :         for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa, lsanext)) {
    1137           0 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1138           0 :                         zlog_debug(
    1139             :                                 "%s Remove LSA %s lsa->lock %u lsdb count %u",
    1140             :                                 __func__, lsa->name, lsa->lock,
    1141             :                                 area->temp_router_lsa_lsdb->count);
    1142           0 :                 ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
    1143             :         }
    1144         169 : }
    1145             : 
    1146         228 : int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
    1147             :                               struct ospf6_area *area)
    1148             : {
    1149         228 :         struct ospf6_route *route;
    1150         228 :         struct ospf6_as_external_lsa *external;
    1151         228 :         struct prefix prefix;
    1152         228 :         void (*hook_add)(struct ospf6_route *) = NULL;
    1153         228 :         void (*hook_remove)(struct ospf6_route *) = NULL;
    1154             : 
    1155         228 :         assert(lsa);
    1156             : 
    1157         228 :         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1158           0 :                 zlog_debug("%s :  start", __func__);
    1159             : 
    1160         228 :         if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7)
    1161           0 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1162           0 :                         zlog_debug("%s: Processing Type-7", __func__);
    1163             : 
    1164             :         /* Stay away from any Local Translated Type-7 LSAs */
    1165         228 :         if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
    1166           0 :                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1167           0 :                         zlog_debug("%s: Rejecting Local translated LSA",
    1168             :                                    __func__);
    1169           0 :                 return 0;
    1170             :         }
    1171             : 
    1172         228 :         external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
    1173             :                 lsa->header);
    1174         228 :         prefix.family = AF_INET6;
    1175         228 :         prefix.prefixlen = external->prefix.prefix_length;
    1176         228 :         ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
    1177             : 
    1178         228 :         if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
    1179         228 :                 hook_add = ospf6->route_table->hook_add;
    1180         228 :                 hook_remove = ospf6->route_table->hook_remove;
    1181         228 :                 ospf6->route_table->hook_add = NULL;
    1182         228 :                 ospf6->route_table->hook_remove = NULL;
    1183             : 
    1184         228 :                 if (!OSPF6_LSA_IS_MAXAGE(lsa))
    1185         162 :                         ospf6_asbr_lsa_add(lsa);
    1186             : 
    1187         228 :                 ospf6->route_table->hook_add = hook_add;
    1188         228 :                 ospf6->route_table->hook_remove = hook_remove;
    1189             : 
    1190         228 :                 route = ospf6_route_lookup(&prefix, ospf6->route_table);
    1191         228 :                 if (route == NULL) {
    1192         102 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1193           0 :                                 zlog_debug("%s: no external route %pFX",
    1194             :                                            __func__, &prefix);
    1195         102 :                         return 0;
    1196             :                 }
    1197             : 
    1198         126 :                 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
    1199             :                     && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
    1200           0 :                         UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
    1201           0 :                         UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
    1202             :                 }
    1203             : 
    1204         126 :                 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
    1205           0 :                         ospf6_route_remove(route, ospf6->route_table);
    1206         126 :                 else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
    1207             :                          || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
    1208         126 :                         if (hook_add) {
    1209         126 :                                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1210           0 :                                         zlog_debug(
    1211             :                                                 "%s: add external route %pFX",
    1212             :                                                 __func__, &prefix);
    1213         126 :                                 (*hook_add)(route);
    1214             :                         }
    1215             :                 }
    1216           0 :         } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
    1217           0 :                 hook_add = area->route_table->hook_add;
    1218           0 :                 hook_remove = area->route_table->hook_remove;
    1219           0 :                 area->route_table->hook_add = NULL;
    1220           0 :                 area->route_table->hook_remove = NULL;
    1221             : 
    1222           0 :                 if (!OSPF6_LSA_IS_MAXAGE(lsa))
    1223           0 :                         ospf6_asbr_lsa_add(lsa);
    1224             : 
    1225           0 :                 area->route_table->hook_add = hook_add;
    1226           0 :                 area->route_table->hook_remove = hook_remove;
    1227             : 
    1228           0 :                 route = ospf6_route_lookup(&prefix, area->route_table);
    1229           0 :                 if (route == NULL) {
    1230           0 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1231           0 :                                 zlog_debug("%s: no route %pFX, area %s",
    1232             :                                            __func__, &prefix, area->name);
    1233           0 :                         return 0;
    1234             :                 }
    1235             : 
    1236           0 :                 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
    1237             :                     && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
    1238           0 :                         UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
    1239           0 :                         UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
    1240             :                 }
    1241             : 
    1242           0 :                 if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
    1243           0 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1244           0 :                                 zlog_debug("%s : remove route %pFX, area %s",
    1245             :                                            __func__, &prefix, area->name);
    1246           0 :                         ospf6_route_remove(route, area->route_table);
    1247           0 :                 } else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
    1248             :                            || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
    1249           0 :                         if (hook_add) {
    1250           0 :                                 if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1251           0 :                                         zlog_debug(
    1252             :                                                 "%s: add nssa route %pFX, area %s",
    1253             :                                                 __func__, &prefix, area->name);
    1254           0 :                                 (*hook_add)(route);
    1255             :                         }
    1256           0 :                         ospf6_abr_check_translate_nssa(area, lsa);
    1257             :                 }
    1258             :         }
    1259             :         return 0;
    1260             : }
    1261             : 
    1262          55 : static void ospf6_ase_calculate_timer(struct thread *t)
    1263             : {
    1264          55 :         struct ospf6 *ospf6;
    1265          55 :         struct ospf6_lsa *lsa;
    1266          55 :         struct listnode *node, *nnode;
    1267          55 :         struct ospf6_area *area;
    1268          55 :         uint16_t type;
    1269             : 
    1270          55 :         ospf6 = THREAD_ARG(t);
    1271             : 
    1272             :         /* Calculate external route for each AS-external-LSA */
    1273          55 :         type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
    1274         283 :         for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa))
    1275         228 :                 ospf6_ase_calculate_route(ospf6, lsa, NULL);
    1276             : 
    1277             :         /*  This version simple adds to the table all NSSA areas  */
    1278          55 :         if (ospf6->anyNSSA) {
    1279           0 :                 for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
    1280           0 :                         if (IS_OSPF6_DEBUG_SPF(PROCESS))
    1281           0 :                                 zlog_debug("%s : looking at area %s", __func__,
    1282             :                                            area->name);
    1283             : 
    1284           0 :                         type = htons(OSPF6_LSTYPE_TYPE_7);
    1285           0 :                         for (ALL_LSDB_TYPED(area->lsdb, type, lsa))
    1286           0 :                                 ospf6_ase_calculate_route(ospf6, lsa, area);
    1287             :                 }
    1288             :         }
    1289             : 
    1290          55 :         if (ospf6->gr_info.finishing_restart) {
    1291             :                 /*
    1292             :                  * The routing table computation is complete. Uninstall remnant
    1293             :                  * routes that were installed before the restart, but that are
    1294             :                  * no longer valid.
    1295             :                  */
    1296           0 :                 ospf6_zebra_gr_disable(ospf6);
    1297           0 :                 ospf6->gr_info.finishing_restart = false;
    1298             :         }
    1299          55 : }
    1300             : 
    1301         139 : void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6)
    1302             : {
    1303         139 :         if (ospf6 == NULL)
    1304             :                 return;
    1305             : 
    1306         139 :         thread_add_timer(master, ospf6_ase_calculate_timer, ospf6,
    1307             :                          OSPF6_ASE_CALC_INTERVAL, &ospf6->t_ase_calc);
    1308             : }

Generated by: LCOV version v1.16-topotato