back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_ase.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 242 360 67.2 %
Date: 2023-02-24 19:38:44 Functions: 12 15 80.0 %

          Line data    Source code
       1             : /*
       2             :  * OSPF AS external route calculation.
       3             :  * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
       4             :  *
       5             :  * This file is part of GNU Zebra.
       6             :  *
       7             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       8             :  * under the terms of the GNU General Public License as published by the
       9             :  * Free Software Foundation; either version 2, or (at your option) any
      10             :  * later version.
      11             :  *
      12             :  * GNU Zebra is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "thread.h"
      25             : #include "memory.h"
      26             : #include "hash.h"
      27             : #include "linklist.h"
      28             : #include "prefix.h"
      29             : #include "if.h"
      30             : #include "table.h"
      31             : #include "vty.h"
      32             : #include "log.h"
      33             : 
      34             : #include "ospfd/ospfd.h"
      35             : #include "ospfd/ospf_interface.h"
      36             : #include "ospfd/ospf_ism.h"
      37             : #include "ospfd/ospf_asbr.h"
      38             : #include "ospfd/ospf_lsa.h"
      39             : #include "ospfd/ospf_lsdb.h"
      40             : #include "ospfd/ospf_neighbor.h"
      41             : #include "ospfd/ospf_nsm.h"
      42             : #include "ospfd/ospf_spf.h"
      43             : #include "ospfd/ospf_route.h"
      44             : #include "ospfd/ospf_ase.h"
      45             : #include "ospfd/ospf_zebra.h"
      46             : #include "ospfd/ospf_dump.h"
      47             : 
      48          53 : struct ospf_route *ospf_find_asbr_route(struct ospf *ospf,
      49             :                                         struct route_table *rtrs,
      50             :                                         struct prefix_ipv4 *asbr)
      51             : {
      52          53 :         struct route_node *rn;
      53          53 :         struct ospf_route * or, *best = NULL;
      54          53 :         struct listnode *node;
      55          53 :         struct list *chosen;
      56             : 
      57             :         /* Sanity check. */
      58          53 :         if (rtrs == NULL)
      59             :                 return NULL;
      60             : 
      61          53 :         rn = route_node_lookup(rtrs, (struct prefix *)asbr);
      62          53 :         if (!rn)
      63             :                 return NULL;
      64             : 
      65          21 :         route_unlock_node(rn);
      66             : 
      67          21 :         chosen = list_new();
      68             : 
      69             :         /* First try to find intra-area non-bb paths. */
      70          21 :         if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE))
      71          63 :                 for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
      72          21 :                         if (or->cost < OSPF_LS_INFINITY)
      73          21 :                                 if (!OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)
      74           9 :                                             &&
      75           9 :                                     or->path_type == OSPF_PATH_INTRA_AREA)
      76           7 :                                         listnode_add(chosen, or);
      77             : 
      78             :         /* If none is found -- look through all. */
      79          21 :         if (listcount(chosen) == 0) {
      80          14 :                 list_delete(&chosen);
      81          14 :                 chosen = rn->info;
      82             :         }
      83             : 
      84             :         /* Now find the route with least cost. */
      85          63 :         for (ALL_LIST_ELEMENTS_RO(chosen, node, or))
      86          21 :                 if (or->cost < OSPF_LS_INFINITY) {
      87          21 :                         if (best == NULL)
      88             :                                 best = or ;
      89           0 :                         else if (best->cost > or->cost)
      90             :                                 best = or ;
      91           0 :                         else if (best->cost ==
      92             :                                  or->cost
      93           0 :                                            && IPV4_ADDR_CMP(
      94             :                                                       &best->u.std.area_id,
      95             :                                                       & or->u.std.area_id)
      96             :                                                       < 0)
      97          21 :                                 best = or ;
      98             :                 }
      99             : 
     100          21 :         if (chosen != rn->info)
     101           7 :                 list_delete(&chosen);
     102             : 
     103             :         return best;
     104             : }
     105             : 
     106           0 : struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *rtrs,
     107             :                                                      struct prefix_ipv4 *asbr,
     108             :                                                      struct ospf_area *area)
     109             : {
     110           0 :         struct route_node *rn;
     111             : 
     112             :         /* Sanity check. */
     113           0 :         if (rtrs == NULL)
     114             :                 return NULL;
     115             : 
     116           0 :         rn = route_node_lookup(rtrs, (struct prefix *)asbr);
     117             : 
     118           0 :         if (rn) {
     119           0 :                 struct listnode *node;
     120           0 :                 struct ospf_route * or ;
     121             : 
     122           0 :                 route_unlock_node(rn);
     123             : 
     124           0 :                 for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
     125           0 :                         if (IPV4_ADDR_SAME(& or->u.std.area_id, &area->area_id))
     126           0 :                                 return or ;
     127             :         }
     128             : 
     129             :         return NULL;
     130             : }
     131             : 
     132           0 : static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
     133             :                                             struct in_addr nexthop)
     134             : {
     135           0 :         struct listnode *node;
     136           0 :         struct ospf_path *op;
     137             : 
     138           0 :         for (ALL_LIST_ELEMENTS_RO(ro->paths, node, op))
     139           0 :                 if (op->nexthop.s_addr == INADDR_ANY)
     140           0 :                         op->nexthop.s_addr = nexthop.s_addr;
     141           0 : }
     142             : 
     143           0 : static int ospf_ase_forward_address_check(struct ospf *ospf,
     144             :                                           struct in_addr fwd_addr)
     145             : {
     146           0 :         struct listnode *ifn;
     147           0 :         struct ospf_interface *oi;
     148             : 
     149           0 :         for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ifn, oi))
     150           0 :                 if (if_is_operative(oi->ifp))
     151           0 :                         if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
     152           0 :                                 if (IPV4_ADDR_SAME(&oi->address->u.prefix4,
     153             :                                                    &fwd_addr))
     154             :                                         return 0;
     155             : 
     156             :         return 1;
     157             : }
     158             : 
     159             : static struct ospf_route *
     160          16 : ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
     161             :                              struct ospf_route *asbr_route, uint32_t metric)
     162             : {
     163          16 :         struct as_external_lsa *al;
     164          16 :         struct ospf_route *new;
     165             : 
     166          16 :         al = (struct as_external_lsa *)lsa->data;
     167             : 
     168          16 :         new = ospf_route_new();
     169             : 
     170             :         /* Set redistributed type -- does make sense? */
     171             :         /* new->type = type; */
     172          16 :         new->id = al->header.id;
     173          16 :         new->mask = al->mask;
     174             : 
     175          16 :         if (!IS_EXTERNAL_METRIC(al->e[0].tos)) {
     176           0 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     177           0 :                         zlog_debug("Route[External]: type-1 created.");
     178           0 :                 new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
     179           0 :                 new->cost = asbr_route->cost + metric; /* X + Y */
     180             :         } else {
     181          16 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     182           0 :                         zlog_debug("Route[External]: type-2 created.");
     183          16 :                 new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
     184          16 :                 new->cost = asbr_route->cost;   /* X */
     185          16 :                 new->u.ext.type2_cost = metric; /* Y */
     186             :         }
     187             : 
     188          16 :         new->type = OSPF_DESTINATION_NETWORK;
     189          16 :         new->u.ext.origin = lsa;
     190          16 :         new->u.ext.tag = ntohl(al->e[0].route_tag);
     191          16 :         new->u.ext.asbr = asbr_route;
     192             : 
     193          16 :         assert(new != asbr_route);
     194             : 
     195          16 :         return new;
     196             : }
     197             : 
     198             : #define OSPF_ASE_CALC_INTERVAL 1
     199             : 
     200          68 : int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
     201             : {
     202          68 :         uint32_t metric;
     203          68 :         struct as_external_lsa *al;
     204          68 :         struct ospf_route *asbr_route;
     205          68 :         struct prefix_ipv4 asbr, p;
     206          68 :         struct route_node *rn;
     207          68 :         struct ospf_route *new, * or ;
     208          68 :         int ret;
     209             : 
     210          68 :         assert(lsa);
     211          68 :         al = (struct as_external_lsa *)lsa->data;
     212             : 
     213          68 :         if (lsa->data->type == OSPF_AS_NSSA_LSA)
     214           0 :                 if (IS_DEBUG_OSPF_NSSA)
     215           0 :                         zlog_debug("%s: Processing Type-7", __func__);
     216             : 
     217             :         /* Stay away from any Local Translated Type-7 LSAs */
     218          68 :         if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
     219           0 :                 if (IS_DEBUG_OSPF_NSSA)
     220           0 :                         zlog_debug("%s: Rejecting Local Xlt'd", __func__);
     221           0 :                 return 0;
     222             :         }
     223             : 
     224          68 :         if (IS_DEBUG_OSPF(lsa, LSA)) {
     225           0 :                 zlog_debug(
     226             :                         "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
     227             :                         &al->header.id, ip_masklen(al->mask),
     228             :                         &al->header.adv_router);
     229             :         }
     230             : 
     231             :         /* (1) If the cost specified by the LSA is LSInfinity, or if the
     232             :                LSA's LS age is equal to MaxAge, then examine the next LSA. */
     233          68 :         if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
     234           0 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     235           0 :                         zlog_debug(
     236             :                                 "Route[External]: Metric is OSPF_LS_INFINITY");
     237           0 :                 return 0;
     238             :         }
     239          68 :         if (IS_LSA_MAXAGE(lsa)) {
     240           2 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     241           0 :                         zlog_debug(
     242             :                                 "Route[External]: AS-external-LSA is MAXAGE");
     243           2 :                 return 0;
     244             :         }
     245             : 
     246             :         /* (2) If the LSA was originated by the calculating router itself,
     247             :            examine the next LSA. */
     248          66 :         if (IS_LSA_SELF(lsa)) {
     249          18 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     250           0 :                         zlog_debug(
     251             :                                 "Route[External]: AS-external-LSA is self originated");
     252          18 :                 return 0;
     253             :         }
     254             : 
     255             :         /* (3) Call the destination described by the LSA N.  N's address is
     256             :                obtained by masking the LSA's Link State ID with the
     257             :                network/subnet mask contained in the body of the LSA.  Look
     258             :                up the routing table entries (potentially one per attached
     259             :                area) for the AS boundary router (ASBR) that originated the
     260             :                LSA. If no entries exist for router ASBR (i.e., ASBR is
     261             :                unreachable), do nothing with this LSA and consider the next
     262             :                in the list. */
     263             : 
     264          48 :         asbr.family = AF_INET;
     265          48 :         asbr.prefix = al->header.adv_router;
     266          48 :         asbr.prefixlen = IPV4_MAX_BITLEN;
     267          48 :         apply_mask_ipv4(&asbr);
     268             : 
     269          48 :         asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
     270          48 :         if (asbr_route == NULL) {
     271          32 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     272           0 :                         zlog_debug(
     273             :                                 "Route[External]: Can't find originating ASBR route");
     274          32 :                 return 0;
     275             :         }
     276          16 :         if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
     277           0 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     278           0 :                         zlog_debug(
     279             :                                 "Route[External]: Originating router is not an ASBR");
     280           0 :                 return 0;
     281             :         }
     282             : 
     283             :         /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR.
     284             :          * As per RFC 3101, expectation is to receive type-7 lsas from
     285             :          * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and
     286             :          * originated ASBR's area is NSSA.
     287             :          */
     288          16 :         if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA)
     289          16 :             && (asbr_route->u.std.external_routing != OSPF_AREA_DEFAULT)) {
     290           0 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     291           0 :                         zlog_debug(
     292             :                                 "Route[External]: Ignore, If type-5 LSA from NSSA area.");
     293           0 :                 return 0;
     294             :         }
     295             : 
     296             :         /*     Else, this LSA describes an AS external path to destination
     297             :                N.  Examine the forwarding address specified in the AS-
     298             :                external-LSA.  This indicates the IP address to which
     299             :                packets for the destination should be forwarded. */
     300             : 
     301          16 :         if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
     302             :                 /* If the forwarding address is set to 0.0.0.0, packets should
     303             :                    be sent to the ASBR itself. Among the multiple routing table
     304             :                    entries for the ASBR, select the preferred entry as follows.
     305             :                    If RFC1583Compatibility is set to "disabled", prune the set
     306             :                    of routing table entries for the ASBR as described in
     307             :                    Section 16.4.1. In any case, among the remaining routing
     308             :                    table entries, select the routing table entry with the least
     309             :                    cost; when there are multiple least cost routing table
     310             :                    entries the entry whose associated area has the largest OSPF
     311             :                    Area ID (when considered as an unsigned 32-bit integer) is
     312             :                    chosen. */
     313             : 
     314             :                 /* asbr_route already contains the requested route */
     315             :         } else {
     316             :                 /* If the forwarding address is non-zero, look up the
     317             :                    forwarding address in the routing table.[24] The matching
     318             :                    routing table entry must specify an intra-area or inter-area
     319             :                    path; if no such path exists, do nothing with the LSA and
     320             :                    consider the next in the list. */
     321           0 :                 if (!ospf_ase_forward_address_check(ospf, al->e[0].fwd_addr)) {
     322           0 :                         if (IS_DEBUG_OSPF(lsa, LSA))
     323           0 :                                 zlog_debug(
     324             :                                         "Route[External]: Forwarding address is our router address");
     325           0 :                         return 0;
     326             :                 }
     327             : 
     328           0 :                 asbr.family = AF_INET;
     329           0 :                 asbr.prefix = al->e[0].fwd_addr;
     330           0 :                 asbr.prefixlen = IPV4_MAX_BITLEN;
     331             : 
     332           0 :                 rn = route_node_match(ospf->new_table, (struct prefix *)&asbr);
     333             : 
     334           0 :                 if (rn == NULL || (asbr_route = rn->info) == NULL) {
     335           0 :                         if (IS_DEBUG_OSPF(lsa, LSA))
     336           0 :                                 zlog_debug(
     337             :                                         "Route[External]: Can't find route to forwarding address");
     338           0 :                         if (rn)
     339           0 :                                 route_unlock_node(rn);
     340           0 :                         return 0;
     341             :                 }
     342             : 
     343           0 :                 route_unlock_node(rn);
     344             :         }
     345             : 
     346             :         /* (4) Let X be the cost specified by the preferred routing table
     347             :                entry for the ASBR/forwarding address, and Y the cost
     348             :                specified in the LSA.  X is in terms of the link state
     349             :                metric, and Y is a type 1 or 2 external metric. */
     350             : 
     351             : 
     352             :         /* (5) Look up the routing table entry for the destination N.  If
     353             :                no entry exists for N, install the AS external path to N,
     354             :                with next hop equal to the list of next hops to the
     355             :                forwarding address, and advertising router equal to ASBR.
     356             :                If the external metric type is 1, then the path-type is set
     357             :                to type 1 external and the cost is equal to X+Y.  If the
     358             :                external metric type is 2, the path-type is set to type 2
     359             :                external, the link state component of the route's cost is X,
     360             :                and the type 2 cost is Y. */
     361          16 :         new = ospf_ase_calculate_new_route(lsa, asbr_route, metric);
     362             : 
     363             :         /* (6) Compare the AS external path described by the LSA with the
     364             :                existing paths in N's routing table entry, as follows. If
     365             :                the new path is preferred, it replaces the present paths in
     366             :                N's routing table entry.  If the new path is of equal
     367             :                preference, it is added to N's routing table entry's list of
     368             :                paths. */
     369             : 
     370             :         /* Set prefix. */
     371          16 :         p.family = AF_INET;
     372          16 :         p.prefix = al->header.id;
     373          16 :         p.prefixlen = ip_masklen(al->mask);
     374             : 
     375             :         /* if there is a Intra/Inter area route to the N
     376             :            do not install external route */
     377          16 :         if ((rn = route_node_lookup(ospf->new_table, (struct prefix *)&p))) {
     378           0 :                 route_unlock_node(rn);
     379           0 :                 if (rn->info == NULL)
     380           0 :                         zlog_info("Route[External]: rn->info NULL");
     381           0 :                 if (new)
     382           0 :                         ospf_route_free(new);
     383           0 :                 return 0;
     384             :         }
     385             :         /* Find a route to the same dest */
     386             :         /* If there is no route, create new one. */
     387          16 :         if ((rn = route_node_lookup(ospf->new_external_route,
     388             :                                     (struct prefix *)&p)))
     389           0 :                 route_unlock_node(rn);
     390             : 
     391           0 :         if (!rn || (or = rn->info) == NULL) {
     392          16 :                 if (IS_DEBUG_OSPF(lsa, LSA))
     393           0 :                         zlog_debug("Route[External]: Adding a new route %pFX with paths %u",
     394             :                                    &p, listcount(asbr_route->paths));
     395             : 
     396          16 :                 ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
     397             : 
     398          16 :                 if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
     399           0 :                         ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
     400          16 :                 return 0;
     401             :         } else {
     402             :                 /* (a) Intra-area and inter-area paths are always preferred
     403             :                        over AS external paths.
     404             : 
     405             :                    (b) Type 1 external paths are always preferred over type 2
     406             :                        external paths. When all paths are type 2 external
     407             :                        paths, the paths with the smallest advertised type 2
     408             :                        metric are always preferred. */
     409           0 :                 ret = ospf_route_cmp(ospf, new, or);
     410             : 
     411             :                 /*     (c) If the new AS external path is still
     412             :                    indistinguishable
     413             :                            from the current paths in the N's routing table
     414             :                    entry,
     415             :                            and RFC1583Compatibility is set to "disabled", select
     416             :                            the preferred paths based on the intra-AS paths to
     417             :                    the
     418             :                            ASBR/forwarding addresses, as specified in Section
     419             :                            16.4.1.
     420             : 
     421             :                        (d) If the new AS external path is still
     422             :                    indistinguishable
     423             :                            from the current paths in the N's routing table
     424             :                    entry,
     425             :                            select the preferred path based on a least cost
     426             :                            comparison.  Type 1 external paths are compared by
     427             :                            looking at the sum of the distance to the forwarding
     428             :                            address and the advertised type 1 metric (X+Y).  Type
     429             :                    2
     430             :                            external paths advertising equal type 2 metrics are
     431             :                            compared by looking at the distance to the forwarding
     432             :                            addresses.
     433             :                 */
     434             :                 /* New route is better */
     435           0 :                 if (ret < 0) {
     436           0 :                         if (IS_DEBUG_OSPF(lsa, LSA))
     437           0 :                                 zlog_debug(
     438             :                                         "Route[External]: New route is better");
     439           0 :                         ospf_route_subst(rn, new, asbr_route);
     440           0 :                         if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
     441           0 :                                 ospf_ase_complete_direct_routes(
     442             :                                         new, al->e[0].fwd_addr);
     443             :                         or = new;
     444             :                         new = NULL;
     445             :                 }
     446             :                 /* Old route is better */
     447           0 :                 else if (ret > 0) {
     448           0 :                         if (IS_DEBUG_OSPF(lsa, LSA))
     449           0 :                                 zlog_debug(
     450             :                                         "Route[External]: Old route is better");
     451             :                         /* do nothing */
     452             :                 }
     453             :                 /* Routes are equal */
     454             :                 else {
     455           0 :                         if (IS_DEBUG_OSPF(lsa, LSA))
     456           0 :                                 zlog_debug("Route[External]: Routes are equal");
     457           0 :                         ospf_route_copy_nexthops(or, asbr_route->paths);
     458           0 :                         if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
     459           0 :                                 ospf_ase_complete_direct_routes(
     460             :                                         or, al->e[0].fwd_addr);
     461             :                 }
     462             :         }
     463             :         /* Make sure setting newly calculated ASBR route.*/
     464           0 :         or->u.ext.asbr = asbr_route;
     465           0 :         if (new)
     466           0 :                 ospf_route_free(new);
     467             : 
     468           0 :         lsa->route = or ;
     469           0 :         return 0;
     470             : }
     471             : 
     472          16 : static int ospf_ase_route_match_same(struct route_table *rt,
     473             :                                      struct prefix *prefix,
     474             :                                      struct ospf_route *newor)
     475             : {
     476          16 :         struct route_node *rn;
     477          16 :         struct ospf_route *or;
     478          16 :         struct ospf_path *op;
     479          16 :         struct ospf_path *newop;
     480          16 :         struct listnode *n1;
     481          16 :         struct listnode *n2;
     482             : 
     483          16 :         if (!rt || !prefix)
     484             :                 return 0;
     485             : 
     486          16 :         rn = route_node_lookup(rt, prefix);
     487          16 :         if (!rn)
     488             :                 return 0;
     489             : 
     490           4 :         route_unlock_node(rn);
     491             : 
     492           4 :         or = rn->info;
     493             : 
     494           4 :         assert(or);
     495             : 
     496           4 :         if (or->path_type != newor->path_type)
     497             :                 return 0;
     498             : 
     499           4 :         switch (or->path_type) {
     500           0 :         case OSPF_PATH_TYPE1_EXTERNAL:
     501           0 :                 if (or->cost != newor->cost)
     502             :                         return 0;
     503             :                 break;
     504           4 :         case OSPF_PATH_TYPE2_EXTERNAL:
     505           4 :                 if ((or->cost != newor->cost)
     506           4 :                     || (or->u.ext.type2_cost != newor->u.ext.type2_cost))
     507             :                         return 0;
     508             :                 break;
     509             :         default:
     510           0 :                 assert(0);
     511             :                 return 0;
     512             :         }
     513             : 
     514           4 :         assert(or->paths);
     515             : 
     516           4 :         if (or->paths->count != newor->paths->count)
     517             :                 return 0;
     518             : 
     519             :         /* Check each path. */
     520           8 :         for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
     521           4 :              n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
     522           4 :                 op = listgetdata(n1);
     523           4 :                 newop = listgetdata(n2);
     524             : 
     525           4 :                 if (!IPV4_ADDR_SAME(&op->nexthop, &newop->nexthop))
     526             :                         return 0;
     527           4 :                 if (op->ifindex != newop->ifindex)
     528             :                         return 0;
     529             :         }
     530             : 
     531           4 :         if (or->u.ext.tag != newor->u.ext.tag)
     532             :                 return 0;
     533             : 
     534             :         return 1;
     535             : }
     536             : 
     537          32 : static int ospf_ase_compare_tables(struct ospf *ospf,
     538             :                                    struct route_table *new_external_route,
     539             :                                    struct route_table *old_external_route)
     540             : {
     541          32 :         struct route_node *rn, *new_rn;
     542          32 :         struct ospf_route * or ;
     543             : 
     544             :         /* Remove deleted routes */
     545          54 :         for (rn = route_top(old_external_route); rn; rn = route_next(rn))
     546          22 :                 if ((or = rn->info)) {
     547          14 :                         if (!(new_rn = route_node_lookup(new_external_route,
     548          14 :                                                          &rn->p)))
     549          10 :                                 ospf_zebra_delete(
     550             :                                         ospf, (struct prefix_ipv4 *)&rn->p, or);
     551             :                         else
     552           4 :                                 route_unlock_node(new_rn);
     553             :                 }
     554             : 
     555             : 
     556             :         /* Install new routes */
     557          56 :         for (rn = route_top(new_external_route); rn; rn = route_next(rn))
     558          24 :                 if ((or = rn->info) != NULL)
     559          16 :                         if (!ospf_ase_route_match_same(old_external_route,
     560             :                                                        &rn->p, or))
     561          12 :                                 ospf_zebra_add(
     562             :                                         ospf, (struct prefix_ipv4 *)&rn->p, or);
     563             : 
     564          32 :         return 0;
     565             : }
     566             : 
     567          18 : static void ospf_ase_calculate_timer(struct thread *t)
     568             : {
     569          18 :         struct ospf *ospf;
     570          18 :         struct ospf_lsa *lsa;
     571          18 :         struct route_node *rn;
     572          18 :         struct listnode *node;
     573          18 :         struct ospf_area *area;
     574          18 :         struct timeval start_time, stop_time;
     575             : 
     576          18 :         ospf = THREAD_ARG(t);
     577          18 :         ospf->t_ase_calc = NULL;
     578             : 
     579          18 :         if (ospf->ase_calc) {
     580          18 :                 ospf->ase_calc = 0;
     581             : 
     582          18 :                 monotime(&start_time);
     583             : 
     584             :                 /* Calculate external route for each AS-external-LSA */
     585         108 :                 LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
     586          54 :                         ospf_ase_calculate_route(ospf, lsa);
     587             : 
     588             :                 /*  This version simple adds to the table all NSSA areas  */
     589          18 :                 if (ospf->anyNSSA)
     590           0 :                         for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
     591           0 :                                 if (IS_DEBUG_OSPF_NSSA)
     592           0 :                                         zlog_debug("%s: looking at area %pI4",
     593             :                                                    __func__, &area->area_id);
     594             : 
     595           0 :                                 if (area->external_routing == OSPF_AREA_NSSA)
     596           0 :                                         LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
     597           0 :                                                 ospf_ase_calculate_route(ospf,
     598             :                                                                          lsa);
     599             :                         }
     600             :                 /* kevinm: And add the NSSA routes in ospf_top */
     601          18 :                 LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
     602           0 :                         ospf_ase_calculate_route(ospf, lsa);
     603             : 
     604             :                 /* Compare old and new external routing table and install the
     605             :                    difference info zebra/kernel */
     606          18 :                 ospf_ase_compare_tables(ospf, ospf->new_external_route,
     607             :                                         ospf->old_external_route);
     608             : 
     609             :                 /* Delete old external routing table */
     610          18 :                 ospf_route_table_free(ospf->old_external_route);
     611          18 :                 ospf->old_external_route = ospf->new_external_route;
     612          18 :                 ospf->new_external_route = route_table_init();
     613             : 
     614          18 :                 monotime(&stop_time);
     615             : 
     616          18 :                 if (IS_DEBUG_OSPF_EVENT)
     617          18 :                         zlog_info(
     618             :                                 "SPF Processing Time(usecs): External Routes: %lld",
     619             :                                 (stop_time.tv_sec - start_time.tv_sec)
     620             :                                                 * 1000000LL
     621             :                                         + (stop_time.tv_usec
     622             :                                            - start_time.tv_usec));
     623             :         }
     624             : 
     625             :         /*
     626             :          * Uninstall remnant routes that were installed before the restart, but
     627             :          * that are no longer valid.
     628             :          */
     629          18 :         if (ospf->gr_info.finishing_restart) {
     630           0 :                 ospf_zebra_gr_disable(ospf);
     631           0 :                 ospf->gr_info.finishing_restart = false;
     632             :         }
     633          18 : }
     634             : 
     635          49 : void ospf_ase_calculate_schedule(struct ospf *ospf)
     636             : {
     637          49 :         if (ospf == NULL)
     638             :                 return;
     639             : 
     640          49 :         ospf->ase_calc = 1;
     641             : }
     642             : 
     643          49 : void ospf_ase_calculate_timer_add(struct ospf *ospf)
     644             : {
     645          49 :         if (ospf == NULL)
     646             :                 return;
     647             : 
     648          49 :         thread_add_timer(master, ospf_ase_calculate_timer, ospf,
     649             :                          OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
     650             : }
     651             : 
     652          18 : void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
     653             : {
     654          18 :         struct route_node *rn;
     655          18 :         struct prefix_ipv4 p;
     656          18 :         struct list *lst;
     657          18 :         struct as_external_lsa *al;
     658             : 
     659          18 :         al = (struct as_external_lsa *)lsa->data;
     660          18 :         p.family = AF_INET;
     661          18 :         p.prefix = lsa->data->id;
     662          18 :         p.prefixlen = ip_masklen(al->mask);
     663          18 :         apply_mask_ipv4(&p);
     664             : 
     665          18 :         rn = route_node_get(top->external_lsas, (struct prefix *)&p);
     666          18 :         if ((lst = rn->info) == NULL)
     667          16 :                 rn->info = lst = list_new();
     668             :         else
     669           2 :                 route_unlock_node(rn);
     670             : 
     671             :         /* We assume that if LSA is deleted from DB
     672             :            is is also deleted from this RT */
     673          18 :         listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
     674          18 : }
     675             : 
     676          18 : void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
     677             : {
     678          18 :         struct route_node *rn;
     679          18 :         struct prefix_ipv4 p;
     680          18 :         struct list *lst;
     681          18 :         struct as_external_lsa *al;
     682             : 
     683          18 :         al = (struct as_external_lsa *)lsa->data;
     684          18 :         p.family = AF_INET;
     685          18 :         p.prefix = lsa->data->id;
     686          18 :         p.prefixlen = ip_masklen(al->mask);
     687          18 :         apply_mask_ipv4(&p);
     688             : 
     689          18 :         rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
     690             : 
     691          18 :         if (rn) {
     692          18 :                 lst = rn->info;
     693          18 :                 struct listnode *node = listnode_lookup(lst, lsa);
     694             :                 /* Unlock lsa only if node is present in the list */
     695          18 :                 if (node) {
     696          18 :                         listnode_delete(lst, lsa);
     697          18 :                         ospf_lsa_unlock(&lsa); /* external_lsas list */
     698             :                 }
     699             : 
     700          18 :                 route_unlock_node(rn);
     701             :         }
     702          18 : }
     703             : 
     704           4 : void ospf_ase_external_lsas_finish(struct route_table *rt)
     705             : {
     706           4 :         struct route_node *rn;
     707           4 :         struct ospf_lsa *lsa;
     708           4 :         struct list *lst;
     709           4 :         struct listnode *node, *nnode;
     710             : 
     711          32 :         for (rn = route_top(rt); rn; rn = route_next(rn))
     712          28 :                 if ((lst = rn->info) != NULL) {
     713          16 :                         for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
     714           0 :                                 ospf_lsa_unlock(&lsa); /* external_lsas lst */
     715          16 :                         list_delete(&lst);
     716             :                 }
     717             : 
     718           4 :         route_table_finish(rt);
     719           4 : }
     720             : 
     721          14 : void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
     722             : {
     723          14 :         struct list *lsas;
     724          14 :         struct listnode *node;
     725          14 :         struct route_node *rn, *rn2;
     726          14 :         struct prefix_ipv4 p;
     727          14 :         struct route_table *tmp_old;
     728          14 :         struct as_external_lsa *al;
     729             : 
     730          14 :         al = (struct as_external_lsa *)lsa->data;
     731          14 :         p.family = AF_INET;
     732          14 :         p.prefix = lsa->data->id;
     733          14 :         p.prefixlen = ip_masklen(al->mask);
     734          14 :         apply_mask_ipv4(&p);
     735             : 
     736             :         /* if new_table is NULL, there was no spf calculation, thus
     737             :            incremental update is unneeded */
     738          14 :         if (!ospf->new_table)
     739           0 :                 return;
     740             : 
     741             :         /* If there is already an intra-area or inter-area route
     742             :            to the destination, no recalculation is necessary
     743             :            (internal routes take precedence). */
     744             : 
     745          14 :         rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
     746          14 :         if (rn) {
     747           0 :                 route_unlock_node(rn);
     748           0 :                 if (rn->info)
     749             :                         return;
     750             :         }
     751             : 
     752          14 :         rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
     753          14 :         assert(rn);
     754          14 :         assert(rn->info);
     755          14 :         lsas = rn->info;
     756          14 :         route_unlock_node(rn);
     757             : 
     758          42 :         for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
     759          14 :                 ospf_ase_calculate_route(ospf, lsa);
     760             : 
     761             :         /* prepare temporary old routing table for compare */
     762          14 :         tmp_old = route_table_init();
     763          14 :         rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
     764          14 :         if (rn && rn->info) {
     765           2 :                 rn2 = route_node_get(tmp_old, (struct prefix *)&p);
     766           2 :                 rn2->info = rn->info;
     767           2 :                 route_unlock_node(rn);
     768             :         }
     769             : 
     770             :         /* install changes to zebra */
     771          14 :         ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
     772             : 
     773             :         /* update ospf->old_external_route table */
     774          14 :         if (rn && rn->info)
     775           2 :                 ospf_route_free((struct ospf_route *)rn->info);
     776             : 
     777          14 :         rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
     778             :         /* if new route exists, install it to ospf->old_external_route */
     779          14 :         if (rn2 && rn2->info) {
     780           0 :                 if (!rn)
     781           0 :                         rn = route_node_get(ospf->old_external_route,
     782             :                                             (struct prefix *)&p);
     783           0 :                 rn->info = rn2->info;
     784             :         } else {
     785             :                 /* remove route node from ospf->old_external_route */
     786          14 :                 if (rn) {
     787           2 :                         rn->info = NULL;
     788           2 :                         route_unlock_node(rn);
     789             :                 }
     790             :         }
     791             : 
     792          14 :         if (rn2) {
     793             :                 /* rn2->info is stored in route node of ospf->old_external_route
     794             :                  */
     795           0 :                 rn2->info = NULL;
     796           0 :                 route_unlock_node(rn2);
     797           0 :                 route_unlock_node(rn2);
     798             :         }
     799             : 
     800          14 :         route_table_finish(tmp_old);
     801             : }

Generated by: LCOV version v1.16-topotato