back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_asbr.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 581 1757 33.1 %
Date: 2023-02-24 18:38:32 Functions: 38 111 34.2 %

          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             : #include <zebra.h>
      22             : 
      23             : #include "log.h"
      24             : #include "memory.h"
      25             : #include "prefix.h"
      26             : #include "command.h"
      27             : #include "vty.h"
      28             : #include "routemap.h"
      29             : #include "table.h"
      30             : #include "plist.h"
      31             : #include "thread.h"
      32             : #include "linklist.h"
      33             : #include "lib/northbound_cli.h"
      34             : 
      35             : #include "ospf6_proto.h"
      36             : #include "ospf6_lsa.h"
      37             : #include "ospf6_lsdb.h"
      38             : #include "ospf6_route.h"
      39             : #include "ospf6_zebra.h"
      40             : #include "ospf6_message.h"
      41             : #include "ospf6_spf.h"
      42             : 
      43             : #include "ospf6_top.h"
      44             : #include "ospf6d.h"
      45             : #include "ospf6_area.h"
      46             : #include "ospf6_interface.h"
      47             : #include "ospf6_neighbor.h"
      48             : #include "ospf6_asbr.h"
      49             : #include "ospf6_abr.h"
      50             : #include "ospf6_intra.h"
      51             : #include "ospf6_flood.h"
      52             : #include "ospf6_nssa.h"
      53             : #include "ospf6d.h"
      54             : #include "ospf6_spf.h"
      55             : #include "ospf6_nssa.h"
      56             : #include "ospf6_gr.h"
      57             : #include "lib/json.h"
      58             : 
      59          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
      60          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS,     "OSPF6 Distribute arguments");
      61          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
      62          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_RT_AGGR, "OSPF6 ASBR Summarisation");
      63             : 
      64             : static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type);
      65             : static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
      66             :                                           struct ospf6_redist *red, int type);
      67             : 
      68             : #include "ospf6d/ospf6_asbr_clippy.c"
      69             : 
      70             : unsigned char conf_debug_ospf6_asbr = 0;
      71             : 
      72             : #define ZROUTE_NAME(x) zebra_route_string(x)
      73             : 
      74             : /* Originate Type-5 and Type-7 LSA */
      75          53 : static struct ospf6_lsa *ospf6_originate_type5_type7_lsas(
      76             :                                                 struct ospf6_route *route,
      77             :                                                 struct ospf6 *ospf6)
      78             : {
      79          53 :         struct ospf6_lsa *lsa;
      80          53 :         struct listnode *lnode;
      81          53 :         struct ospf6_area *oa = NULL;
      82             : 
      83          53 :         lsa = ospf6_as_external_lsa_originate(route, ospf6);
      84             : 
      85         173 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
      86          67 :                 if (IS_AREA_NSSA(oa))
      87           0 :                         ospf6_nssa_lsa_originate(route, oa, true);
      88             :         }
      89             : 
      90          53 :         return lsa;
      91             : }
      92             : 
      93             : /* AS External LSA origination */
      94          53 : struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
      95             :                                             struct ospf6 *ospf6)
      96             : {
      97          53 :         char buffer[OSPF6_MAX_LSASIZE];
      98          53 :         struct ospf6_lsa_header *lsa_header;
      99          53 :         struct ospf6_lsa *lsa;
     100          53 :         struct ospf6_external_info *info = route->route_option;
     101             : 
     102          53 :         struct ospf6_as_external_lsa *as_external_lsa;
     103          53 :         caddr_t p;
     104             : 
     105          53 :         if (ospf6->gr_info.restart_in_progress) {
     106           0 :                 if (IS_DEBUG_OSPF6_GR)
     107           0 :                         zlog_debug(
     108             :                                 "Graceful Restart in progress, don't originate LSA");
     109           0 :                 return NULL;
     110             :         }
     111             : 
     112          53 :         if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
     113           0 :                 zlog_debug("Originate AS-External-LSA for %pFX",
     114             :                            &route->prefix);
     115             : 
     116             :         /* prepare buffer */
     117          53 :         memset(buffer, 0, sizeof(buffer));
     118          53 :         lsa_header = (struct ospf6_lsa_header *)buffer;
     119          53 :         as_external_lsa = (struct ospf6_as_external_lsa
     120             :                                    *)((caddr_t)lsa_header
     121             :                                       + sizeof(struct ospf6_lsa_header));
     122          53 :         p = (caddr_t)((caddr_t)as_external_lsa
     123             :                       + sizeof(struct ospf6_as_external_lsa));
     124             : 
     125             :         /* Fill AS-External-LSA */
     126             :         /* Metric type */
     127          53 :         if (route->path.metric_type == 2)
     128          53 :                 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
     129             :         else
     130             :                 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
     131             : 
     132             :         /* forwarding address */
     133          53 :         if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
     134           0 :                 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
     135             :         else
     136          53 :                 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
     137             : 
     138             :         /* external route tag */
     139          53 :         if (info->tag)
     140           0 :                 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
     141             :         else
     142          53 :                 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
     143             : 
     144             :         /* Set metric */
     145          53 :         OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
     146             : 
     147             :         /* prefixlen */
     148          53 :         as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
     149             : 
     150             :         /* PrefixOptions */
     151          53 :         as_external_lsa->prefix.prefix_options = route->prefix_options;
     152             : 
     153             :         /* don't use refer LS-type */
     154          53 :         as_external_lsa->prefix.prefix_refer_lstype = htons(0);
     155             : 
     156             :         /* set Prefix */
     157          53 :         memcpy(p, &route->prefix.u.prefix6,
     158          53 :                OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
     159          53 :         ospf6_prefix_apply_mask(&as_external_lsa->prefix);
     160          53 :         p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
     161             : 
     162             :         /* Forwarding address */
     163          53 :         if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
     164           0 :                 memcpy(p, &info->forwarding, sizeof(struct in6_addr));
     165           0 :                 p += sizeof(struct in6_addr);
     166             :         }
     167             : 
     168             :         /* External Route Tag */
     169          53 :         if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
     170           0 :                 route_tag_t network_order = htonl(info->tag);
     171             : 
     172           0 :                 memcpy(p, &network_order, sizeof(network_order));
     173           0 :                 p += sizeof(network_order);
     174             :         }
     175             : 
     176             :         /* Fill LSA Header */
     177          53 :         lsa_header->age = 0;
     178          53 :         lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
     179          53 :         lsa_header->id = route->path.origin.id;
     180          53 :         lsa_header->adv_router = ospf6->router_id;
     181         106 :         lsa_header->seqnum =
     182          53 :                 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
     183             :                                     lsa_header->adv_router, ospf6->lsdb);
     184          53 :         lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
     185             : 
     186             :         /* LSA checksum */
     187          53 :         ospf6_lsa_checksum(lsa_header);
     188             : 
     189             :         /* create LSA */
     190          53 :         lsa = ospf6_lsa_create(lsa_header);
     191             : 
     192             :         /* Originate */
     193          53 :         ospf6_lsa_originate_process(lsa, ospf6);
     194             : 
     195          53 :         return lsa;
     196             : }
     197             : 
     198           8 : void ospf6_orig_as_external_lsa(struct thread *thread)
     199             : {
     200           8 :         struct ospf6_interface *oi;
     201           8 :         struct ospf6_lsa *lsa;
     202           8 :         uint32_t type, adv_router;
     203             : 
     204           8 :         oi = (struct ospf6_interface *)THREAD_ARG(thread);
     205             : 
     206           8 :         if (oi->state == OSPF6_INTERFACE_DOWN)
     207           0 :                 return;
     208           8 :         if (IS_AREA_NSSA(oi->area) || IS_AREA_STUB(oi->area))
     209             :                 return;
     210             : 
     211           8 :         type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
     212           8 :         adv_router = oi->area->ospf6->router_id;
     213          46 :         for (ALL_LSDB_TYPED_ADVRTR(oi->area->ospf6->lsdb, type, adv_router,
     214             :                                    lsa)) {
     215          38 :                 if (IS_OSPF6_DEBUG_ASBR)
     216           0 :                         zlog_debug(
     217             :                                 "%s: Send update of AS-External LSA %s seq 0x%x",
     218             :                                 __func__, lsa->name,
     219             :                                 ntohl(lsa->header->seqnum));
     220             : 
     221          38 :                 ospf6_flood_interface(NULL, lsa, oi);
     222             :         }
     223             : }
     224             : 
     225          74 : static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
     226             : {
     227          74 :         struct ospf6_as_external_lsa *external;
     228          74 :         ptrdiff_t tag_offset;
     229          74 :         route_tag_t network_order;
     230             : 
     231          74 :         if (!lsa)
     232             :                 return 0;
     233             : 
     234          74 :         external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
     235             :                 lsa->header);
     236             : 
     237          74 :         if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
     238             :                 return 0;
     239             : 
     240           0 :         tag_offset = sizeof(*external)
     241           0 :                      + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
     242           0 :         if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
     243           0 :                 tag_offset += sizeof(struct in6_addr);
     244             : 
     245           0 :         memcpy(&network_order, (caddr_t)external + tag_offset,
     246             :                sizeof(network_order));
     247           0 :         return ntohl(network_order);
     248             : }
     249             : 
     250          58 : void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
     251             :                                        struct ospf6_route *route,
     252             :                                        struct ospf6 *ospf6)
     253             : {
     254          58 :         struct ospf6_route *old_route, *next_route;
     255          58 :         struct ospf6_path *ecmp_path, *o_path = NULL;
     256          58 :         struct listnode *anode, *anext;
     257          58 :         struct listnode *nnode, *rnode, *rnext;
     258          58 :         struct ospf6_nexthop *nh, *rnh;
     259          58 :         bool route_found = false;
     260             : 
     261             :         /* check for old entry match with new route origin,
     262             :          * delete old entry.
     263             :          */
     264         147 :         for (old_route = old; old_route; old_route = next_route) {
     265         140 :                 bool route_updated = false;
     266             : 
     267         140 :                 next_route = old_route->next;
     268             : 
     269             :                 /* The route linked-list is grouped in batches of prefix.
     270             :                  * If the new prefix is not the same as the one of interest
     271             :                  * then we have walked over the end of the batch and so we
     272             :                  * should break rather than continuing unnecessarily.
     273             :                  */
     274         140 :                 if (!ospf6_route_is_same(old_route, route))
     275             :                         break;
     276          89 :                 if (old_route->path.type != route->path.type)
     277          45 :                         continue;
     278             : 
     279             :                 /* Current and New route has same origin,
     280             :                  * delete old entry.
     281             :                  */
     282         141 :                 for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
     283             :                                        o_path)) {
     284             :                         /* Check old route path and route has same
     285             :                          * origin.
     286             :                          */
     287          53 :                         if (o_path->area_id != route->path.area_id
     288          53 :                             || !ospf6_ls_origin_same(o_path, &route->path))
     289          18 :                                 continue;
     290             : 
     291             :                         /* Cost is not same then delete current path */
     292          35 :                         if ((o_path->cost == route->path.cost)
     293          35 :                             && (o_path->u.cost_e2 == route->path.u.cost_e2))
     294          35 :                                 continue;
     295             : 
     296           0 :                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
     297           0 :                                 zlog_debug(
     298             :                                         "%s: route %pFX cost old %u new %u is not same, replace route",
     299             :                                         __func__, &old_route->prefix, o_path->cost,
     300             :                                         route->path.cost);
     301             :                         }
     302             : 
     303             :                         /* Remove selected current rout path's nh from
     304             :                          * effective nh list.
     305             :                          */
     306           0 :                         for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
     307           0 :                                 for (ALL_LIST_ELEMENTS(old_route->nh_list,
     308             :                                                        rnode, rnext, rnh)) {
     309           0 :                                         if (!ospf6_nexthop_is_same(rnh, nh))
     310           0 :                                                 continue;
     311           0 :                                         listnode_delete(old_route->nh_list,
     312             :                                                         rnh);
     313           0 :                                         ospf6_nexthop_delete(rnh);
     314             :                                 }
     315             :                         }
     316             : 
     317           0 :                         listnode_delete(old_route->paths, o_path);
     318           0 :                         ospf6_path_free(o_path);
     319           0 :                         route_updated = true;
     320             : 
     321             :                         /* Current route's path (adv_router info) is similar
     322             :                          * to route being added.
     323             :                          * Replace current route's path with paths list head.
     324             :                          * Update FIB with effective NHs.
     325             :                          */
     326           0 :                         if (listcount(old_route->paths)) {
     327           0 :                                 for (ALL_LIST_ELEMENTS(old_route->paths,
     328             :                                                 anode, anext, o_path)) {
     329           0 :                                         ospf6_merge_nexthops(
     330             :                                                 old_route->nh_list,
     331             :                                                 o_path->nh_list);
     332             :                                 }
     333             :                                 /* Update RIB/FIB with effective
     334             :                                  * nh_list
     335             :                                  */
     336           0 :                                 if (ospf6->route_table->hook_add)
     337           0 :                                         (*ospf6->route_table->hook_add)(
     338             :                                                 old_route);
     339             : 
     340           0 :                                 if (old_route->path.origin.id
     341           0 :                                             == route->path.origin.id
     342           0 :                                     && old_route->path.origin.adv_router
     343             :                                                == route->path.origin
     344           0 :                                                           .adv_router) {
     345           0 :                                         struct ospf6_path *h_path;
     346             : 
     347           0 :                                         h_path = (struct ospf6_path *)
     348           0 :                                                 listgetdata(listhead(
     349             :                                                         old_route->paths));
     350           0 :                                         old_route->path.origin.type =
     351           0 :                                                 h_path->origin.type;
     352           0 :                                         old_route->path.origin.id =
     353           0 :                                                 h_path->origin.id;
     354           0 :                                         old_route->path.origin.adv_router =
     355           0 :                                                 h_path->origin.adv_router;
     356             :                                 }
     357             :                         } else {
     358           0 :                                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
     359           0 :                                         zlog_debug(
     360             :                                                 "%s: route %pFX old cost %u new cost %u, delete old entry.",
     361             :                                                 __func__, &old_route->prefix,
     362             :                                                 old_route->path.cost,
     363             :                                                 route->path.cost);
     364             :                                 }
     365           0 :                                 if (old == old_route)
     366           0 :                                         old = next_route;
     367           0 :                                 ospf6_route_remove(old_route,
     368             :                                                    ospf6->route_table);
     369             :                         }
     370             :                 }
     371          44 :                 if (route_updated)
     372             :                         break;
     373             :         }
     374             : 
     375             :         /* Add new route */
     376         107 :         for (old_route = old; old_route; old_route = old_route->next) {
     377             : 
     378             :                 /* The route linked-list is grouped in batches of prefix.
     379             :                  * If the new prefix is not the same as the one of interest
     380             :                  * then we have walked over the end of the batch and so we
     381             :                  * should break rather than continuing unnecessarily.
     382             :                  */
     383         104 :                 if (!ospf6_route_is_same(old_route, route))
     384             :                         break;
     385          88 :                 if (old_route->path.type != route->path.type)
     386          45 :                         continue;
     387             : 
     388             :                 /* Old Route and New Route have Equal Cost, Merge NHs */
     389          43 :                 if ((old_route->path.cost == route->path.cost)
     390          39 :                     && (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
     391             : 
     392          39 :                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
     393           0 :                                 zlog_debug(
     394             :                                         "%s: old route %pFX path  cost %u e2 %u",
     395             :                                         __func__, &old_route->prefix,
     396             :                                         old_route->path.cost,
     397             :                                         old_route->path.u.cost_e2);
     398             :                         }
     399          39 :                         route_found = true;
     400             :                         /* check if this path exists already in
     401             :                          * route->paths list, if so, replace nh_list
     402             :                          * from asbr_entry.
     403             :                          */
     404          86 :                         for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
     405             :                                                   o_path)) {
     406          43 :                                 if (o_path->area_id == route->path.area_id
     407          43 :                                     && ospf6_ls_origin_same(o_path, &route->path))
     408             :                                         break;
     409             :                         }
     410             :                         /* If path is not found in old_route paths's list,
     411             :                          * add a new path to route paths list and merge
     412             :                          * nexthops in route->path->nh_list.
     413             :                          * Otherwise replace existing path's nh_list.
     414             :                          */
     415          39 :                         if (o_path == NULL) {
     416           4 :                                 ecmp_path = ospf6_path_dup(&route->path);
     417             : 
     418             :                                 /* Add a nh_list to new ecmp path */
     419           4 :                                 ospf6_copy_nexthops(ecmp_path->nh_list,
     420             :                                                     route->nh_list);
     421             : 
     422             :                                 /* Add the new path to route's path list */
     423           4 :                                 listnode_add_sort(old_route->paths, ecmp_path);
     424             : 
     425           4 :                                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
     426           0 :                                         zlog_debug(
     427             :                                                 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
     428             :                                                 __func__, &route->prefix,
     429             :                                                 listcount(ecmp_path->nh_list),
     430             :                                                 old_route->paths ? listcount(
     431             :                                                         old_route->paths)
     432             :                                                                  : 0,
     433             :                                                 listcount(old_route->nh_list));
     434             :                                 }
     435             :                         } else {
     436          35 :                                 list_delete_all_node(o_path->nh_list);
     437          35 :                                 ospf6_copy_nexthops(o_path->nh_list,
     438             :                                                     route->nh_list);
     439             :                         }
     440             : 
     441             :                         /* Reset nexthop lists, rebuild from brouter table
     442             :                          * for each adv. router.
     443             :                          */
     444          39 :                         list_delete_all_node(old_route->nh_list);
     445             : 
     446         129 :                         for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
     447             :                                                   o_path)) {
     448          51 :                                 struct ospf6_route *asbr_entry;
     449             : 
     450          51 :                                 asbr_entry = ospf6_route_lookup(
     451             :                                                         &o_path->ls_prefix,
     452             :                                                         ospf6->brouter_table);
     453          51 :                                 if (asbr_entry == NULL) {
     454           0 :                                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     455           0 :                                                 zlog_debug(
     456             :                                                         "%s: ls_prfix %pFX asbr_entry not found.",
     457             :                                                         __func__,
     458             :                                                         &old_route->prefix);
     459           0 :                                         continue;
     460             :                                 }
     461          51 :                                 ospf6_route_merge_nexthops(old_route,
     462             :                                                            asbr_entry);
     463             :                         }
     464             : 
     465          39 :                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     466           0 :                                 zlog_debug(
     467             :                                         "%s: route %pFX with effective paths %u nh %u",
     468             :                                         __func__, &route->prefix,
     469             :                                         old_route->paths
     470             :                                                 ? listcount(old_route->paths)
     471             :                                                 : 0,
     472             :                                         old_route->nh_list
     473             :                                                 ? listcount(old_route->nh_list)
     474             :                                                 : 0);
     475             : 
     476             :                         /* Update RIB/FIB */
     477          39 :                         if (ospf6->route_table->hook_add)
     478           4 :                                 (*ospf6->route_table->hook_add)(old_route);
     479             : 
     480             :                         /* Delete the new route its info added to existing
     481             :                          * route.
     482             :                          */
     483          39 :                         ospf6_route_delete(route);
     484             : 
     485          39 :                         break;
     486             :                 }
     487             :         }
     488             : 
     489          39 :         if (!route_found) {
     490             :                 /* Add new route to existing node in ospf6 route table. */
     491          19 :                 ospf6_route_add(route, ospf6->route_table);
     492             :         }
     493          58 : }
     494             : 
     495             : /* Check if the forwarding address is local address */
     496           0 : static int ospf6_ase_forward_address_check(struct ospf6 *ospf6,
     497             :                                            struct in6_addr *fwd_addr)
     498             : {
     499           0 :         struct listnode *anode, *node, *cnode;
     500           0 :         struct ospf6_interface *oi;
     501           0 :         struct ospf6_area *oa;
     502           0 :         struct interface *ifp;
     503           0 :         struct connected *c;
     504             : 
     505           0 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, oa)) {
     506           0 :                 for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
     507           0 :                         if (!if_is_operative(oi->interface)
     508           0 :                             || oi->type == OSPF_IFTYPE_VIRTUALLINK)
     509           0 :                                 continue;
     510             : 
     511           0 :                         ifp = oi->interface;
     512           0 :                         for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
     513           0 :                                 if (IPV6_ADDR_SAME(&c->address->u.prefix6,
     514             :                                                    fwd_addr))
     515             :                                         return 0;
     516             :                         }
     517             :                 }
     518             :         }
     519             : 
     520             :         return 1;
     521             : }
     522             : 
     523         227 : void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
     524             : {
     525         227 :         struct ospf6_as_external_lsa *external;
     526         227 :         struct prefix asbr_id;
     527         227 :         struct ospf6_route *asbr_entry, *route, *old = NULL;
     528         227 :         struct ospf6_path *path;
     529         227 :         struct ospf6 *ospf6;
     530         227 :         int type;
     531         227 :         struct ospf6_area *oa = NULL;
     532         227 :         struct prefix fwd_addr;
     533         227 :         ptrdiff_t offset;
     534             : 
     535         227 :         type = ntohs(lsa->header->type);
     536         227 :         oa = lsa->lsdb->data;
     537             : 
     538         227 :         external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
     539             :                 lsa->header);
     540             : 
     541         227 :         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     542           0 :                 zlog_debug("Calculate AS-External route for %s", lsa->name);
     543             : 
     544         227 :         ospf6 = ospf6_get_by_lsdb(lsa);
     545             : 
     546         227 :         if (lsa->header->adv_router == ospf6->router_id) {
     547          65 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     548           0 :                         zlog_debug("Ignore self-originated AS-External-LSA");
     549         153 :                 return;
     550             :         }
     551             : 
     552         162 :         if (OSPF6_ASBR_METRIC(external) == OSPF_LS_INFINITY) {
     553           0 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     554           0 :                         zlog_debug("Ignore LSA with LSInfinity Metric");
     555           0 :                 return;
     556             :         }
     557             : 
     558         162 :         if (CHECK_FLAG(external->prefix.prefix_options,
     559             :                        OSPF6_PREFIX_OPTION_NU)) {
     560           0 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     561           0 :                         zlog_debug("Ignore LSA with NU bit set Metric");
     562           0 :                 return;
     563             :         }
     564             : 
     565         162 :         ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
     566         162 :         asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
     567         162 :         if (asbr_entry == NULL) {
     568          88 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     569           0 :                         zlog_debug("ASBR entry not found: %pFX", &asbr_id);
     570          88 :                 return;
     571             :         } else {
     572             :                 /* The router advertising external LSA can be ASBR or ABR */
     573          74 :                 if (!CHECK_FLAG(asbr_entry->path.router_bits,
     574             :                                 OSPF6_ROUTER_BIT_E)) {
     575           0 :                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     576           0 :                                 zlog_debug(
     577             :                                         "External bit reset ASBR route entry : %pFX",
     578             :                                         &asbr_id);
     579           0 :                         return;
     580             :                 }
     581             : 
     582             :                 /*
     583             :                  * RFC 3101 - Section 2.5:
     584             :                  * "For a Type-7 LSA the matching routing table entry must
     585             :                  * specify an intra-area path through the LSA's originating
     586             :                  * NSSA".
     587             :                  */
     588          74 :                 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
     589           0 :                     && (asbr_entry->path.area_id != oa->area_id
     590           0 :                         || asbr_entry->path.type != OSPF6_PATH_TYPE_INTRA)) {
     591           0 :                         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     592           0 :                                 zlog_debug(
     593             :                                         "Intra-area route to NSSA ASBR not found: %pFX",
     594             :                                         &asbr_id);
     595           0 :                         return;
     596             :                 }
     597             :         }
     598             : 
     599             :         /*
     600             :          * RFC 3101 - Section 2.5:
     601             :          * "If the destination is a Type-7 default route (destination ID =
     602             :          * DefaultDestination) and one of the following is true, then do
     603             :          * nothing with this LSA and consider the next in the list:
     604             :          *
     605             :          *  o  The calculating router is a border router and the LSA has
     606             :          *     its P-bit clear.  Appendix E describes a technique
     607             :          *     whereby an NSSA border router installs a Type-7 default
     608             :          *     LSA without propagating it.
     609             :          *
     610             :          *  o  The calculating router is a border router and is
     611             :          *     suppressing the import of summary routes as Type-3
     612             :          *     summary-LSAs".
     613             :          */
     614          74 :         if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
     615           0 :             && external->prefix.prefix_length == 0
     616           0 :             && CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR)
     617           0 :             && (CHECK_FLAG(external->prefix.prefix_options,
     618             :                            OSPF6_PREFIX_OPTION_P)
     619           0 :                 || oa->no_summary)) {
     620           0 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     621           0 :                         zlog_debug("Skipping Type-7 default route");
     622           0 :                 return;
     623             :         }
     624             : 
     625             :         /* Check the forwarding address */
     626          74 :         if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
     627           0 :                 offset = sizeof(*external)
     628           0 :                          + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
     629           0 :                 memset(&fwd_addr, 0, sizeof(fwd_addr));
     630           0 :                 fwd_addr.family = AF_INET6;
     631           0 :                 fwd_addr.prefixlen = IPV6_MAX_BITLEN;
     632           0 :                 memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
     633             :                        sizeof(struct in6_addr));
     634             : 
     635           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr.u.prefix6)) {
     636           0 :                         if (!ospf6_ase_forward_address_check(
     637             :                                     ospf6, &fwd_addr.u.prefix6)) {
     638           0 :                                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     639           0 :                                         zlog_debug(
     640             :                                                 "Fwd address %pFX is local address",
     641             :                                                 &fwd_addr);
     642           0 :                                 return;
     643             :                         }
     644             : 
     645             :                         /* Find the forwarding entry */
     646           0 :                         asbr_entry = ospf6_route_lookup_bestmatch(
     647             :                                 &fwd_addr, ospf6->route_table);
     648           0 :                         if (asbr_entry == NULL) {
     649           0 :                                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     650           0 :                                         zlog_debug(
     651             :                                                 "Fwd address not found: %pFX",
     652             :                                                 &fwd_addr);
     653           0 :                                 return;
     654             :                         }
     655             :                 }
     656             :         }
     657             : 
     658          74 :         route = ospf6_route_create(ospf6);
     659          74 :         route->type = OSPF6_DEST_TYPE_NETWORK;
     660          74 :         route->prefix.family = AF_INET6;
     661          74 :         route->prefix.prefixlen = external->prefix.prefix_length;
     662          74 :         ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
     663          74 :                               &external->prefix);
     664          74 :         route->prefix_options = external->prefix.prefix_options;
     665             : 
     666          74 :         route->path.area_id = asbr_entry->path.area_id;
     667          74 :         route->path.origin.type = lsa->header->type;
     668          74 :         route->path.origin.id = lsa->header->id;
     669          74 :         route->path.origin.adv_router = lsa->header->adv_router;
     670          74 :         memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix));
     671             : 
     672          74 :         if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
     673          74 :                 route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
     674          74 :                 route->path.metric_type = 2;
     675          74 :                 route->path.cost = asbr_entry->path.cost;
     676          74 :                 route->path.u.cost_e2 = OSPF6_ASBR_METRIC(external);
     677             :         } else {
     678           0 :                 route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
     679           0 :                 route->path.metric_type = 1;
     680           0 :                 route->path.cost =
     681           0 :                         asbr_entry->path.cost + OSPF6_ASBR_METRIC(external);
     682           0 :                 route->path.u.cost_e2 = 0;
     683             :         }
     684             : 
     685          74 :         route->path.tag = ospf6_as_external_lsa_get_tag(lsa);
     686             : 
     687          74 :         ospf6_route_copy_nexthops(route, asbr_entry);
     688             : 
     689          74 :         path = ospf6_path_dup(&route->path);
     690          74 :         ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
     691          74 :         listnode_add_sort(route->paths, path);
     692             : 
     693             : 
     694          74 :         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     695           0 :                 zlog_debug(
     696             :                         "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__,
     697             :                         (type == OSPF6_LSTYPE_AS_EXTERNAL) ? "AS-External"
     698             :                                                            : "NSSA",
     699             :                         (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1 : 2,
     700             :                         &route->prefix, route->path.cost, route->path.u.cost_e2,
     701             :                         listcount(route->nh_list));
     702             : 
     703          74 :         if (type == OSPF6_LSTYPE_AS_EXTERNAL)
     704          74 :                 old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
     705           0 :         else if (type == OSPF6_LSTYPE_TYPE_7)
     706           0 :                 old = ospf6_route_lookup(&route->prefix, oa->route_table);
     707          74 :         if (!old) {
     708          16 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     709           0 :                         zlog_debug("%s: Adding new route", __func__);
     710             :                 /* Add the new route to ospf6 instance route table. */
     711          16 :                 if (type == OSPF6_LSTYPE_AS_EXTERNAL)
     712          16 :                         ospf6_route_add(route, ospf6->route_table);
     713             :                 /* Add the route to the area route table */
     714           0 :                 else if (type == OSPF6_LSTYPE_TYPE_7) {
     715           0 :                         ospf6_route_add(route, oa->route_table);
     716             :                 }
     717             :         } else {
     718             :                 /* RFC 2328 16.4 (6)
     719             :                  * ECMP: Keep new equal preference path in current
     720             :                  * route's path list, update zebra with new effective
     721             :                  * list along with addition of ECMP path.
     722             :                  */
     723          58 :                 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
     724           0 :                         zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
     725             :                                    __func__, &route->prefix, route->path.cost,
     726             :                                    route->path.u.cost_e2,
     727             :                                    listcount(route->nh_list));
     728          58 :                 ospf6_asbr_update_route_ecmp_path(old, route, ospf6);
     729             :         }
     730             : }
     731             : 
     732         124 : void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
     733             :                            struct ospf6_route *asbr_entry)
     734             : {
     735         124 :         struct ospf6_as_external_lsa *external;
     736         124 :         struct prefix prefix;
     737         124 :         struct ospf6_route *route, *nroute, *route_to_del;
     738         124 :         struct ospf6_area *oa = NULL;
     739         124 :         struct ospf6 *ospf6;
     740         124 :         int type;
     741         124 :         bool debug = false;
     742             : 
     743         124 :         external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
     744             :                 lsa->header);
     745             : 
     746         124 :         if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA))
     747           0 :                 debug = true;
     748             : 
     749         124 :         ospf6 = ospf6_get_by_lsdb(lsa);
     750         124 :         type = ntohs(lsa->header->type);
     751             : 
     752         124 :         if (type == OSPF6_LSTYPE_TYPE_7) {
     753           0 :                 if (debug)
     754           0 :                         zlog_debug("%s: Withdraw  Type 7 route for %s",
     755             :                                    __func__, lsa->name);
     756           0 :                 oa = lsa->lsdb->data;
     757             :         } else {
     758         124 :                 if (debug)
     759           0 :                         zlog_debug("%s: Withdraw AS-External route for %s",
     760             :                                    __func__, lsa->name);
     761             : 
     762         124 :                 if (ospf6_check_and_set_router_abr(ospf6))
     763          15 :                         oa = ospf6->backbone;
     764             :                 else
     765         109 :                         oa = listnode_head(ospf6->area_list);
     766             :         }
     767             : 
     768         124 :         if (oa == NULL) {
     769           0 :                 if (debug)
     770           0 :                         zlog_debug("%s: Invalid area", __func__);
     771          69 :                 return;
     772             :         }
     773             : 
     774         124 :         if (lsa->header->adv_router == oa->ospf6->router_id) {
     775          18 :                 if (debug)
     776           0 :                         zlog_debug("Ignore self-originated AS-External-LSA");
     777          18 :                 return;
     778             :         }
     779             : 
     780         106 :         route_to_del = ospf6_route_create(ospf6);
     781         106 :         route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
     782         106 :         route_to_del->prefix.family = AF_INET6;
     783         106 :         route_to_del->prefix.prefixlen = external->prefix.prefix_length;
     784         106 :         ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external,
     785         106 :                               &external->prefix);
     786             : 
     787         106 :         route_to_del->path.origin.type = lsa->header->type;
     788         106 :         route_to_del->path.origin.id = lsa->header->id;
     789         106 :         route_to_del->path.origin.adv_router = lsa->header->adv_router;
     790             : 
     791         106 :         if (asbr_entry) {
     792          37 :                 route_to_del->path.area_id = asbr_entry->path.area_id;
     793          37 :                 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
     794          37 :                         route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
     795          37 :                         route_to_del->path.metric_type = 2;
     796          37 :                         route_to_del->path.cost = asbr_entry->path.cost;
     797          37 :                         route_to_del->path.u.cost_e2 =
     798          37 :                                 OSPF6_ASBR_METRIC(external);
     799             :                 } else {
     800           0 :                         route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
     801           0 :                         route_to_del->path.metric_type = 1;
     802           0 :                         route_to_del->path.cost = asbr_entry->path.cost
     803           0 :                                                   + OSPF6_ASBR_METRIC(external);
     804           0 :                         route_to_del->path.u.cost_e2 = 0;
     805             :                 }
     806             :         }
     807             : 
     808         106 :         memset(&prefix, 0, sizeof(struct prefix));
     809         106 :         prefix.family = AF_INET6;
     810         106 :         prefix.prefixlen = external->prefix.prefix_length;
     811         106 :         ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
     812             : 
     813         106 :         if (type == OSPF6_LSTYPE_TYPE_7)
     814           0 :                 route = ospf6_route_lookup(&prefix, oa->route_table);
     815             :         else
     816         106 :                 route = ospf6_route_lookup(&prefix, oa->ospf6->route_table);
     817             : 
     818         106 :         if (route == NULL) {
     819          51 :                 if (debug)
     820           0 :                         zlog_debug("AS-External route %pFX not found", &prefix);
     821          51 :                 ospf6_route_delete(route_to_del);
     822          51 :                 return;
     823             :         }
     824             : 
     825          55 :         if (debug)
     826           0 :                 zlog_debug(
     827             :                         "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
     828             :                         __func__, &prefix, route->path.cost, route->path.u.cost_e2,
     829             :                         route_to_del->path.cost, route_to_del->path.u.cost_e2);
     830             : 
     831          55 :         for (ospf6_route_lock(route);
     832         118 :              route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
     833          63 :                 nroute = ospf6_route_next(route);
     834             : 
     835          63 :                 if (route->type != OSPF6_DEST_TYPE_NETWORK)
     836           0 :                         continue;
     837             : 
     838             :                 /* Route has multiple ECMP paths, remove matching
     839             :                  * path. Update current route's effective nh list
     840             :                  * after removal of one of the path.
     841             :                  */
     842          63 :                 if (listcount(route->paths) > 1) {
     843          12 :                         struct listnode *anode, *anext;
     844          12 :                         struct listnode *nnode, *rnode, *rnext;
     845          12 :                         struct ospf6_nexthop *nh, *rnh;
     846          12 :                         struct ospf6_path *o_path;
     847          12 :                         bool nh_updated = false;
     848             : 
     849             :                         /* Iterate all paths of route to find maching with LSA
     850             :                          * remove from route path list. If route->path is same,
     851             :                          * replace from paths list.
     852             :                          */
     853          42 :                         for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
     854             :                                                o_path)) {
     855          30 :                                 if ((o_path->origin.type != lsa->header->type)
     856          12 :                                     || (o_path->origin.adv_router
     857          12 :                                         != lsa->header->adv_router)
     858           6 :                                     || (o_path->origin.id != lsa->header->id))
     859          26 :                                         continue;
     860             : 
     861             :                                 /* Compare LSA cost with current
     862             :                                  * route info.
     863             :                                  */
     864           4 :                                 if (asbr_entry
     865           4 :                                     && (o_path->cost != route_to_del->path.cost
     866           4 :                                         || o_path->u.cost_e2
     867             :                                                    != route_to_del->path.u
     868           4 :                                                               .cost_e2)) {
     869           0 :                                         if (IS_OSPF6_DEBUG_EXAMIN(
     870             :                                                     AS_EXTERNAL)) {
     871           0 :                                                 zlog_debug(
     872             :                                                         "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
     873             :                                                         __func__, &prefix,
     874             :                                                         route->path.cost,
     875             :                                                         route_to_del->path
     876             :                                                                 .cost);
     877             :                                         }
     878           0 :                                         continue;
     879             :                                 }
     880             : 
     881           4 :                                 if (debug) {
     882           0 :                                         zlog_debug(
     883             :                                                 "%s: route %pFX path found with cost %u nh %u to remove.",
     884             :                                                 __func__, &prefix, route->path.cost,
     885             :                                                 listcount(o_path->nh_list));
     886             :                                 }
     887             : 
     888             :                                 /* Remove found path's nh_list from
     889             :                                  * the route's nh_list.
     890             :                                  */
     891          12 :                                 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
     892             :                                                           nnode, nh)) {
     893          15 :                                         for (ALL_LIST_ELEMENTS(route->nh_list,
     894             :                                                                rnode, rnext,
     895             :                                                                rnh)) {
     896           7 :                                                 if (!ospf6_nexthop_is_same(rnh,
     897             :                                                                            nh))
     898           3 :                                                         continue;
     899           4 :                                                 listnode_delete(route->nh_list,
     900             :                                                                 rnh);
     901           4 :                                                 ospf6_nexthop_delete(rnh);
     902             :                                         }
     903             :                                 }
     904             :                                 /* Delete the path from route's path list */
     905           4 :                                 listnode_delete(route->paths, o_path);
     906           4 :                                 ospf6_path_free(o_path);
     907           4 :                                 nh_updated = true;
     908             :                         }
     909             : 
     910          12 :                         if (nh_updated) {
     911             :                                 /* Iterate all paths and merge nexthop,
     912             :                                  * unlesss any of the nexthop similar to
     913             :                                  * ones deleted as part of path deletion.
     914             :                                  */
     915             : 
     916          12 :                                 for (ALL_LIST_ELEMENTS(route->paths, anode,
     917             :                                                        anext, o_path)) {
     918           4 :                                         ospf6_merge_nexthops(route->nh_list,
     919             :                                                              o_path->nh_list);
     920             :                                 }
     921             : 
     922           4 :                                 if (debug) {
     923           0 :                                         zlog_debug(
     924             :                                                 "%s: AS-External %u route %pFX update paths %u nh %u",
     925             :                                                 __func__,
     926             :                                                 (route->path.type
     927             :                                                  == OSPF6_PATH_TYPE_EXTERNAL1)
     928             :                                                         ? 1
     929             :                                                         : 2,
     930             :                                                 &route->prefix, listcount(route->paths),
     931             :                                                 route->nh_list ? listcount(
     932             :                                                         route->nh_list)
     933             :                                                                : 0);
     934             :                                 }
     935             : 
     936           4 :                                 if (listcount(route->paths)) {
     937             :                                         /* Update RIB/FIB with effective
     938             :                                          * nh_list
     939             :                                          */
     940           4 :                                         if (oa->ospf6->route_table->hook_add)
     941           4 :                                                 (*oa->ospf6->route_table
     942             :                                                           ->hook_add)(route);
     943             : 
     944             :                                         /* route's primary path is similar
     945             :                                          * to LSA, replace route's primary
     946             :                                          * path with route's paths list head.
     947             :                                          */
     948           4 :                                         if ((route->path.origin.id ==
     949           4 :                                             lsa->header->id) &&
     950           4 :                                             (route->path.origin.adv_router
     951           4 :                                                  == lsa->header->adv_router)) {
     952           2 :                                                 struct ospf6_path *h_path;
     953             : 
     954           4 :                                                 h_path = (struct ospf6_path *)
     955           2 :                                                 listgetdata(
     956             :                                                         listhead(route->paths));
     957           2 :                                                 route->path.origin.type =
     958           2 :                                                         h_path->origin.type;
     959           2 :                                                 route->path.origin.id =
     960           2 :                                                         h_path->origin.id;
     961           2 :                                                 route->path.origin.adv_router =
     962           2 :                                                 h_path->origin.adv_router;
     963             :                                         }
     964             :                                 } else {
     965           0 :                                         if (type == OSPF6_LSTYPE_TYPE_7)
     966           0 :                                                 ospf6_route_remove(
     967             :                                                         route, oa->route_table);
     968             :                                         else
     969           0 :                                                 ospf6_route_remove(
     970             :                                                         route,
     971           0 :                                                         oa->ospf6->route_table);
     972             :                                 }
     973             :                         }
     974          12 :                         continue;
     975             : 
     976             :                 } else {
     977             :                         /* Compare LSA origin and cost with current route info.
     978             :                          * if any check fails skip del this route node.
     979             :                          */
     980          51 :                         if (asbr_entry
     981          33 :                             && (!ospf6_route_is_same_origin(route, route_to_del)
     982          24 :                                 || (route->path.type != route_to_del->path.type)
     983          24 :                                 || (route->path.cost != route_to_del->path.cost)
     984          24 :                                 || (route->path.u.cost_e2
     985          24 :                                     != route_to_del->path.u.cost_e2))) {
     986           9 :                                 if (debug) {
     987           0 :                                         zlog_debug(
     988             :                                                 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
     989             :                                                 __func__, &prefix, route->path.cost,
     990             :                                                 route_to_del->path.cost);
     991             :                                 }
     992           9 :                                 continue;
     993             :                         }
     994             : 
     995          42 :                         if ((route->path.origin.type != lsa->header->type)
     996          36 :                             || (route->path.origin.adv_router
     997          36 :                                 != lsa->header->adv_router)
     998          36 :                             || (route->path.origin.id != lsa->header->id))
     999           7 :                                 continue;
    1000             :                 }
    1001          35 :                 if (debug) {
    1002           0 :                         zlog_debug(
    1003             :                                 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
    1004             :                                 __func__,
    1005             :                                 route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
    1006             :                                         ? 1
    1007             :                                         : 2,
    1008             :                                 &route->prefix, route->path.cost, route->path.u.cost_e2,
    1009             :                                 listcount(route->nh_list));
    1010             :                 }
    1011          35 :                 if (type == OSPF6_LSTYPE_TYPE_7)
    1012           0 :                         ospf6_route_remove(route, oa->route_table);
    1013             :                 else
    1014          35 :                         ospf6_route_remove(route, oa->ospf6->route_table);
    1015             :         }
    1016          55 :         if (route != NULL)
    1017          45 :                 ospf6_route_unlock(route);
    1018             : 
    1019          55 :         ospf6_route_delete(route_to_del);
    1020             : }
    1021             : 
    1022          19 : void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry, struct ospf6 *ospf6)
    1023             : {
    1024          19 :         struct ospf6_lsa *lsa;
    1025          19 :         uint16_t type;
    1026          19 :         uint32_t router;
    1027             : 
    1028          19 :         if (!CHECK_FLAG(asbr_entry->flag, OSPF6_ROUTE_BEST)) {
    1029           0 :                 char buf[16];
    1030           0 :                 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&asbr_entry->prefix),
    1031             :                           buf, sizeof(buf));
    1032           0 :                 zlog_info("ignore non-best path: lsentry %s add", buf);
    1033           0 :                 return;
    1034             :         }
    1035             : 
    1036          19 :         type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
    1037          19 :         router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
    1038          80 :         for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
    1039          61 :                 if (!OSPF6_LSA_IS_MAXAGE(lsa))
    1040          42 :                         ospf6_asbr_lsa_add(lsa);
    1041             :         }
    1042             : }
    1043             : 
    1044          19 : void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry,
    1045             :                                struct ospf6 *ospf6)
    1046             : {
    1047          19 :         struct ospf6_lsa *lsa;
    1048          19 :         uint16_t type;
    1049          19 :         uint32_t router;
    1050             : 
    1051          19 :         type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
    1052          19 :         router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
    1053          56 :         for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
    1054          37 :                 ospf6_asbr_lsa_remove(lsa, asbr_entry);
    1055          19 : }
    1056             : 
    1057             : 
    1058             : /* redistribute function */
    1059           0 : static void ospf6_asbr_routemap_set(struct ospf6_redist *red,
    1060             :                                     const char *mapname)
    1061             : {
    1062           0 :         if (ROUTEMAP_NAME(red)) {
    1063           0 :                 route_map_counter_decrement(ROUTEMAP(red));
    1064           0 :                 free(ROUTEMAP_NAME(red));
    1065             :         }
    1066             : 
    1067           0 :         ROUTEMAP_NAME(red) = strdup(mapname);
    1068           0 :         ROUTEMAP(red) = route_map_lookup_by_name(mapname);
    1069           0 :         route_map_counter_increment(ROUTEMAP(red));
    1070           0 : }
    1071             : 
    1072           8 : static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
    1073             : {
    1074           8 :         if (ROUTEMAP_NAME(red))
    1075           0 :                 free(ROUTEMAP_NAME(red));
    1076             : 
    1077           8 :         route_map_counter_decrement(ROUTEMAP(red));
    1078             : 
    1079           8 :         ROUTEMAP_NAME(red) = NULL;
    1080           8 :         ROUTEMAP(red) = NULL;
    1081           8 : }
    1082             : 
    1083           0 : static void ospf6_asbr_routemap_update_timer(struct thread *thread)
    1084             : {
    1085           0 :         struct ospf6 *ospf6 = THREAD_ARG(thread);
    1086           0 :         struct ospf6_redist *red;
    1087           0 :         int type;
    1088             : 
    1089           0 :         for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    1090           0 :                 red = ospf6_redist_lookup(ospf6, type, 0);
    1091             : 
    1092           0 :                 if (!red)
    1093           0 :                         continue;
    1094             : 
    1095           0 :                 if (!CHECK_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED))
    1096           0 :                         continue;
    1097             : 
    1098           0 :                 if (ROUTEMAP_NAME(red))
    1099           0 :                         ROUTEMAP(red) =
    1100           0 :                                 route_map_lookup_by_name(ROUTEMAP_NAME(red));
    1101             : 
    1102           0 :                 if (ROUTEMAP(red)) {
    1103           0 :                         if (IS_OSPF6_DEBUG_ASBR)
    1104           0 :                                 zlog_debug(
    1105             :                                         "%s: route-map %s update, reset redist %s",
    1106             :                                         __func__, ROUTEMAP_NAME(red),
    1107             :                                         ZROUTE_NAME(type));
    1108             : 
    1109           0 :                         ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
    1110           0 :                         ospf6_zebra_redistribute(type, ospf6->vrf_id);
    1111             :                 }
    1112             : 
    1113           0 :                 UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
    1114             :         }
    1115           0 : }
    1116             : 
    1117           0 : void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
    1118             :                                        struct ospf6_redist *red)
    1119             : {
    1120           0 :         SET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
    1121             : 
    1122           0 :         if (thread_is_scheduled(ospf6->t_distribute_update))
    1123             :                 return;
    1124             : 
    1125           0 :         if (IS_OSPF6_DEBUG_ASBR)
    1126           0 :                 zlog_debug("%s: trigger redistribute reset thread", __func__);
    1127             : 
    1128           0 :         thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
    1129             :                               OSPF_MIN_LS_INTERVAL,
    1130             :                               &ospf6->t_distribute_update);
    1131             : }
    1132             : 
    1133           0 : void ospf6_asbr_routemap_update(const char *mapname)
    1134             : {
    1135           0 :         int type;
    1136           0 :         struct listnode *node, *nnode;
    1137           0 :         struct ospf6 *ospf6 = NULL;
    1138           0 :         struct ospf6_redist *red;
    1139             : 
    1140           0 :         if (om6 == NULL)
    1141             :                 return;
    1142             : 
    1143           0 :         for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
    1144           0 :                 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    1145           0 :                         red = ospf6_redist_lookup(ospf6, type, 0);
    1146           0 :                         if (!red || (ROUTEMAP_NAME(red) == NULL))
    1147           0 :                                 continue;
    1148           0 :                         ROUTEMAP(red) =
    1149           0 :                                 route_map_lookup_by_name(ROUTEMAP_NAME(red));
    1150             : 
    1151           0 :                         if (mapname == NULL
    1152           0 :                             || strcmp(ROUTEMAP_NAME(red), mapname))
    1153           0 :                                 continue;
    1154           0 :                         if (ROUTEMAP(red)) {
    1155           0 :                                 if (IS_OSPF6_DEBUG_ASBR)
    1156           0 :                                         zlog_debug(
    1157             :                                                         "%s: route-map %s update, reset redist %s",
    1158             :                                                         __func__,
    1159             :                                                         mapname,
    1160             :                                                         ZROUTE_NAME(
    1161             :                                                                 type));
    1162             : 
    1163           0 :                                 route_map_counter_increment(ROUTEMAP(red));
    1164           0 :                                 ospf6_asbr_distribute_list_update(ospf6, red);
    1165             :                         } else {
    1166             :                                 /*
    1167             :                                 * if the mapname matches a
    1168             :                                 * route-map on ospf6 but the
    1169             :                                 * map doesn't exist, it is
    1170             :                                 * being deleted. flush and then
    1171             :                                 * readvertise
    1172             :                                 */
    1173           0 :                                 if (IS_OSPF6_DEBUG_ASBR)
    1174           0 :                                         zlog_debug(
    1175             :                                                         "%s: route-map %s deleted, reset redist %s",
    1176             :                                                         __func__,
    1177             :                                                         mapname,
    1178             :                                                         ZROUTE_NAME(
    1179             :                                                                 type));
    1180           0 :                                 ospf6_asbr_redistribute_unset(ospf6, red, type);
    1181           0 :                                 ospf6_asbr_routemap_set(red, mapname);
    1182           0 :                                 ospf6_asbr_redistribute_set(ospf6, type);
    1183             :                         }
    1184             :                 }
    1185             :         }
    1186             : }
    1187             : 
    1188           0 : static void ospf6_asbr_routemap_event(const char *name)
    1189             : {
    1190           0 :         int type;
    1191           0 :         struct listnode *node, *nnode;
    1192           0 :         struct ospf6 *ospf6;
    1193           0 :         struct ospf6_redist *red;
    1194             : 
    1195           0 :         if (om6 == NULL)
    1196             :                 return;
    1197           0 :         for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
    1198           0 :                 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    1199           0 :                         red = ospf6_redist_lookup(ospf6, type, 0);
    1200           0 :                         if (red && ROUTEMAP_NAME(red)
    1201           0 :                             && (strcmp(ROUTEMAP_NAME(red), name) == 0))
    1202           0 :                                 ospf6_asbr_distribute_list_update(ospf6, red);
    1203             :                 }
    1204             :         }
    1205             : }
    1206             : 
    1207          35 : int ospf6_asbr_is_asbr(struct ospf6 *o)
    1208             : {
    1209          35 :         return (o->external_table->count || IS_OSPF6_ASBR(o));
    1210             : }
    1211             : 
    1212         445 : struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
    1213             :                                          unsigned short instance)
    1214             : {
    1215         445 :         struct list *red_list;
    1216         445 :         struct listnode *node;
    1217         445 :         struct ospf6_redist *red;
    1218             : 
    1219         445 :         red_list = ospf6->redist[type];
    1220         445 :         if (!red_list)
    1221             :                 return (NULL);
    1222             : 
    1223         163 :         for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
    1224         163 :                 if (red->instance == instance)
    1225         163 :                         return red;
    1226             : 
    1227             :         return NULL;
    1228             : }
    1229             : 
    1230           4 : static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
    1231             :                                              uint8_t instance)
    1232             : {
    1233           4 :         struct ospf6_redist *red;
    1234             : 
    1235           4 :         red = ospf6_redist_lookup(ospf6, type, instance);
    1236           4 :         if (red)
    1237             :                 return red;
    1238             : 
    1239           4 :         if (!ospf6->redist[type])
    1240           4 :                 ospf6->redist[type] = list_new();
    1241             : 
    1242           4 :         red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
    1243           4 :         red->instance = instance;
    1244           4 :         red->dmetric.type = -1;
    1245           4 :         red->dmetric.value = -1;
    1246           4 :         ROUTEMAP_NAME(red) = NULL;
    1247           4 :         ROUTEMAP(red) = NULL;
    1248             : 
    1249           4 :         listnode_add(ospf6->redist[type], red);
    1250           4 :         ospf6->redistribute++;
    1251             : 
    1252           4 :         return red;
    1253             : }
    1254             : 
    1255           4 : static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
    1256             :                              int type)
    1257             : {
    1258           4 :         if (red) {
    1259           4 :                 listnode_delete(ospf6->redist[type], red);
    1260           4 :                 if (!ospf6->redist[type]->count) {
    1261           4 :                         list_delete(&ospf6->redist[type]);
    1262             :                 }
    1263           4 :                 XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
    1264           4 :                 ospf6->redistribute--;
    1265             :         }
    1266           4 : }
    1267             : 
    1268             : /*Set the status of the ospf instance to ASBR based on the status parameter,
    1269             :  * rechedule SPF calculation, originate router LSA*/
    1270          79 : void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
    1271             : {
    1272          79 :         struct listnode *lnode, *lnnode;
    1273          79 :         struct ospf6_area *oa;
    1274             : 
    1275          79 :         zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
    1276             : 
    1277          79 :         if (status) {
    1278          75 :                 if (IS_OSPF6_ASBR(ospf6)) {
    1279          71 :                         zlog_info("ASBR[%s:Status:%d]: Already ASBR",
    1280             :                                   ospf6->name, status);
    1281          71 :                         return;
    1282             :                 }
    1283           4 :                 SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
    1284             :         } else {
    1285           4 :                 if (!IS_OSPF6_ASBR(ospf6)) {
    1286           0 :                         zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
    1287             :                                   ospf6->name, status);
    1288           0 :                         return;
    1289             :                 }
    1290           4 :                 UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
    1291             :         }
    1292             : 
    1293             :         /* Transition from/to status ASBR, schedule timer. */
    1294           8 :         ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
    1295             : 
    1296             :         /* Reoriginate router LSA for all areas */
    1297          21 :         for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
    1298           5 :                 OSPF6_ROUTER_LSA_SCHEDULE(oa);
    1299             : }
    1300             : 
    1301           4 : static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type)
    1302             : {
    1303           4 :         ospf6_zebra_redistribute(type, ospf6->vrf_id);
    1304             : 
    1305           4 :         ++ospf6->redist_count;
    1306           4 :         ospf6_asbr_status_update(ospf6, ospf6->redist_count);
    1307           4 : }
    1308             : 
    1309           4 : static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
    1310             :                                           struct ospf6_redist *red, int type)
    1311             : {
    1312           4 :         struct ospf6_route *route;
    1313           4 :         struct ospf6_external_info *info;
    1314             : 
    1315           4 :         ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
    1316             : 
    1317          14 :         for (route = ospf6_route_head(ospf6->external_table); route;
    1318          10 :              route = ospf6_route_next(route)) {
    1319          10 :                 info = route->route_option;
    1320          10 :                 if (info->type != type)
    1321           0 :                         continue;
    1322             : 
    1323          10 :                 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix,
    1324             :                                                ospf6);
    1325             :         }
    1326             : 
    1327           4 :         ospf6_asbr_routemap_unset(red);
    1328           4 :         --ospf6->redist_count;
    1329           4 :         ospf6_asbr_status_update(ospf6, ospf6->redist_count);
    1330           4 : }
    1331             : 
    1332             : /* When an area is unstubified, flood all the external LSAs in the area */
    1333           0 : void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
    1334             : {
    1335           0 :         struct ospf6_lsa *lsa, *lsanext;
    1336             : 
    1337           0 :         for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
    1338           0 :                 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
    1339           0 :                         if (IS_OSPF6_DEBUG_ASBR)
    1340           0 :                                 zlog_debug("%s: Flooding AS-External LSA %s",
    1341             :                                            __func__, lsa->name);
    1342             : 
    1343           0 :                         ospf6_flood_area(NULL, lsa, oa);
    1344             :                 }
    1345             :         }
    1346           0 : }
    1347             : 
    1348             : /* When an area is stubified, remove all the external LSAs in the area */
    1349           0 : void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
    1350             : {
    1351           0 :         struct ospf6_lsa *lsa, *lsanext;
    1352           0 :         struct listnode *node, *nnode;
    1353           0 :         struct ospf6_area *area;
    1354           0 :         struct ospf6 *ospf6 = oa->ospf6;
    1355           0 :         const struct route_node *iterend;
    1356             : 
    1357             :         /* skip if router is in other non-stub/non-NSSA areas */
    1358           0 :         for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
    1359           0 :                 if (!IS_AREA_STUB(area) && !IS_AREA_NSSA(area))
    1360           0 :                         return;
    1361             : 
    1362             :         /* if router is only in a stub area then purge AS-External LSAs */
    1363           0 :         iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
    1364           0 :         while (lsa != NULL) {
    1365           0 :                 assert(lsa->lock > 1);
    1366           0 :                 lsanext = ospf6_lsdb_next(iterend, lsa);
    1367           0 :                 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
    1368           0 :                         ospf6_lsdb_remove(lsa, ospf6->lsdb);
    1369           0 :                 lsa = lsanext;
    1370             :         }
    1371             : }
    1372             : 
    1373             : static struct ospf6_external_aggr_rt *
    1374          53 : ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p)
    1375             : {
    1376          53 :         struct route_node *node;
    1377             : 
    1378          53 :         node = route_node_match(ospf6->rt_aggr_tbl, p);
    1379          53 :         if (node == NULL)
    1380             :                 return NULL;
    1381             : 
    1382           0 :         if (IS_OSPF6_DEBUG_AGGR) {
    1383           0 :                 struct ospf6_external_aggr_rt *ag = node->info;
    1384           0 :                 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
    1385             :                         __func__,
    1386             :                         p,
    1387             :                         &ag->p);
    1388             :         }
    1389             : 
    1390           0 :         route_unlock_node(node);
    1391             : 
    1392           0 :         return node->info;
    1393             : }
    1394             : 
    1395          53 : void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
    1396             :                                  struct prefix *prefix,
    1397             :                                  unsigned int nexthop_num,
    1398             :                                  struct in6_addr *nexthop, route_tag_t tag,
    1399             :                                  struct ospf6 *ospf6)
    1400             : {
    1401          53 :         route_map_result_t ret;
    1402          53 :         struct ospf6_route troute;
    1403          53 :         struct ospf6_external_info tinfo;
    1404          53 :         struct ospf6_route *route, *match;
    1405          53 :         struct ospf6_external_info *info;
    1406          53 :         struct ospf6_redist *red;
    1407             : 
    1408          53 :         red = ospf6_redist_lookup(ospf6, type, 0);
    1409             : 
    1410          53 :         if (!red)
    1411          35 :                 return;
    1412             : 
    1413          53 :         if ((type != DEFAULT_ROUTE)
    1414          53 :             && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
    1415             :                 return;
    1416             : 
    1417          53 :         memset(&troute, 0, sizeof(troute));
    1418          53 :         memset(&tinfo, 0, sizeof(tinfo));
    1419             : 
    1420          53 :         if (IS_OSPF6_DEBUG_ASBR)
    1421           0 :                 zlog_debug("Redistribute %pFX (%s)", prefix,
    1422             :                            type == DEFAULT_ROUTE
    1423             :                                    ? "default-information-originate"
    1424             :                                    : ZROUTE_NAME(type));
    1425             : 
    1426             :         /* if route-map was specified but not found, do not advertise */
    1427          53 :         if (ROUTEMAP_NAME(red)) {
    1428           0 :                 if (ROUTEMAP(red) == NULL)
    1429           0 :                         ospf6_asbr_routemap_update(NULL);
    1430           0 :                 if (ROUTEMAP(red) == NULL) {
    1431           0 :                         zlog_warn(
    1432             :                                 "route-map \"%s\" not found, suppress redistributing",
    1433             :                                 ROUTEMAP_NAME(red));
    1434           0 :                         return;
    1435             :                 }
    1436             :         }
    1437             : 
    1438             :         /* apply route-map */
    1439          53 :         if (ROUTEMAP(red)) {
    1440           0 :                 troute.route_option = &tinfo;
    1441           0 :                 troute.ospf6 = ospf6;
    1442           0 :                 tinfo.ifindex = ifindex;
    1443           0 :                 tinfo.tag = tag;
    1444             : 
    1445           0 :                 ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
    1446           0 :                 if (ret == RMAP_DENYMATCH) {
    1447           0 :                         if (IS_OSPF6_DEBUG_ASBR)
    1448           0 :                                 zlog_debug("Denied by route-map \"%s\"",
    1449             :                                            ROUTEMAP_NAME(red));
    1450           0 :                         ospf6_asbr_redistribute_remove(type, ifindex, prefix,
    1451             :                                                        ospf6);
    1452           0 :                         return;
    1453             :                 }
    1454             :         }
    1455             : 
    1456          53 :         match = ospf6_route_lookup(prefix, ospf6->external_table);
    1457          53 :         if (match) {
    1458          35 :                 info = match->route_option;
    1459             :                 /* copy result of route-map */
    1460          35 :                 if (ROUTEMAP(red)) {
    1461           0 :                         if (troute.path.metric_type)
    1462           0 :                                 match->path.metric_type =
    1463             :                                         troute.path.metric_type;
    1464             :                         else
    1465           0 :                                 match->path.metric_type =
    1466           0 :                                         metric_type(ospf6, type, 0);
    1467           0 :                         if (troute.path.cost)
    1468           0 :                                 match->path.cost = troute.path.cost;
    1469             :                         else
    1470           0 :                                 match->path.cost = metric_value(ospf6, type, 0);
    1471             : 
    1472           0 :                         if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
    1473           0 :                                 memcpy(&info->forwarding, &tinfo.forwarding,
    1474             :                                        sizeof(struct in6_addr));
    1475           0 :                         info->tag = tinfo.tag;
    1476             :                 } else {
    1477             :                         /* If there is no route-map, simply update the tag and
    1478             :                          * metric fields
    1479             :                          */
    1480          35 :                         match->path.metric_type = metric_type(ospf6, type, 0);
    1481          35 :                         match->path.cost = metric_value(ospf6, type, 0);
    1482          35 :                         info->tag = tag;
    1483             :                 }
    1484             : 
    1485          35 :                 info->type = type;
    1486             : 
    1487          35 :                 if (nexthop_num && nexthop)
    1488          35 :                         ospf6_route_add_nexthop(match, ifindex, nexthop);
    1489             :                 else
    1490           0 :                         ospf6_route_add_nexthop(match, ifindex, NULL);
    1491             : 
    1492          35 :                 match->path.origin.id = htonl(info->id);
    1493          35 :                 ospf6_handle_external_lsa_origination(ospf6, match, prefix);
    1494             : 
    1495          35 :                 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
    1496             : 
    1497          35 :                 return;
    1498             :         }
    1499             : 
    1500             :         /* create new entry */
    1501          18 :         route = ospf6_route_create(ospf6);
    1502          18 :         route->type = OSPF6_DEST_TYPE_NETWORK;
    1503          18 :         prefix_copy(&route->prefix, prefix);
    1504             : 
    1505          18 :         info = (struct ospf6_external_info *)XCALLOC(
    1506             :                 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
    1507          18 :         route->route_option = info;
    1508             : 
    1509             :         /* copy result of route-map */
    1510          18 :         if (ROUTEMAP(red)) {
    1511           0 :                 if (troute.path.metric_type)
    1512           0 :                         route->path.metric_type = troute.path.metric_type;
    1513             :                 else
    1514           0 :                         route->path.metric_type = metric_type(ospf6, type, 0);
    1515           0 :                 if (troute.path.cost)
    1516           0 :                         route->path.cost = troute.path.cost;
    1517             :                 else
    1518           0 :                         route->path.cost = metric_value(ospf6, type, 0);
    1519           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
    1520           0 :                         memcpy(&info->forwarding, &tinfo.forwarding,
    1521             :                                sizeof(struct in6_addr));
    1522           0 :                 info->tag = tinfo.tag;
    1523             :         } else {
    1524             :                 /* If there is no route-map, simply update the tag and metric
    1525             :                  * fields
    1526             :                  */
    1527          18 :                 route->path.metric_type = metric_type(ospf6, type, 0);
    1528          18 :                 route->path.cost = metric_value(ospf6, type, 0);
    1529          18 :                 info->tag = tag;
    1530             :         }
    1531             : 
    1532          18 :         info->type = type;
    1533          18 :         if (nexthop_num && nexthop)
    1534          18 :                 ospf6_route_add_nexthop(route, ifindex, nexthop);
    1535             :         else
    1536           0 :                 ospf6_route_add_nexthop(route, ifindex, NULL);
    1537             : 
    1538          18 :         route = ospf6_route_add(route, ospf6->external_table);
    1539          18 :         ospf6_handle_external_lsa_origination(ospf6, route, prefix);
    1540             : 
    1541          18 :         ospf6_asbr_status_update(ospf6, ospf6->redistribute);
    1542             : 
    1543             : }
    1544             : 
    1545          18 : static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6,
    1546             :                                          uint32_t id)
    1547             : {
    1548          18 :         struct ospf6_lsa *lsa;
    1549             : 
    1550          18 :         lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
    1551             :                                 htonl(id), ospf6->router_id, ospf6->lsdb);
    1552          18 :         if (!lsa)
    1553             :                 return;
    1554             : 
    1555          18 :         ospf6_external_lsa_purge(ospf6, lsa);
    1556             : 
    1557             : }
    1558             : 
    1559             : static void
    1560           0 : ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt *aggr,
    1561             :                         struct ospf6_route *rt)
    1562             : {
    1563           0 :         (void)hash_get(aggr->match_extnl_hash, rt, hash_alloc_intern);
    1564           0 :         rt->aggr_route = aggr;
    1565             : }
    1566             : 
    1567             : static void
    1568           0 : ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
    1569             :                                         struct ospf6_external_aggr_rt *aggr)
    1570             : {
    1571             : 
    1572             :         /* Send a Max age LSA if it is already originated.*/
    1573           0 :         if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED))
    1574             :                 return;
    1575             : 
    1576           0 :         if (IS_OSPF6_DEBUG_AGGR)
    1577           0 :                 zlog_debug("%s: Flushing Aggregate route (%pFX)",
    1578             :                                 __func__,
    1579             :                                 &aggr->p);
    1580             : 
    1581           0 :         ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id);
    1582             : 
    1583           0 :         if (aggr->route) {
    1584           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    1585           0 :                         zlog_debug(
    1586             :                                 "%s: Remove the blackhole route",
    1587             :                                 __func__);
    1588             : 
    1589           0 :                 ospf6_zebra_route_update_remove(aggr->route, ospf6);
    1590           0 :                 if (aggr->route->route_option)
    1591           0 :                         XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
    1592             :                               aggr->route->route_option);
    1593           0 :                 ospf6_route_delete(aggr->route);
    1594           0 :                 aggr->route = NULL;
    1595             :         }
    1596             : 
    1597           0 :         aggr->id = 0;
    1598             :         /* Unset the Origination flag */
    1599           0 :         UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    1600             : }
    1601             : 
    1602             : static void
    1603           0 : ospf6_unlink_route_from_aggr(struct ospf6 *ospf6,
    1604             :                              struct ospf6_external_aggr_rt *aggr,
    1605             :                              struct ospf6_route *rt)
    1606             : {
    1607           0 :         if (IS_OSPF6_DEBUG_AGGR)
    1608           0 :                 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
    1609             :                                         __func__,
    1610             :                                         &rt->prefix,
    1611             :                                         &aggr->p,
    1612             :                                         OSPF6_EXTERNAL_RT_COUNT(aggr));
    1613             : 
    1614           0 :         hash_release(aggr->match_extnl_hash, rt);
    1615           0 :         rt->aggr_route = NULL;
    1616             : 
    1617             :         /* Flush the aggregate route if matching
    1618             :          * external route count becomes zero.
    1619             :          */
    1620           0 :         if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
    1621           0 :                 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
    1622           0 : }
    1623             : 
    1624          26 : void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
    1625             :                                     struct prefix *prefix, struct ospf6 *ospf6)
    1626             : {
    1627          26 :         struct ospf6_route *match;
    1628          26 :         struct ospf6_external_info *info = NULL;
    1629             : 
    1630          26 :         match = ospf6_route_lookup(prefix, ospf6->external_table);
    1631          26 :         if (match == NULL) {
    1632           8 :                 if (IS_OSPF6_DEBUG_ASBR)
    1633           0 :                         zlog_debug("No such route %pFX to withdraw", prefix);
    1634           8 :                 return;
    1635             :         }
    1636             : 
    1637          18 :         info = match->route_option;
    1638          18 :         assert(info);
    1639             : 
    1640          18 :         if (info->type != type) {
    1641           0 :                 if (IS_OSPF6_DEBUG_ASBR)
    1642           0 :                         zlog_debug("Original protocol mismatch: %pFX", prefix);
    1643           0 :                 return;
    1644             :         }
    1645             : 
    1646             :         /* This means aggregation on this route was not done, hence remove LSA
    1647             :          * if any originated for this prefix
    1648             :          */
    1649          18 :         if (!match->aggr_route)
    1650          18 :                 ospf6_asbr_external_lsa_remove_by_id(ospf6, info->id);
    1651             :         else
    1652           0 :                 ospf6_unlink_route_from_aggr(ospf6, match->aggr_route, match);
    1653             : 
    1654          18 :         if (IS_OSPF6_DEBUG_ASBR)
    1655           0 :                 zlog_debug("Removing route from external table %pFX",
    1656             :                            prefix);
    1657             : 
    1658          18 :         ospf6_route_remove(match, ospf6->external_table);
    1659          18 :         XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
    1660             : 
    1661          18 :         ospf6_asbr_status_update(ospf6, ospf6->redistribute);
    1662             : }
    1663             : 
    1664           4 : DEFPY (ospf6_redistribute,
    1665             :        ospf6_redistribute_cmd,
    1666             :        "redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map RMAP_NAME$rmap_str}]",
    1667             :        "Redistribute\n"
    1668             :        FRR_REDIST_HELP_STR_OSPF6D
    1669             :        "Metric for redistributed routes\n"
    1670             :        "OSPF default metric\n"
    1671             :        "OSPF exterior metric type for redistributed routes\n"
    1672             :        "Set OSPF External Type 1/2 metrics\n"
    1673             :        "Route map reference\n"
    1674             :        "Route map name\n")
    1675             : {
    1676           4 :         int type;
    1677           4 :         struct ospf6_redist *red;
    1678           4 :         int idx_protocol = 1;
    1679           4 :         char *proto = argv[idx_protocol]->text;
    1680             : 
    1681           4 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1682             : 
    1683           4 :         type = proto_redistnum(AFI_IP6, proto);
    1684           4 :         if (type < 0)
    1685             :                 return CMD_WARNING_CONFIG_FAILED;
    1686             : 
    1687           4 :         if (!metric_str)
    1688           4 :                 metric = -1;
    1689           4 :         if (!metric_type_str)
    1690           4 :                 metric_type = -1;
    1691             : 
    1692           4 :         red = ospf6_redist_lookup(ospf6, type, 0);
    1693           4 :         if (!red) {
    1694           4 :                 red = ospf6_redist_add(ospf6, type, 0);
    1695             :         } else {
    1696             :                 /* Check if nothing has changed. */
    1697           0 :                 if (red->dmetric.value == metric
    1698           0 :                     && red->dmetric.type == metric_type
    1699           0 :                     && ((!ROUTEMAP_NAME(red) && !rmap_str)
    1700           0 :                         || (ROUTEMAP_NAME(red) && rmap_str
    1701           0 :                             && strmatch(ROUTEMAP_NAME(red), rmap_str))))
    1702             :                         return CMD_SUCCESS;
    1703             : 
    1704           0 :                 ospf6_asbr_redistribute_unset(ospf6, red, type);
    1705             :         }
    1706             : 
    1707           4 :         red->dmetric.value = metric;
    1708           4 :         red->dmetric.type = metric_type;
    1709           4 :         if (rmap_str)
    1710           0 :                 ospf6_asbr_routemap_set(red, rmap_str);
    1711             :         else
    1712           4 :                 ospf6_asbr_routemap_unset(red);
    1713           4 :         ospf6_asbr_redistribute_set(ospf6, type);
    1714             : 
    1715           4 :         return CMD_SUCCESS;
    1716             : }
    1717             : 
    1718           0 : DEFUN (no_ospf6_redistribute,
    1719             :        no_ospf6_redistribute_cmd,
    1720             :        "no redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
    1721             :        NO_STR
    1722             :        "Redistribute\n"
    1723             :        FRR_REDIST_HELP_STR_OSPF6D
    1724             :        "Metric for redistributed routes\n"
    1725             :        "OSPF default metric\n"
    1726             :        "OSPF exterior metric type for redistributed routes\n"
    1727             :        "Set OSPF External Type 1/2 metrics\n"
    1728             :        "Route map reference\n"
    1729             :        "Route map name\n")
    1730             : {
    1731           0 :         int type;
    1732           0 :         struct ospf6_redist *red;
    1733           0 :         int idx_protocol = 2;
    1734           0 :         char *proto = argv[idx_protocol]->text;
    1735             : 
    1736           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1737             : 
    1738           0 :         type = proto_redistnum(AFI_IP6, proto);
    1739           0 :         if (type < 0)
    1740             :                 return CMD_WARNING_CONFIG_FAILED;
    1741             : 
    1742           0 :         red = ospf6_redist_lookup(ospf6, type, 0);
    1743           0 :         if (!red)
    1744             :                 return CMD_SUCCESS;
    1745             : 
    1746           0 :         ospf6_asbr_redistribute_unset(ospf6, red, type);
    1747           0 :         ospf6_redist_del(ospf6, red, type);
    1748             : 
    1749           0 :         return CMD_SUCCESS;
    1750             : }
    1751             : 
    1752           0 : int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
    1753             : {
    1754           0 :         int type;
    1755           0 :         struct ospf6_redist *red;
    1756             : 
    1757           0 :         for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    1758           0 :                 red = ospf6_redist_lookup(ospf6, type, 0);
    1759           0 :                 if (!red)
    1760           0 :                         continue;
    1761           0 :                 if (type == ZEBRA_ROUTE_OSPF6)
    1762           0 :                         continue;
    1763             : 
    1764           0 :                 vty_out(vty, " redistribute %s", ZROUTE_NAME(type));
    1765           0 :                 if (red->dmetric.value >= 0)
    1766           0 :                         vty_out(vty, " metric %d", red->dmetric.value);
    1767           0 :                 if (red->dmetric.type == 1)
    1768           0 :                         vty_out(vty, " metric-type 1");
    1769           0 :                 if (ROUTEMAP_NAME(red))
    1770           0 :                         vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
    1771           0 :                 vty_out(vty, "\n");
    1772             :         }
    1773             : 
    1774           0 :         return 0;
    1775             : }
    1776             : 
    1777           0 : static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
    1778             :                                            json_object *json_array,
    1779             :                                            json_object *json, bool use_json)
    1780             : {
    1781           0 :         int type;
    1782           0 :         int nroute[ZEBRA_ROUTE_MAX];
    1783           0 :         int total;
    1784           0 :         struct ospf6_route *route;
    1785           0 :         struct ospf6_external_info *info;
    1786           0 :         json_object *json_route;
    1787           0 :         struct ospf6_redist *red;
    1788             : 
    1789           0 :         total = 0;
    1790           0 :         memset(nroute, 0, sizeof(nroute));
    1791           0 :         for (route = ospf6_route_head(ospf6->external_table); route;
    1792           0 :              route = ospf6_route_next(route)) {
    1793           0 :                 info = route->route_option;
    1794           0 :                 nroute[info->type]++;
    1795           0 :                 total++;
    1796             :         }
    1797             : 
    1798           0 :         if (!use_json)
    1799           0 :                 vty_out(vty, "Redistributing External Routes from:\n");
    1800             : 
    1801           0 :         for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    1802             : 
    1803           0 :                 red = ospf6_redist_lookup(ospf6, type, 0);
    1804             : 
    1805           0 :                 if (!red)
    1806           0 :                         continue;
    1807           0 :                 if (type == ZEBRA_ROUTE_OSPF6)
    1808           0 :                         continue;
    1809             : 
    1810           0 :                 if (use_json) {
    1811           0 :                         json_route = json_object_new_object();
    1812           0 :                         json_object_string_add(json_route, "routeType",
    1813             :                                                ZROUTE_NAME(type));
    1814           0 :                         json_object_int_add(json_route, "numberOfRoutes",
    1815           0 :                                             nroute[type]);
    1816           0 :                         json_object_boolean_add(json_route,
    1817             :                                                 "routeMapNamePresent",
    1818           0 :                                                 ROUTEMAP_NAME(red));
    1819             :                 }
    1820             : 
    1821           0 :                 if (ROUTEMAP_NAME(red)) {
    1822           0 :                         if (use_json) {
    1823           0 :                                 json_object_string_add(json_route,
    1824             :                                                        "routeMapName",
    1825             :                                                        ROUTEMAP_NAME(red));
    1826           0 :                                 json_object_boolean_add(json_route,
    1827             :                                                         "routeMapFound",
    1828           0 :                                                         ROUTEMAP(red));
    1829             :                         } else
    1830           0 :                                 vty_out(vty,
    1831             :                                         "    %d: %s with route-map \"%s\"%s\n",
    1832             :                                         nroute[type], ZROUTE_NAME(type),
    1833             :                                         ROUTEMAP_NAME(red),
    1834           0 :                                         (ROUTEMAP(red) ? ""
    1835             :                                                        : " (not found !)"));
    1836             :                 } else {
    1837           0 :                         if (!use_json)
    1838           0 :                                 vty_out(vty, "    %d: %s\n", nroute[type],
    1839             :                                         ZROUTE_NAME(type));
    1840             :                 }
    1841             : 
    1842           0 :                 if (use_json)
    1843           0 :                         json_object_array_add(json_array, json_route);
    1844             :         }
    1845           0 :         if (use_json) {
    1846           0 :                 json_object_object_add(json, "redistributedRoutes", json_array);
    1847           0 :                 json_object_int_add(json, "totalRoutes", total);
    1848             :         } else
    1849           0 :                 vty_out(vty, "Total %d routes\n", total);
    1850           0 : }
    1851             : 
    1852           0 : static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate)
    1853             : {
    1854           0 :         struct prefix_ipv6 p = {};
    1855           0 :         struct in6_addr nexthop = {};
    1856           0 :         int cur_originate = ospf6->default_originate;
    1857             : 
    1858           0 :         p.family = AF_INET6;
    1859           0 :         p.prefixlen = 0;
    1860             : 
    1861           0 :         ospf6->default_originate = originate;
    1862             : 
    1863           0 :         switch (cur_originate) {
    1864             :         case DEFAULT_ORIGINATE_NONE:
    1865             :                 break;
    1866           0 :         case DEFAULT_ORIGINATE_ZEBRA:
    1867           0 :                 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
    1868             :                                              zclient, AFI_IP6, ospf6->vrf_id);
    1869           0 :                 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
    1870             :                                                (struct prefix *)&p, ospf6);
    1871             : 
    1872           0 :                 break;
    1873           0 :         case DEFAULT_ORIGINATE_ALWAYS:
    1874           0 :                 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
    1875             :                                                (struct prefix *)&p, ospf6);
    1876           0 :                 break;
    1877             :         }
    1878             : 
    1879           0 :         switch (originate) {
    1880             :         case DEFAULT_ORIGINATE_NONE:
    1881             :                 break;
    1882           0 :         case DEFAULT_ORIGINATE_ZEBRA:
    1883           0 :                 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
    1884             :                                              zclient, AFI_IP6, ospf6->vrf_id);
    1885             : 
    1886           0 :                 break;
    1887           0 :         case DEFAULT_ORIGINATE_ALWAYS:
    1888           0 :                 ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0,
    1889             :                                             (struct prefix *)&p, 0, &nexthop, 0,
    1890             :                                             ospf6);
    1891           0 :                 break;
    1892             :         }
    1893           0 : }
    1894             : 
    1895             : /* Default Route originate. */
    1896           0 : DEFPY (ospf6_default_route_originate,
    1897             :        ospf6_default_route_originate_cmd,
    1898             :        "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map RMAP_NAME$rtmap}]",
    1899             :        "Control distribution of default route\n"
    1900             :        "Distribute a default route\n"
    1901             :        "Always advertise default route\n"
    1902             :        "OSPFv3 default metric\n"
    1903             :        "OSPFv3 metric\n"
    1904             :        "OSPFv3 metric type for default routes\n"
    1905             :        "Set OSPFv3 External Type 1/2 metrics\n"
    1906             :        "Route map reference\n"
    1907             :        "Pointer to route-map entries\n")
    1908             : {
    1909           0 :         int default_originate = DEFAULT_ORIGINATE_ZEBRA;
    1910           0 :         struct ospf6_redist *red;
    1911           0 :         bool sameRtmap = false;
    1912             : 
    1913           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1914             : 
    1915           0 :         int cur_originate = ospf6->default_originate;
    1916             : 
    1917           0 :         red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
    1918             : 
    1919           0 :         if (always != NULL)
    1920           0 :                 default_originate = DEFAULT_ORIGINATE_ALWAYS;
    1921             : 
    1922           0 :         if (mval_str == NULL)
    1923           0 :                 mval = -1;
    1924             : 
    1925           0 :         if (mtype_str == NULL)
    1926           0 :                 mtype = -1;
    1927             : 
    1928             :         /* To check if user is providing same route map */
    1929           0 :         if ((!rtmap && !ROUTEMAP_NAME(red)) ||
    1930           0 :             (rtmap && ROUTEMAP_NAME(red) &&
    1931           0 :              (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0)))
    1932           0 :                 sameRtmap = true;
    1933             : 
    1934             :         /* Don't allow if the same lsa is already originated. */
    1935           0 :         if ((sameRtmap) && (red->dmetric.type == mtype)
    1936           0 :             && (red->dmetric.value == mval)
    1937           0 :             && (cur_originate == default_originate))
    1938             :                 return CMD_SUCCESS;
    1939             : 
    1940             :         /* Updating Metric details */
    1941           0 :         red->dmetric.type = mtype;
    1942           0 :         red->dmetric.value = mval;
    1943             : 
    1944             :         /* updating route map details */
    1945           0 :         if (rtmap)
    1946           0 :                 ospf6_asbr_routemap_set(red, rtmap);
    1947             :         else
    1948           0 :                 ospf6_asbr_routemap_unset(red);
    1949             : 
    1950           0 :         ospf6_redistribute_default_set(ospf6, default_originate);
    1951           0 :         return CMD_SUCCESS;
    1952             : }
    1953             : 
    1954           0 : DEFPY (no_ospf6_default_information_originate,
    1955             :        no_ospf6_default_information_originate_cmd,
    1956             :        "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
    1957             :        NO_STR
    1958             :        "Control distribution of default information\n"
    1959             :        "Distribute a default route\n"
    1960             :        "Always advertise default route\n"
    1961             :        "OSPFv3 default metric\n"
    1962             :        "OSPFv3 metric\n"
    1963             :        "OSPFv3 metric type for default routes\n"
    1964             :        "Set OSPFv3 External Type 1/2 metrics\n"
    1965             :        "Route map reference\n"
    1966             :        "Pointer to route-map entries\n")
    1967             : {
    1968           0 :         struct ospf6_redist *red;
    1969             : 
    1970           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1971             : 
    1972           0 :         red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
    1973           0 :         if (!red)
    1974             :                 return CMD_SUCCESS;
    1975             : 
    1976           0 :         ospf6_asbr_routemap_unset(red);
    1977           0 :         ospf6_redist_del(ospf6, red, DEFAULT_ROUTE);
    1978             : 
    1979           0 :         ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
    1980           0 :         return CMD_SUCCESS;
    1981             : }
    1982             : 
    1983             : /* Routemap Functions */
    1984             : static enum route_map_cmd_result_t
    1985           0 : ospf6_routemap_rule_match_address_prefixlist(void *rule,
    1986             :                                              const struct prefix *prefix,
    1987             : 
    1988             :                                              void *object)
    1989             : {
    1990           0 :         struct prefix_list *plist;
    1991             : 
    1992           0 :         plist = prefix_list_lookup(AFI_IP6, (char *)rule);
    1993           0 :         if (plist == NULL)
    1994             :                 return RMAP_NOMATCH;
    1995             : 
    1996           0 :         return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
    1997           0 :                                                                 : RMAP_MATCH);
    1998             : }
    1999             : 
    2000             : static void *
    2001           0 : ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
    2002             : {
    2003           0 :         return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
    2004             : }
    2005             : 
    2006           0 : static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
    2007             : {
    2008           0 :         XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
    2009           0 : }
    2010             : 
    2011             : static const struct route_map_rule_cmd
    2012             :                 ospf6_routemap_rule_match_address_prefixlist_cmd = {
    2013             :         "ipv6 address prefix-list",
    2014             :         ospf6_routemap_rule_match_address_prefixlist,
    2015             :         ospf6_routemap_rule_match_address_prefixlist_compile,
    2016             :         ospf6_routemap_rule_match_address_prefixlist_free,
    2017             : };
    2018             : 
    2019             : /* `match interface IFNAME' */
    2020             : /* Match function should return 1 if match is success else return
    2021             :    zero. */
    2022             : static enum route_map_cmd_result_t
    2023           0 : ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
    2024             :                                     void *object)
    2025             : {
    2026           0 :         struct interface *ifp;
    2027           0 :         struct ospf6_route *route;
    2028           0 :         struct ospf6_external_info *ei;
    2029             : 
    2030           0 :         route = object;
    2031           0 :         ei = route->route_option;
    2032           0 :         ifp = if_lookup_by_name((char *)rule, route->ospf6->vrf_id);
    2033             : 
    2034           0 :         if (ifp != NULL && ei->ifindex == ifp->ifindex)
    2035           0 :                 return RMAP_MATCH;
    2036             : 
    2037             :         return RMAP_NOMATCH;
    2038             : }
    2039             : 
    2040             : /* Route map `interface' match statement.  `arg' should be
    2041             :    interface name. */
    2042           0 : static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
    2043             : {
    2044           0 :         return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
    2045             : }
    2046             : 
    2047             : /* Free route map's compiled `interface' value. */
    2048           0 : static void ospf6_routemap_rule_match_interface_free(void *rule)
    2049             : {
    2050           0 :         XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
    2051           0 : }
    2052             : 
    2053             : /* Route map commands for interface matching. */
    2054             : static const struct route_map_rule_cmd
    2055             :                 ospf6_routemap_rule_match_interface_cmd = {
    2056             :         "interface",
    2057             :         ospf6_routemap_rule_match_interface,
    2058             :         ospf6_routemap_rule_match_interface_compile,
    2059             :         ospf6_routemap_rule_match_interface_free
    2060             : };
    2061             : 
    2062             : /* Match function for matching route tags */
    2063             : static enum route_map_cmd_result_t
    2064           0 : ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, void *object)
    2065             : {
    2066           0 :         route_tag_t *tag = rule;
    2067           0 :         struct ospf6_route *route = object;
    2068           0 :         struct ospf6_external_info *info = route->route_option;
    2069             : 
    2070           0 :         if (info->tag == *tag)
    2071           0 :                 return RMAP_MATCH;
    2072             : 
    2073             :         return RMAP_NOMATCH;
    2074             : }
    2075             : 
    2076             : static const struct route_map_rule_cmd
    2077             :                 ospf6_routemap_rule_match_tag_cmd = {
    2078             :         "tag",
    2079             :         ospf6_routemap_rule_match_tag,
    2080             :         route_map_rule_tag_compile,
    2081             :         route_map_rule_tag_free,
    2082             : };
    2083             : 
    2084             : static enum route_map_cmd_result_t
    2085           0 : ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
    2086             :                                     void *object)
    2087             : {
    2088           0 :         char *metric_type = rule;
    2089           0 :         struct ospf6_route *route = object;
    2090             : 
    2091           0 :         if (strcmp(metric_type, "type-2") == 0)
    2092           0 :                 route->path.metric_type = 2;
    2093             :         else
    2094           0 :                 route->path.metric_type = 1;
    2095             : 
    2096           0 :         return RMAP_OKAY;
    2097             : }
    2098             : 
    2099           0 : static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
    2100             : {
    2101           0 :         if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
    2102             :                 return NULL;
    2103           0 :         return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
    2104             : }
    2105             : 
    2106           0 : static void ospf6_routemap_rule_set_metric_type_free(void *rule)
    2107             : {
    2108           0 :         XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
    2109           0 : }
    2110             : 
    2111             : static const struct route_map_rule_cmd
    2112             :                 ospf6_routemap_rule_set_metric_type_cmd = {
    2113             :         "metric-type",
    2114             :         ospf6_routemap_rule_set_metric_type,
    2115             :         ospf6_routemap_rule_set_metric_type_compile,
    2116             :         ospf6_routemap_rule_set_metric_type_free,
    2117             : };
    2118             : 
    2119             : static enum route_map_cmd_result_t
    2120           0 : ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
    2121             :                                void *object)
    2122             : {
    2123           0 :         char *metric = rule;
    2124           0 :         struct ospf6_route *route = object;
    2125             : 
    2126           0 :         route->path.cost = atoi(metric);
    2127           0 :         return RMAP_OKAY;
    2128             : }
    2129             : 
    2130           0 : static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
    2131             : {
    2132           0 :         uint32_t metric;
    2133           0 :         char *endp;
    2134           0 :         metric = strtoul(arg, &endp, 0);
    2135           0 :         if (metric > OSPF_LS_INFINITY || *endp != '\0')
    2136             :                 return NULL;
    2137           0 :         return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
    2138             : }
    2139             : 
    2140           0 : static void ospf6_routemap_rule_set_metric_free(void *rule)
    2141             : {
    2142           0 :         XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
    2143           0 : }
    2144             : 
    2145             : static const struct route_map_rule_cmd
    2146             :                 ospf6_routemap_rule_set_metric_cmd = {
    2147             :         "metric",
    2148             :         ospf6_routemap_rule_set_metric,
    2149             :         ospf6_routemap_rule_set_metric_compile,
    2150             :         ospf6_routemap_rule_set_metric_free,
    2151             : };
    2152             : 
    2153             : static enum route_map_cmd_result_t
    2154           0 : ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
    2155             :                                    void *object)
    2156             : {
    2157           0 :         char *forwarding = rule;
    2158           0 :         struct ospf6_route *route = object;
    2159           0 :         struct ospf6_external_info *info = route->route_option;
    2160             : 
    2161           0 :         if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
    2162           0 :                 memset(&info->forwarding, 0, sizeof(struct in6_addr));
    2163           0 :                 return RMAP_ERROR;
    2164             :         }
    2165             : 
    2166             :         return RMAP_OKAY;
    2167             : }
    2168             : 
    2169           0 : static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
    2170             : {
    2171           0 :         struct in6_addr a;
    2172           0 :         if (inet_pton(AF_INET6, arg, &a) != 1)
    2173             :                 return NULL;
    2174           0 :         return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
    2175             : }
    2176             : 
    2177           0 : static void ospf6_routemap_rule_set_forwarding_free(void *rule)
    2178             : {
    2179           0 :         XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
    2180           0 : }
    2181             : 
    2182             : static const struct route_map_rule_cmd
    2183             :                 ospf6_routemap_rule_set_forwarding_cmd = {
    2184             :         "forwarding-address",
    2185             :         ospf6_routemap_rule_set_forwarding,
    2186             :         ospf6_routemap_rule_set_forwarding_compile,
    2187             :         ospf6_routemap_rule_set_forwarding_free,
    2188             : };
    2189             : 
    2190             : static enum route_map_cmd_result_t
    2191           0 : ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object)
    2192             : {
    2193           0 :         route_tag_t *tag = rule;
    2194           0 :         struct ospf6_route *route = object;
    2195           0 :         struct ospf6_external_info *info = route->route_option;
    2196             : 
    2197           0 :         info->tag = *tag;
    2198           0 :         return RMAP_OKAY;
    2199             : }
    2200             : 
    2201             : static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
    2202             :         "tag",
    2203             :         ospf6_routemap_rule_set_tag,
    2204             :         route_map_rule_tag_compile,
    2205             :         route_map_rule_tag_free,
    2206             : };
    2207             : 
    2208             : /* add "set metric-type" */
    2209           0 : DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
    2210             :       "set metric-type <type-1|type-2>",
    2211             :        SET_STR
    2212             :        "Type of metric for destination routing protocol\n"
    2213             :        "OSPF[6] external type 1 metric\n"
    2214             :        "OSPF[6] external type 2 metric\n")
    2215             : {
    2216           0 :         char *ext = argv[2]->text;
    2217             : 
    2218           0 :         const char *xpath =
    2219             :                 "./set-action[action='frr-ospf-route-map:metric-type']";
    2220           0 :         char xpath_value[XPATH_MAXLEN];
    2221             : 
    2222           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    2223           0 :         snprintf(xpath_value, sizeof(xpath_value),
    2224             :                  "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
    2225           0 :         nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
    2226           0 :         return nb_cli_apply_changes(vty, NULL);
    2227             : }
    2228             : 
    2229             : /* delete "set metric-type" */
    2230           0 : DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
    2231             :       "no set metric-type [<type-1|type-2>]",
    2232             :       NO_STR
    2233             :       SET_STR
    2234             :       "Type of metric for destination routing protocol\n"
    2235             :       "OSPF[6] external type 1 metric\n"
    2236             :       "OSPF[6] external type 2 metric\n")
    2237             : {
    2238           0 :         const char *xpath =
    2239             :                 "./set-action[action='frr-ospf-route-map:metric-type']";
    2240             : 
    2241           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    2242           0 :         return nb_cli_apply_changes(vty, NULL);
    2243             : }
    2244             : 
    2245             : /* add "set forwarding-address" */
    2246           0 : DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd,
    2247             :       "set forwarding-address X:X::X:X",
    2248             :       "Set value\n"
    2249             :       "Forwarding Address\n"
    2250             :       "IPv6 Address\n")
    2251             : {
    2252           0 :         int idx_ipv6 = 2;
    2253           0 :         const char *xpath =
    2254             :                 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
    2255           0 :         char xpath_value[XPATH_MAXLEN];
    2256             : 
    2257           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    2258           0 :         snprintf(xpath_value, sizeof(xpath_value),
    2259             :                  "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath);
    2260           0 :         nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
    2261           0 :                               argv[idx_ipv6]->arg);
    2262           0 :         return nb_cli_apply_changes(vty, NULL);
    2263             : }
    2264             : 
    2265             : /* delete "set forwarding-address" */
    2266           0 : DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd,
    2267             :       "no set forwarding-address [X:X::X:X]",
    2268             :       NO_STR
    2269             :       "Set value\n"
    2270             :       "Forwarding Address\n"
    2271             :       "IPv6 Address\n")
    2272             : {
    2273           0 :         const char *xpath =
    2274             :                 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
    2275             : 
    2276           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    2277           0 :         return nb_cli_apply_changes(vty, NULL);
    2278             : }
    2279             : 
    2280           4 : static void ospf6_routemap_init(void)
    2281             : {
    2282           4 :         route_map_init();
    2283             : 
    2284           4 :         route_map_add_hook(ospf6_asbr_routemap_update);
    2285           4 :         route_map_delete_hook(ospf6_asbr_routemap_update);
    2286           4 :         route_map_event_hook(ospf6_asbr_routemap_event);
    2287             : 
    2288           4 :         route_map_set_metric_hook(generic_set_add);
    2289           4 :         route_map_no_set_metric_hook(generic_set_delete);
    2290             : 
    2291           4 :         route_map_set_tag_hook(generic_set_add);
    2292           4 :         route_map_no_set_tag_hook(generic_set_delete);
    2293             : 
    2294           4 :         route_map_match_tag_hook(generic_match_add);
    2295           4 :         route_map_no_match_tag_hook(generic_match_delete);
    2296             : 
    2297           4 :         route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
    2298           4 :         route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
    2299             : 
    2300           4 :         route_map_match_interface_hook(generic_match_add);
    2301           4 :         route_map_no_match_interface_hook(generic_match_delete);
    2302             : 
    2303           4 :         route_map_install_match(
    2304             :                 &ospf6_routemap_rule_match_address_prefixlist_cmd);
    2305           4 :         route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
    2306           4 :         route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
    2307             : 
    2308           4 :         route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
    2309           4 :         route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
    2310           4 :         route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
    2311           4 :         route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
    2312             : 
    2313             :         /* ASE Metric Type (e.g. Type-1/Type-2) */
    2314           4 :         install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
    2315           4 :         install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
    2316             : 
    2317             :         /* ASE Metric */
    2318           4 :         install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
    2319           4 :         install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
    2320           4 : }
    2321             : 
    2322             : 
    2323             : /* Display functions */
    2324           0 : static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
    2325             :                                                   char *buf, int buflen,
    2326             :                                                   int pos)
    2327             : {
    2328           0 :         struct ospf6_as_external_lsa *external;
    2329           0 :         struct in6_addr in6;
    2330           0 :         int prefix_length = 0;
    2331           0 :         char tbuf[16];
    2332             : 
    2333           0 :         if (lsa) {
    2334           0 :                 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
    2335             :                         lsa->header);
    2336             : 
    2337           0 :                 if (pos == 0) {
    2338           0 :                         ospf6_prefix_in6_addr(&in6, external,
    2339           0 :                                               &external->prefix);
    2340           0 :                         prefix_length = external->prefix.prefix_length;
    2341             :                 } else {
    2342           0 :                         in6 = *((struct in6_addr
    2343             :                                          *)((caddr_t)external
    2344             :                                             + sizeof(struct
    2345             :                                                      ospf6_as_external_lsa)
    2346           0 :                                             + OSPF6_PREFIX_SPACE(
    2347             :                                                       external->prefix
    2348             :                                                               .prefix_length)));
    2349             :                 }
    2350           0 :                 if (buf) {
    2351           0 :                         inet_ntop(AF_INET6, &in6, buf, buflen);
    2352           0 :                         if (prefix_length) {
    2353           0 :                                 snprintf(tbuf, sizeof(tbuf), "/%d",
    2354             :                                          prefix_length);
    2355           0 :                                 strlcat(buf, tbuf, buflen);
    2356             :                         }
    2357             :                 }
    2358             :         }
    2359           0 :         return (buf);
    2360             : }
    2361             : 
    2362           0 : static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
    2363             :                                       json_object *json_obj, bool use_json)
    2364             : {
    2365           0 :         struct ospf6_as_external_lsa *external;
    2366           0 :         char buf[64];
    2367             : 
    2368           0 :         assert(lsa->header);
    2369           0 :         external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
    2370             :                 lsa->header);
    2371             : 
    2372             :         /* bits */
    2373           0 :         snprintf(buf, sizeof(buf), "%c%c%c",
    2374           0 :                  (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
    2375             :                                                                       : '-'),
    2376           0 :                  (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
    2377             :                                                                       : '-'),
    2378           0 :                  (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
    2379             :                                                                       : '-'));
    2380             : 
    2381           0 :         if (use_json) {
    2382           0 :                 json_object_string_add(json_obj, "bits", buf);
    2383           0 :                 json_object_int_add(json_obj, "metric",
    2384           0 :                                     (unsigned long)OSPF6_ASBR_METRIC(external));
    2385           0 :                 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
    2386             :                                               buf, sizeof(buf));
    2387           0 :                 json_object_string_add(json_obj, "prefixOptions", buf);
    2388           0 :                 json_object_int_add(
    2389             :                         json_obj, "referenceLsType",
    2390           0 :                         ntohs(external->prefix.prefix_refer_lstype));
    2391           0 :                 json_object_string_add(json_obj, "prefix",
    2392           0 :                                        ospf6_as_external_lsa_get_prefix_str(
    2393             :                                                lsa, buf, sizeof(buf), 0));
    2394             : 
    2395             :                 /* Forwarding-Address */
    2396           0 :                 json_object_boolean_add(
    2397             :                         json_obj, "forwardingAddressPresent",
    2398           0 :                         CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F));
    2399           0 :                 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
    2400           0 :                         json_object_string_add(
    2401             :                                 json_obj, "forwardingAddress",
    2402           0 :                                 ospf6_as_external_lsa_get_prefix_str(
    2403             :                                         lsa, buf, sizeof(buf), 1));
    2404             : 
    2405             :                 /* Tag */
    2406           0 :                 json_object_boolean_add(
    2407             :                         json_obj, "tagPresent",
    2408           0 :                         CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T));
    2409           0 :                 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
    2410           0 :                         json_object_int_add(json_obj, "tag",
    2411           0 :                                             ospf6_as_external_lsa_get_tag(lsa));
    2412             :         } else {
    2413           0 :                 vty_out(vty, "     Bits: %s\n", buf);
    2414           0 :                 vty_out(vty, "     Metric: %5lu\n",
    2415           0 :                         (unsigned long)OSPF6_ASBR_METRIC(external));
    2416             : 
    2417           0 :                 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
    2418             :                                               buf, sizeof(buf));
    2419           0 :                 vty_out(vty, "     Prefix Options: %s\n", buf);
    2420             : 
    2421           0 :                 vty_out(vty, "     Referenced LSType: %d\n",
    2422           0 :                         ntohs(external->prefix.prefix_refer_lstype));
    2423             : 
    2424           0 :                 vty_out(vty, "     Prefix: %s\n",
    2425             :                         ospf6_as_external_lsa_get_prefix_str(lsa, buf,
    2426             :                                                              sizeof(buf), 0));
    2427             : 
    2428             :                 /* Forwarding-Address */
    2429           0 :                 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
    2430           0 :                         vty_out(vty, "     Forwarding-Address: %s\n",
    2431             :                                 ospf6_as_external_lsa_get_prefix_str(
    2432             :                                         lsa, buf, sizeof(buf), 1));
    2433             :                 }
    2434             : 
    2435             :                 /* Tag */
    2436           0 :                 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
    2437           0 :                         vty_out(vty, "     Tag: %" ROUTE_TAG_PRI "\n",
    2438             :                                 ospf6_as_external_lsa_get_tag(lsa));
    2439             :                 }
    2440             :         }
    2441             : 
    2442           0 :         return 0;
    2443             : }
    2444             : 
    2445           0 : static void ospf6_asbr_external_route_show(struct vty *vty,
    2446             :                                            struct ospf6_route *route,
    2447             :                                            json_object *json_array,
    2448             :                                            bool use_json)
    2449             : {
    2450           0 :         struct ospf6_external_info *info = route->route_option;
    2451           0 :         char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
    2452           0 :         uint32_t tmp_id;
    2453           0 :         json_object *json_route;
    2454           0 :         char route_type[2];
    2455             : 
    2456           0 :         prefix2str(&route->prefix, prefix, sizeof(prefix));
    2457           0 :         tmp_id = ntohl(info->id);
    2458           0 :         inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
    2459           0 :         if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
    2460           0 :                 inet_ntop(AF_INET6, &info->forwarding, forwarding,
    2461             :                           sizeof(forwarding));
    2462             :         else
    2463           0 :                 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
    2464             :                          ospf6_route_get_first_nh_index(route));
    2465             : 
    2466           0 :         if (use_json) {
    2467           0 :                 json_route = json_object_new_object();
    2468           0 :                 snprintf(route_type, sizeof(route_type), "%c",
    2469           0 :                          zebra_route_char(info->type));
    2470           0 :                 json_object_string_add(json_route, "routeType", route_type);
    2471           0 :                 json_object_string_add(json_route, "destination", prefix);
    2472           0 :                 json_object_string_add(json_route, "id", id);
    2473           0 :                 json_object_int_add(json_route, "metricType",
    2474           0 :                                     route->path.metric_type);
    2475           0 :                 json_object_int_add(
    2476             :                         json_route, "routeCost",
    2477           0 :                         (unsigned long)(route->path.metric_type == 2
    2478           0 :                                                 ? route->path.u.cost_e2
    2479           0 :                                                 : route->path.cost));
    2480           0 :                 json_object_string_add(json_route, "forwarding", forwarding);
    2481             : 
    2482           0 :                 json_object_array_add(json_array, json_route);
    2483             :         } else
    2484             : 
    2485           0 :                 vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
    2486           0 :                         zebra_route_char(info->type), &route->prefix, id,
    2487             :                         route->path.metric_type,
    2488           0 :                         (unsigned long)(route->path.metric_type == 2
    2489           0 :                                                 ? route->path.u.cost_e2
    2490           0 :                                                 : route->path.cost),
    2491             :                         forwarding);
    2492           0 : }
    2493             : 
    2494           0 : DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
    2495             :       "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
    2496             :       SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
    2497             :       "All VRFs\n"
    2498             :       "redistributing External information\n" JSON_STR)
    2499             : {
    2500           0 :         struct ospf6_route *route;
    2501           0 :         struct ospf6 *ospf6 = NULL;
    2502           0 :         json_object *json = NULL;
    2503           0 :         bool uj = use_json(argc, argv);
    2504           0 :         struct listnode *node;
    2505           0 :         const char *vrf_name = NULL;
    2506           0 :         bool all_vrf = false;
    2507           0 :         int idx_vrf = 0;
    2508             : 
    2509           0 :         json_object *json_array_routes = NULL;
    2510           0 :         json_object *json_array_redistribute = NULL;
    2511             : 
    2512           0 :         OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
    2513             : 
    2514           0 :         if (uj) {
    2515           0 :                 json = json_object_new_object();
    2516           0 :                 json_array_routes = json_object_new_array();
    2517           0 :                 json_array_redistribute = json_object_new_array();
    2518             :         }
    2519             : 
    2520           0 :         for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
    2521           0 :                 if (all_vrf
    2522           0 :                     || ((ospf6->name == NULL && vrf_name == NULL)
    2523           0 :                         || (ospf6->name && vrf_name
    2524           0 :                             && strcmp(ospf6->name, vrf_name) == 0))) {
    2525           0 :                         ospf6_redistribute_show_config(
    2526             :                                 vty, ospf6, json_array_redistribute, json, uj);
    2527             : 
    2528           0 :                         for (route = ospf6_route_head(ospf6->external_table);
    2529           0 :                              route; route = ospf6_route_next(route)) {
    2530           0 :                                 ospf6_asbr_external_route_show(
    2531             :                                         vty, route, json_array_routes, uj);
    2532             :                         }
    2533             : 
    2534           0 :                         if (uj) {
    2535           0 :                                 json_object_object_add(json, "routes",
    2536             :                                                        json_array_routes);
    2537           0 :                                 vty_json(vty, json);
    2538             :                         }
    2539             : 
    2540           0 :                         if (!all_vrf)
    2541             :                                 break;
    2542             :                 }
    2543             :         }
    2544             : 
    2545           0 :         OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6);
    2546             : 
    2547             :         return CMD_SUCCESS;
    2548             : }
    2549             : 
    2550             : static struct ospf6_lsa_handler as_external_handler = {
    2551             :         .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
    2552             :         .lh_name = "AS-External",
    2553             :         .lh_short_name = "ASE",
    2554             :         .lh_show = ospf6_as_external_lsa_show,
    2555             :         .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
    2556             :         .lh_debug = 0};
    2557             : 
    2558             : static struct ospf6_lsa_handler nssa_external_handler = {
    2559             :         .lh_type = OSPF6_LSTYPE_TYPE_7,
    2560             :         .lh_name = "NSSA",
    2561             :         .lh_short_name = "Type7",
    2562             :         .lh_show = ospf6_as_external_lsa_show,
    2563             :         .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
    2564             :         .lh_debug = 0};
    2565             : 
    2566           4 : void ospf6_asbr_init(void)
    2567             : {
    2568           4 :         ospf6_routemap_init();
    2569             : 
    2570           4 :         ospf6_install_lsa_handler(&as_external_handler);
    2571           4 :         ospf6_install_lsa_handler(&nssa_external_handler);
    2572             : 
    2573           4 :         install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
    2574             : 
    2575           4 :         install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd);
    2576           4 :         install_element(OSPF6_NODE,
    2577             :                         &no_ospf6_default_information_originate_cmd);
    2578           4 :         install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
    2579           4 :         install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
    2580           4 : }
    2581             : 
    2582           4 : void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6)
    2583             : {
    2584           4 :         int type;
    2585           4 :         struct ospf6_redist *red;
    2586             : 
    2587         128 :         for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
    2588         124 :                 red = ospf6_redist_lookup(ospf6, type, 0);
    2589         124 :                 if (!red)
    2590         120 :                         continue;
    2591           4 :                 if (type == ZEBRA_ROUTE_OSPF6)
    2592           0 :                         continue;
    2593           4 :                 ospf6_asbr_redistribute_unset(ospf6, red, type);
    2594           4 :                 ospf6_redist_del(ospf6, red, type);
    2595             :         }
    2596           4 :         red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
    2597           4 :         if (red) {
    2598           0 :                 ospf6_asbr_routemap_unset(red);
    2599           0 :                 ospf6_redist_del(ospf6, red, type);
    2600           0 :                 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
    2601             :         }
    2602           4 : }
    2603             : 
    2604           4 : void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
    2605             : {
    2606           4 :         int type;
    2607           4 :         struct ospf6_redist *red;
    2608           4 :         char buf[RMAP_NAME_MAXLEN];
    2609             : 
    2610         132 :         for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
    2611         128 :                 buf[0] = '\0';
    2612         128 :                 if (type == ZEBRA_ROUTE_OSPF6)
    2613           4 :                         continue;
    2614         124 :                 red = ospf6_redist_lookup(ospf6, type, 0);
    2615         124 :                 if (!red)
    2616         124 :                         continue;
    2617             : 
    2618           0 :                 if (type == DEFAULT_ROUTE) {
    2619           0 :                         ospf6_redistribute_default_set(
    2620             :                                 ospf6, ospf6->default_originate);
    2621           0 :                         continue;
    2622             :                 }
    2623           0 :                 if (ROUTEMAP_NAME(red))
    2624           0 :                         strlcpy(buf, ROUTEMAP_NAME(red), sizeof(buf));
    2625             : 
    2626           0 :                 ospf6_asbr_redistribute_unset(ospf6, red, type);
    2627           0 :                 if (buf[0])
    2628           0 :                         ospf6_asbr_routemap_set(red, buf);
    2629           0 :                 ospf6_asbr_redistribute_set(ospf6, type);
    2630             :         }
    2631           4 : }
    2632             : 
    2633           4 : void ospf6_asbr_terminate(void)
    2634             : {
    2635             :         /* Cleanup route maps */
    2636           4 :         route_map_finish();
    2637           4 : }
    2638             : 
    2639           0 : DEFUN (debug_ospf6_asbr,
    2640             :        debug_ospf6_asbr_cmd,
    2641             :        "debug ospf6 asbr",
    2642             :        DEBUG_STR
    2643             :        OSPF6_STR
    2644             :        "Debug OSPFv3 ASBR function\n"
    2645             :       )
    2646             : {
    2647           0 :         OSPF6_DEBUG_ASBR_ON();
    2648           0 :         return CMD_SUCCESS;
    2649             : }
    2650             : 
    2651           0 : DEFUN (no_debug_ospf6_asbr,
    2652             :        no_debug_ospf6_asbr_cmd,
    2653             :        "no debug ospf6 asbr",
    2654             :        NO_STR
    2655             :        DEBUG_STR
    2656             :        OSPF6_STR
    2657             :        "Debug OSPFv3 ASBR function\n"
    2658             :       )
    2659             : {
    2660           0 :         OSPF6_DEBUG_ASBR_OFF();
    2661           0 :         return CMD_SUCCESS;
    2662             : }
    2663             : 
    2664           0 : int config_write_ospf6_debug_asbr(struct vty *vty)
    2665             : {
    2666           0 :         if (IS_OSPF6_DEBUG_ASBR)
    2667           0 :                 vty_out(vty, "debug ospf6 asbr\n");
    2668           0 :         return 0;
    2669             : }
    2670             : 
    2671           0 : static void ospf6_default_originate_write(struct vty *vty, struct ospf6 *o)
    2672             : {
    2673           0 :         struct ospf6_redist *red;
    2674             : 
    2675           0 :         vty_out(vty, " default-information originate");
    2676           0 :         if (o->default_originate == DEFAULT_ORIGINATE_ALWAYS)
    2677           0 :                 vty_out(vty, " always");
    2678             : 
    2679           0 :         red = ospf6_redist_lookup(o, DEFAULT_ROUTE, 0);
    2680           0 :         if (red == NULL) {
    2681           0 :                 vty_out(vty, "\n");
    2682           0 :                 return;
    2683             :         }
    2684             : 
    2685           0 :         if (red->dmetric.value >= 0)
    2686           0 :                 vty_out(vty, " metric %d", red->dmetric.value);
    2687             : 
    2688           0 :         if (red->dmetric.type >= 0)
    2689           0 :                 vty_out(vty, " metric-type %d", red->dmetric.type);
    2690             : 
    2691           0 :         if (ROUTEMAP_NAME(red))
    2692           0 :                 vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
    2693             : 
    2694           0 :         vty_out(vty, "\n");
    2695             : }
    2696             : 
    2697           0 : int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *o)
    2698             : {
    2699           0 :         if (o == NULL)
    2700             :                 return 0;
    2701             : 
    2702             :         /* Print default originate configuration. */
    2703           0 :         if (o->default_originate != DEFAULT_ORIGINATE_NONE)
    2704           0 :                 ospf6_default_originate_write(vty, o);
    2705             : 
    2706             :         return 0;
    2707             : }
    2708             : 
    2709           4 : void install_element_ospf6_debug_asbr(void)
    2710             : {
    2711           4 :         install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
    2712           4 :         install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
    2713           4 :         install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
    2714           4 :         install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
    2715           4 : }
    2716             : 
    2717             : /* ASBR Summarisation */
    2718           0 : void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
    2719             :                                    struct ospf6_external_aggr_rt *aggr)
    2720             : {
    2721           0 :         struct ospf6_route *rt_aggr = aggr->route;
    2722           0 :         struct ospf6_external_info *ei_aggr = rt_aggr->route_option;
    2723             : 
    2724           0 :         rt_aggr->prefix = aggr->p;
    2725           0 :         ei_aggr->tag = aggr->tag;
    2726           0 :         ei_aggr->type = 0;
    2727           0 :         ei_aggr->id = aggr->id;
    2728             : 
    2729             :         /* When metric is not configured, apply the default metric */
    2730           0 :         rt_aggr->path.cost = ((aggr->metric == -1) ?
    2731             :                                 DEFAULT_DEFAULT_METRIC
    2732           0 :                                 : (unsigned int)(aggr->metric));
    2733           0 :         rt_aggr->path.metric_type = aggr->mtype;
    2734             : 
    2735           0 :         rt_aggr->path.origin.id = htonl(aggr->id);
    2736           0 : }
    2737             : 
    2738             : static void
    2739           0 : ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
    2740             :                                            struct ospf6_external_aggr_rt *aggr)
    2741             : {
    2742           0 :         struct ospf6_route *rt_aggr;
    2743           0 :         struct ospf6_route *old_rt = NULL;
    2744           0 :         struct ospf6_external_info *info;
    2745             : 
    2746             :         /* Check if a route is already present. */
    2747           0 :         if (aggr->route)
    2748             :                 old_rt = aggr->route;
    2749             : 
    2750             :         /* Create summary route and save it. */
    2751           0 :         rt_aggr = ospf6_route_create(ospf6);
    2752           0 :         rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
    2753             :         /* Needed to install route while calling zebra api */
    2754           0 :         SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST);
    2755             : 
    2756           0 :         info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info));
    2757           0 :         rt_aggr->route_option = info;
    2758           0 :         aggr->route = rt_aggr;
    2759             : 
    2760             :         /* Prepare the external_info for aggregator
    2761             :          * Fill all the details which will get advertised
    2762             :          */
    2763           0 :         ospf6_fill_aggr_route_details(ospf6, aggr);
    2764             : 
    2765             :         /* Add next-hop to Null interface. */
    2766           0 :         ospf6_add_route_nexthop_blackhole(rt_aggr);
    2767             : 
    2768             :         /* Free the old route, if any. */
    2769           0 :         if (old_rt) {
    2770           0 :                 ospf6_zebra_route_update_remove(old_rt, ospf6);
    2771             : 
    2772           0 :                 if (old_rt->route_option)
    2773           0 :                         XFREE(MTYPE_OSPF6_EXTERNAL_INFO, old_rt->route_option);
    2774             : 
    2775           0 :                 ospf6_route_delete(old_rt);
    2776             :         }
    2777             : 
    2778           0 :         ospf6_zebra_route_update_add(rt_aggr, ospf6);
    2779           0 : }
    2780             : 
    2781           0 : static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6,
    2782             :                                          struct ospf6_external_aggr_rt *aggr)
    2783             : {
    2784           0 :         struct prefix prefix_id;
    2785           0 :         struct ospf6_lsa *lsa = NULL;
    2786             : 
    2787           0 :         if (IS_OSPF6_DEBUG_AGGR)
    2788           0 :                 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__,
    2789             :                            &aggr->p);
    2790             : 
    2791           0 :         aggr->id = ospf6->external_id++;
    2792             : 
    2793           0 :         if (IS_OSPF6_DEBUG_AGGR)
    2794           0 :                 zlog_debug(
    2795             :                         "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
    2796             :                         &prefix_id.u.prefix4, &aggr->p, aggr->metric);
    2797             : 
    2798           0 :         ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
    2799             : 
    2800             :         /* Originate summary LSA */
    2801           0 :         lsa = ospf6_originate_type5_type7_lsas(aggr->route, ospf6);
    2802           0 :         if (lsa) {
    2803           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2804           0 :                         zlog_debug("%s: Set the origination bit for aggregator",
    2805             :                                         __func__);
    2806           0 :                 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    2807             :         }
    2808           0 : }
    2809             : 
    2810             : static void
    2811           0 : ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6,
    2812             :                 struct ospf6_external_aggr_rt *aggr)
    2813             : {
    2814             :         /* Check if advertise option modified. */
    2815           0 :         if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
    2816           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2817           0 :                         zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
    2818             :                                         __func__);
    2819           0 :                 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
    2820             : 
    2821           0 :                 return;
    2822             :         }
    2823             : 
    2824             :         /* There are no routes present under this aggregation config, hence
    2825             :          * nothing to originate here
    2826             :          */
    2827           0 :         if (OSPF6_EXTERNAL_RT_COUNT(aggr) == 0) {
    2828           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2829           0 :                         zlog_debug("%s: No routes present under this aggregation",
    2830             :                                         __func__);
    2831           0 :                 return;
    2832             :         }
    2833             : 
    2834           0 :         if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
    2835           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2836           0 :                         zlog_debug("%s: Now it is advertisable",
    2837             :                                         __func__);
    2838             : 
    2839           0 :                 ospf6_originate_new_aggr_lsa(ospf6, aggr);
    2840             : 
    2841           0 :                 return;
    2842             :         }
    2843             : }
    2844             : 
    2845             : static void
    2846           0 : ospf6_originate_summary_lsa(struct ospf6 *ospf6,
    2847             :                             struct ospf6_external_aggr_rt *aggr,
    2848             :                             struct ospf6_route *rt)
    2849             : {
    2850           0 :         struct ospf6_lsa *lsa = NULL, *aggr_lsa = NULL;
    2851           0 :         struct ospf6_external_info *info = NULL;
    2852           0 :         struct ospf6_external_aggr_rt *old_aggr;
    2853           0 :         struct ospf6_as_external_lsa *external;
    2854           0 :         struct ospf6_route *rt_aggr = NULL;
    2855           0 :         route_tag_t tag = 0;
    2856           0 :         unsigned int metric = 0;
    2857           0 :         int mtype;
    2858             : 
    2859           0 :         if (IS_OSPF6_DEBUG_AGGR)
    2860           0 :                 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
    2861             :                            __func__, &aggr->p);
    2862             : 
    2863             :         /* This case to handle when the overlapping aggregator address
    2864             :          * is available. Best match will be considered.So need to delink
    2865             :          * from old aggregator and link to the new aggr.
    2866             :          */
    2867           0 :         if (rt->aggr_route) {
    2868           0 :                 if (rt->aggr_route != aggr) {
    2869           0 :                         old_aggr = rt->aggr_route;
    2870           0 :                         ospf6_unlink_route_from_aggr(ospf6, old_aggr, rt);
    2871             :                 }
    2872             :         }
    2873             : 
    2874             :         /* Add the external route to hash table */
    2875           0 :         ospf6_link_route_to_aggr(aggr, rt);
    2876             : 
    2877             :         /* The key for ID field is a running number and not prefix */
    2878           0 :         info = rt->route_option;
    2879           0 :         assert(info);
    2880           0 :         if (info->id)
    2881           0 :                 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
    2882             :                                         htonl(info->id), ospf6->router_id,
    2883             :                                         ospf6->lsdb);
    2884             : 
    2885           0 :         aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
    2886             :                                 htonl(aggr->id), ospf6->router_id, ospf6->lsdb);
    2887             : 
    2888           0 :         if (IS_OSPF6_DEBUG_AGGR)
    2889           0 :                 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
    2890             :                    __func__, aggr->id, aggr->aggrflags);
    2891             :         /* Don't originate external LSA,
    2892             :          * If it is configured not to advertise.
    2893             :          */
    2894           0 :         if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
    2895             :                 /* If it is already originated as external LSA,
    2896             :                  * But, it is configured not to advertise then
    2897             :                  * flush the originated external lsa.
    2898             :                  */
    2899           0 :                 if (lsa) {
    2900           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    2901           0 :                                 zlog_debug("%s: Purge the external LSA %s.",
    2902             :                                            __func__, lsa->name);
    2903           0 :                         ospf6_external_lsa_purge(ospf6, lsa);
    2904           0 :                         info->id = 0;
    2905           0 :                         rt->path.origin.id = 0;
    2906             :                 }
    2907             : 
    2908           0 :                 if (aggr_lsa) {
    2909           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    2910           0 :                                 zlog_debug("%s: Purge the aggr external LSA %s.",
    2911             :                                            __func__, lsa->name);
    2912           0 :                         ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
    2913             :                 }
    2914             : 
    2915           0 :                 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    2916             : 
    2917           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2918           0 :                         zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
    2919             :                                 __func__);
    2920           0 :                 return;
    2921             :         }
    2922             : 
    2923             :         /* Summary route already originated,
    2924             :          * So, Do nothing.
    2925             :          */
    2926           0 :         if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
    2927           0 :                 if (!aggr_lsa) {
    2928           0 :                         zlog_warn(
    2929             :                                 "%s: Could not refresh/originate %pFX",
    2930             :                                                 __func__,
    2931             :                                                 &aggr->p);
    2932             :                         /* Remove the assert later */
    2933           0 :                         assert(aggr_lsa);
    2934             :                         return;
    2935             :                 }
    2936             : 
    2937           0 :                 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END
    2938             :                                         (aggr_lsa->header);
    2939           0 :                 metric = (unsigned long)OSPF6_ASBR_METRIC(external);
    2940           0 :                 tag = ospf6_as_external_lsa_get_tag(aggr_lsa);
    2941           0 :                 mtype = CHECK_FLAG(external->bits_metric,
    2942           0 :                                    OSPF6_ASBR_BIT_E) ? 2 : 1;
    2943             : 
    2944             :                 /* Prepare the external_info for aggregator */
    2945           0 :                 ospf6_fill_aggr_route_details(ospf6, aggr);
    2946           0 :                 rt_aggr = aggr->route;
    2947             :                 /* If tag/metric/metric-type modified , then re-originate the
    2948             :                  * route with modified tag/metric/metric-type details.
    2949             :                  */
    2950           0 :                 if ((tag != aggr->tag)
    2951           0 :                     || (metric != (unsigned int)rt_aggr->path.cost)
    2952           0 :                     || (mtype != aggr->mtype)) {
    2953             : 
    2954           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    2955           0 :                                 zlog_debug(
    2956             :                                         "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
    2957             :                                         __func__, tag, aggr->tag,
    2958             :                                         metric,
    2959             :                                         aggr->metric,
    2960             :                                         mtype, aggr->mtype,
    2961             :                                         &aggr->p);
    2962             : 
    2963           0 :                         aggr_lsa = ospf6_originate_type5_type7_lsas(aggr->route,
    2964             :                                                                     ospf6);
    2965           0 :                         if (aggr_lsa)
    2966           0 :                                 SET_FLAG(aggr->aggrflags,
    2967             :                                         OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    2968             :                 }
    2969             : 
    2970           0 :                 return;
    2971             :         }
    2972             : 
    2973             :         /* If the external route prefix same as aggregate route
    2974             :          * and if external route is already originated as TYPE-5
    2975             :          * then just update the aggr info and remove the route info
    2976             :          */
    2977           0 :         if (lsa && prefix_same(&aggr->p, &rt->prefix)) {
    2978           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    2979           0 :                         zlog_debug(
    2980             :                                 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
    2981             :                                 __PRETTY_FUNCTION__, &aggr->p);
    2982             : 
    2983           0 :                 aggr->id = info->id;
    2984           0 :                 info->id = 0;
    2985           0 :                 rt->path.origin.id = 0;
    2986             : 
    2987           0 :                 ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
    2988             : 
    2989           0 :                 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    2990             : 
    2991           0 :                 return;
    2992             :         }
    2993             : 
    2994           0 :         ospf6_originate_new_aggr_lsa(ospf6, aggr);
    2995             : }
    2996             : 
    2997           0 : static void ospf6_aggr_handle_external_info(void *data)
    2998             : {
    2999           0 :         struct ospf6_route *rt = (struct ospf6_route *)data;
    3000           0 :         struct ospf6_external_aggr_rt *aggr = NULL;
    3001           0 :         struct ospf6_lsa *lsa = NULL;
    3002           0 :         struct ospf6_external_info *info;
    3003           0 :         struct ospf6 *ospf6 = NULL;
    3004             : 
    3005           0 :         rt->aggr_route = NULL;
    3006             : 
    3007           0 :         rt->to_be_processed = true;
    3008             : 
    3009           0 :         if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
    3010           0 :                 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
    3011             :                                         __func__,
    3012             :                                         &rt->prefix);
    3013             : 
    3014           0 :         ospf6 = rt->ospf6;
    3015           0 :         assert(ospf6);
    3016             : 
    3017           0 :         aggr = ospf6_external_aggr_match(ospf6,
    3018             :                                         &rt->prefix);
    3019           0 :         if (aggr) {
    3020           0 :                 ospf6_originate_summary_lsa(ospf6, aggr, rt);
    3021           0 :                 return;
    3022             :         }
    3023             : 
    3024           0 :         info = rt->route_option;
    3025           0 :         if (info->id) {
    3026           0 :                 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
    3027             :                                         htonl(info->id), ospf6->router_id,
    3028             :                                         ospf6->lsdb);
    3029           0 :                 if (lsa) {
    3030           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    3031           0 :                                 zlog_debug("%s: LSA found, refresh it",
    3032             :                                            __func__);
    3033           0 :                         THREAD_OFF(lsa->refresh);
    3034           0 :                         thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
    3035             :                                          &lsa->refresh);
    3036           0 :                         return;
    3037             :                 }
    3038             :         }
    3039             : 
    3040           0 :         info->id  = ospf6->external_id++;
    3041           0 :         rt->path.origin.id = htonl(info->id);
    3042             : 
    3043           0 :         (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
    3044             : }
    3045             : 
    3046           0 : void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
    3047             :                                       struct route_node *rn)
    3048             : {
    3049           0 :         struct ospf6_external_aggr_rt *aggr = rn->info;
    3050             : 
    3051           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3052           0 :                 zlog_debug("%s: Deleting Aggregate route (%pFX)",
    3053             :                                                 __func__,
    3054             :                                                 &aggr->p);
    3055             : 
    3056           0 :         ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
    3057             : 
    3058           0 :         rn->info = NULL;
    3059           0 :         route_unlock_node(rn);
    3060           0 : }
    3061             : 
    3062             : static int
    3063           0 : ospf6_handle_external_aggr_modify(struct ospf6 *ospf6,
    3064             :                                   struct ospf6_external_aggr_rt *aggr)
    3065             : {
    3066           0 :         struct ospf6_lsa *lsa = NULL;
    3067           0 :         struct ospf6_as_external_lsa *asel = NULL;
    3068           0 :         struct ospf6_route *rt_aggr;
    3069           0 :         unsigned int metric = 0;
    3070           0 :         route_tag_t tag = 0;
    3071           0 :         int mtype;
    3072             : 
    3073           0 :         lsa = ospf6_lsdb_lookup(
    3074           0 :                 htons(OSPF6_LSTYPE_AS_EXTERNAL),
    3075             :                 htonl(aggr->id), ospf6->router_id,
    3076             :                 ospf6->lsdb);
    3077           0 :         if (!lsa) {
    3078           0 :                 zlog_warn(
    3079             :                         "%s: Could not refresh/originate %pFX",
    3080             :                         __func__,
    3081             :                         &aggr->p);
    3082             : 
    3083           0 :                 return OSPF6_FAILURE;
    3084             :         }
    3085             : 
    3086           0 :         asel = (struct ospf6_as_external_lsa *)
    3087           0 :                 OSPF6_LSA_HEADER_END(lsa->header);
    3088           0 :         metric = (unsigned long)OSPF6_ASBR_METRIC(asel);
    3089           0 :         tag = ospf6_as_external_lsa_get_tag(lsa);
    3090           0 :         mtype = CHECK_FLAG(asel->bits_metric,
    3091           0 :                            OSPF6_ASBR_BIT_E) ? 2 : 1;
    3092             : 
    3093             :         /* Fill all the details for advertisement */
    3094           0 :         ospf6_fill_aggr_route_details(ospf6, aggr);
    3095           0 :         rt_aggr = aggr->route;
    3096             :         /* If tag/metric/metric-type modified , then
    3097             :          * re-originate the route with modified
    3098             :          * tag/metric/metric-type details.
    3099             :          */
    3100           0 :         if ((tag != aggr->tag)
    3101           0 :             || (metric
    3102           0 :                 != (unsigned int)rt_aggr->path.cost)
    3103           0 :             || (mtype
    3104           0 :                 != aggr->mtype)) {
    3105           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    3106           0 :                         zlog_debug(
    3107             :                         "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
    3108             :                         __func__, tag,
    3109             :                         aggr->tag,
    3110             :                         metric,
    3111             :                         (unsigned int)rt_aggr->path.cost,
    3112             :                         mtype, aggr->mtype,
    3113             :                         &aggr->p);
    3114             : 
    3115           0 :                 (void)ospf6_originate_type5_type7_lsas(
    3116             :                                         aggr->route,
    3117             :                                         ospf6);
    3118             :         }
    3119             : 
    3120             :         return OSPF6_SUCCESS;
    3121             : }
    3122             : 
    3123           0 : static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6)
    3124             : {
    3125           0 :         struct route_node *rn = NULL;
    3126           0 :         int ret;
    3127             : 
    3128           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3129           0 :                 zlog_debug("%s: Process modified aggregators.", __func__);
    3130             : 
    3131           0 :         for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
    3132           0 :                 struct ospf6_external_aggr_rt *aggr;
    3133             : 
    3134           0 :                 if (!rn->info)
    3135           0 :                         continue;
    3136             : 
    3137           0 :                 aggr = rn->info;
    3138             : 
    3139           0 :                 if (aggr->action == OSPF6_ROUTE_AGGR_DEL) {
    3140           0 :                         aggr->action = OSPF6_ROUTE_AGGR_NONE;
    3141           0 :                         ospf6_asbr_summary_config_delete(ospf6, rn);
    3142             : 
    3143           0 :                         if (OSPF6_EXTERNAL_RT_COUNT(aggr))
    3144           0 :                                 hash_clean(aggr->match_extnl_hash,
    3145             :                                 ospf6_aggr_handle_external_info);
    3146             : 
    3147           0 :                         hash_free(aggr->match_extnl_hash);
    3148           0 :                         XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
    3149             : 
    3150           0 :                 } else if (aggr->action == OSPF6_ROUTE_AGGR_MODIFY) {
    3151             : 
    3152           0 :                         aggr->action = OSPF6_ROUTE_AGGR_NONE;
    3153             : 
    3154             :                         /* Check if tag/metric/metric-type modified */
    3155           0 :                         if (CHECK_FLAG(aggr->aggrflags,
    3156             :                                 OSPF6_EXTERNAL_AGGRT_ORIGINATED)
    3157             :                             && !CHECK_FLAG(aggr->aggrflags,
    3158             :                                 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
    3159             : 
    3160           0 :                                 ret = ospf6_handle_external_aggr_modify(ospf6,
    3161             :                                                                         aggr);
    3162           0 :                                 if (ret == OSPF6_FAILURE)
    3163           0 :                                         continue;
    3164             :                         }
    3165             : 
    3166             :                         /* Advertise option modified ?
    3167             :                          * If so, handled it here.
    3168             :                          */
    3169           0 :                         ospf6_aggr_handle_advertise_change(ospf6, aggr);
    3170             :                 }
    3171             :         }
    3172           0 : }
    3173             : 
    3174           0 : static void ospf6_aggr_unlink_external_info(void *data)
    3175             : {
    3176           0 :         struct ospf6_route *rt = (struct ospf6_route *)data;
    3177             : 
    3178           0 :         rt->aggr_route = NULL;
    3179             : 
    3180           0 :         rt->to_be_processed = true;
    3181           0 : }
    3182             : 
    3183           0 : void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
    3184             : {
    3185           0 :         if (OSPF6_EXTERNAL_RT_COUNT(aggr))
    3186           0 :                 hash_clean(aggr->match_extnl_hash,
    3187             :                         ospf6_aggr_unlink_external_info);
    3188             : 
    3189           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3190           0 :                 zlog_debug("%s: Release the aggregator Address(%pFX)",
    3191             :                                                 __func__,
    3192             :                                                 &aggr->p);
    3193             : 
    3194           0 :         hash_free(aggr->match_extnl_hash);
    3195           0 :         aggr->match_extnl_hash = NULL;
    3196             : 
    3197           0 :         XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
    3198           0 : }
    3199             : 
    3200             : static void
    3201           0 : ospf6_delete_all_marked_aggregators(struct ospf6 *ospf6)
    3202             : {
    3203           0 :         struct route_node *rn = NULL;
    3204           0 :         struct ospf6_external_aggr_rt *aggr;
    3205             : 
    3206             :         /* Loop through all the aggregators, Delete all aggregators
    3207             :          * which are marked as DELETE. Set action to NONE for remaining
    3208             :          * aggregators
    3209             :          */
    3210           0 :         for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
    3211           0 :                 if (!rn->info)
    3212           0 :                         continue;
    3213             : 
    3214           0 :                 aggr = rn->info;
    3215             : 
    3216           0 :                 if (aggr->action != OSPF6_ROUTE_AGGR_DEL) {
    3217           0 :                         aggr->action = OSPF6_ROUTE_AGGR_NONE;
    3218           0 :                         continue;
    3219             :                 }
    3220           0 :                 ospf6_asbr_summary_config_delete(ospf6, rn);
    3221           0 :                 ospf6_external_aggregator_free(aggr);
    3222             :         }
    3223           0 : }
    3224             : 
    3225           0 : static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6 *ospf6,
    3226             :                                                struct ospf6_route *rt)
    3227             : {
    3228           0 :         struct ospf6_lsa *lsa;
    3229             : 
    3230             :         /* Process only marked external routes.
    3231             :          * These routes were part of a deleted
    3232             :          * aggregator.So, originate now.
    3233             :          */
    3234           0 :         if (!rt->to_be_processed)
    3235             :                 return;
    3236             : 
    3237           0 :         rt->to_be_processed = false;
    3238             : 
    3239           0 :         lsa = ospf6_find_external_lsa(ospf6, &rt->prefix);
    3240             : 
    3241           0 :         if (lsa) {
    3242           0 :                 THREAD_OFF(lsa->refresh);
    3243           0 :                 thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
    3244             :                                  &lsa->refresh);
    3245             :         } else {
    3246           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    3247           0 :                         zlog_debug("%s: Originate external route(%pFX)",
    3248             :                                 __func__,
    3249             :                                 &rt->prefix);
    3250             : 
    3251           0 :                 (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
    3252             :         }
    3253             : }
    3254             : 
    3255           0 : static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6,
    3256             :                                            struct ospf6_external_aggr_rt *aggr,
    3257             :                                            struct ospf6_route *rt)
    3258             : {
    3259           0 :         struct ospf6_lsa *lsa;
    3260           0 :         struct ospf6_as_external_lsa *ext_lsa;
    3261           0 :         struct ospf6_external_info *info;
    3262             : 
    3263             :         /* Handling the case where the external route prefix
    3264             :          * and aggegate prefix is same
    3265             :          * If same don't flush the originated external LSA.
    3266             :          */
    3267           0 :         if (prefix_same(&aggr->p, &rt->prefix)) {
    3268           0 :                 if (IS_OSPF6_DEBUG_AGGR)
    3269           0 :                         zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
    3270             :                                 __func__,
    3271             :                                 &rt->prefix);
    3272             : 
    3273           0 :                 return;
    3274             :         }
    3275             : 
    3276           0 :         info = rt->route_option;
    3277           0 :         assert(info);
    3278             : 
    3279           0 :         lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
    3280             :                                 htonl(info->id), ospf6->router_id, ospf6->lsdb);
    3281           0 :         if (lsa) {
    3282           0 :                 ext_lsa = (struct ospf6_as_external_lsa
    3283           0 :                         *)((char *)(lsa->header)
    3284             :                         + sizeof(struct ospf6_lsa_header));
    3285             : 
    3286           0 :                 if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length)
    3287             :                         return;
    3288             : 
    3289           0 :                 ospf6_external_lsa_purge(ospf6, lsa);
    3290             : 
    3291             :                 /* Resetting the ID of route */
    3292           0 :                 rt->path.origin.id = 0;
    3293           0 :                 info->id = 0;
    3294             :         }
    3295             : }
    3296             : 
    3297             : static void
    3298           0 : ospf6_handle_external_aggr_add(struct ospf6 *ospf6)
    3299             : {
    3300           0 :         struct ospf6_route *rt = NULL;
    3301           0 :         struct ospf6_external_info *ei = NULL;
    3302           0 :         struct ospf6_external_aggr_rt *aggr;
    3303             : 
    3304             :         /* Delete all the aggregators which are marked as
    3305             :          * OSPF6_ROUTE_AGGR_DEL.
    3306             :          */
    3307           0 :         ospf6_delete_all_marked_aggregators(ospf6);
    3308             : 
    3309           0 :         for (rt = ospf6_route_head(ospf6->external_table); rt;
    3310           0 :                 rt = ospf6_route_next(rt)) {
    3311           0 :                 ei = rt->route_option;
    3312           0 :                 if (ei == NULL)
    3313           0 :                         continue;
    3314             : 
    3315           0 :                 if (is_default_prefix(&rt->prefix))
    3316           0 :                         continue;
    3317             : 
    3318           0 :                 aggr = ospf6_external_aggr_match(ospf6,
    3319             :                                         &rt->prefix);
    3320             : 
    3321             :                 /* If matching aggregator found, Add
    3322             :                  * the external route refrenace to the
    3323             :                  * aggregator and originate the aggr
    3324             :                  * route if it is advertisable.
    3325             :                  * flush the external LSA if it is
    3326             :                  * already originated for this external
    3327             :                  * prefix.
    3328             :                  */
    3329           0 :                 if (aggr) {
    3330           0 :                         ospf6_originate_summary_lsa(ospf6, aggr, rt);
    3331             : 
    3332             :                         /* All aggregated external rts
    3333             :                          * are handled here.
    3334             :                          */
    3335           0 :                         ospf6_handle_aggregated_exnl_rt(
    3336             :                                 ospf6, aggr, rt);
    3337           0 :                         continue;
    3338             :                 }
    3339             : 
    3340             :                 /* External routes which are only out
    3341             :                  * of aggregation will be handled here.
    3342             :                  */
    3343           0 :                 ospf6_handle_exnl_rt_after_aggr_del(
    3344             :                                         ospf6, rt);
    3345             :         }
    3346           0 : }
    3347             : 
    3348           0 : static void ospf6_asbr_summary_process(struct thread *thread)
    3349             : {
    3350           0 :         struct ospf6 *ospf6 = THREAD_ARG(thread);
    3351           0 :         int operation = 0;
    3352             : 
    3353           0 :         operation = ospf6->aggr_action;
    3354             : 
    3355           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3356           0 :                 zlog_debug("%s: operation:%d",
    3357             :                                 __func__,
    3358             :                                 operation);
    3359             : 
    3360           0 :         switch (operation) {
    3361           0 :         case OSPF6_ROUTE_AGGR_ADD:
    3362           0 :                 ospf6_handle_external_aggr_add(ospf6);
    3363           0 :                 break;
    3364           0 :         case OSPF6_ROUTE_AGGR_DEL:
    3365             :         case OSPF6_ROUTE_AGGR_MODIFY:
    3366           0 :                 ospf6_handle_external_aggr_update(ospf6);
    3367           0 :                 break;
    3368             :         default:
    3369             :                 break;
    3370             :         }
    3371           0 : }
    3372             : 
    3373             : static void
    3374           0 : ospf6_start_asbr_summary_delay_timer(struct ospf6 *ospf6,
    3375             :                         struct ospf6_external_aggr_rt *aggr,
    3376             :                         ospf6_aggr_action_t operation)
    3377             : {
    3378           0 :         aggr->action = operation;
    3379             : 
    3380           0 :         if (thread_is_scheduled(ospf6->t_external_aggr)) {
    3381           0 :                 if (ospf6->aggr_action == OSPF6_ROUTE_AGGR_ADD) {
    3382             : 
    3383           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    3384           0 :                                 zlog_debug("%s: Not required to restart timer,set is already added.",
    3385             :                                         __func__);
    3386           0 :                         return;
    3387             :                 }
    3388             : 
    3389           0 :                 if (operation == OSPF6_ROUTE_AGGR_ADD) {
    3390           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    3391           0 :                                 zlog_debug("%s, Restarting Aggregator delay timer.",
    3392             :                                                         __func__);
    3393           0 :                         THREAD_OFF(ospf6->t_external_aggr);
    3394             :                 }
    3395             :         }
    3396             : 
    3397           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3398           0 :                 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
    3399             :                            __func__, ospf6->aggr_delay_interval);
    3400             : 
    3401           0 :         ospf6->aggr_action = operation;
    3402           0 :         thread_add_timer(master,
    3403             :                         ospf6_asbr_summary_process,
    3404             :                         ospf6, ospf6->aggr_delay_interval,
    3405             :                         &ospf6->t_external_aggr);
    3406             : }
    3407             : 
    3408           0 : int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
    3409             :                                 struct prefix *p)
    3410             : {
    3411           0 :         struct route_node *rn;
    3412           0 :         struct ospf6_external_aggr_rt *aggr;
    3413             : 
    3414           0 :         rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
    3415           0 :         if (!rn)
    3416             :                 return OSPF6_INVALID;
    3417             : 
    3418           0 :         aggr = rn->info;
    3419             : 
    3420           0 :         route_unlock_node(rn);
    3421             : 
    3422           0 :         if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
    3423             :                 return OSPF6_INVALID;
    3424             : 
    3425           0 :         UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
    3426             : 
    3427           0 :         if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
    3428             :                 return OSPF6_SUCCESS;
    3429             : 
    3430           0 :         ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
    3431             :                                              OSPF6_ROUTE_AGGR_MODIFY);
    3432             : 
    3433           0 :         return OSPF6_SUCCESS;
    3434             : }
    3435             : 
    3436           0 : int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6, uint16_t interval)
    3437             : {
    3438           0 :         ospf6->aggr_delay_interval = interval;
    3439             : 
    3440           0 :         return OSPF6_SUCCESS;
    3441             : }
    3442             : 
    3443           0 : static unsigned int ospf6_external_rt_hash_key(const void *data)
    3444             : {
    3445           0 :         const struct ospf6_route *rt = data;
    3446           0 :         unsigned int key = 0;
    3447             : 
    3448           0 :         key = prefix_hash_key(&rt->prefix);
    3449           0 :         return key;
    3450             : }
    3451             : 
    3452           0 : static bool ospf6_external_rt_hash_cmp(const void *d1, const void *d2)
    3453             : {
    3454           0 :         const struct ospf6_route *rt1 = d1;
    3455           0 :         const struct ospf6_route *rt2 = d2;
    3456             : 
    3457           0 :         return prefix_same(&rt1->prefix, &rt2->prefix);
    3458             : }
    3459             : 
    3460             : static struct ospf6_external_aggr_rt *
    3461           0 : ospf6_external_aggr_new(struct prefix *p)
    3462             : {
    3463           0 :         struct ospf6_external_aggr_rt *aggr;
    3464             : 
    3465           0 :         aggr = XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR,
    3466             :                        sizeof(struct ospf6_external_aggr_rt));
    3467             : 
    3468           0 :         prefix_copy(&aggr->p, p);
    3469           0 :         aggr->metric = -1;
    3470           0 :         aggr->mtype = DEFAULT_METRIC_TYPE;
    3471           0 :         aggr->match_extnl_hash = hash_create(ospf6_external_rt_hash_key,
    3472             :                                              ospf6_external_rt_hash_cmp,
    3473             :                                              "Ospf6 external route hash");
    3474           0 :         return aggr;
    3475             : }
    3476             : 
    3477           0 : static void ospf6_external_aggr_add(struct ospf6 *ospf6,
    3478             :                 struct ospf6_external_aggr_rt *aggr)
    3479             : {
    3480           0 :         struct route_node *rn;
    3481             : 
    3482           0 :         if (IS_OSPF6_DEBUG_AGGR)
    3483           0 :                 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
    3484             :                                         __func__,
    3485             :                                         &aggr->p);
    3486             : 
    3487           0 :         rn = route_node_get(ospf6->rt_aggr_tbl, &aggr->p);
    3488           0 :         if (rn->info)
    3489           0 :                 route_unlock_node(rn);
    3490             :         else
    3491           0 :                 rn->info = aggr;
    3492           0 : }
    3493             : 
    3494           0 : int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
    3495             :                                 struct prefix *p)
    3496             : {
    3497           0 :         struct ospf6_external_aggr_rt *aggr;
    3498           0 :         route_tag_t tag = 0;
    3499             : 
    3500           0 :         aggr = ospf6_external_aggr_config_lookup(ospf6, p);
    3501           0 :         if (aggr) {
    3502           0 :                 if (CHECK_FLAG(aggr->aggrflags,
    3503             :                         OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
    3504             :                         return OSPF6_SUCCESS;
    3505             : 
    3506           0 :                 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
    3507             : 
    3508           0 :                 aggr->tag = tag;
    3509           0 :                 aggr->metric = -1;
    3510             : 
    3511           0 :                 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
    3512             :                         return OSPF6_SUCCESS;
    3513             : 
    3514           0 :                 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
    3515             :                         OSPF6_ROUTE_AGGR_MODIFY);
    3516             :         } else {
    3517           0 :                 aggr = ospf6_external_aggr_new(p);
    3518             : 
    3519           0 :                 if (!aggr)
    3520             :                         return OSPF6_FAILURE;
    3521             : 
    3522           0 :                 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
    3523           0 :                 ospf6_external_aggr_add(ospf6, aggr);
    3524           0 :                 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
    3525             :                                         OSPF6_ROUTE_AGGR_ADD);
    3526             :         }
    3527             : 
    3528             :         return OSPF6_SUCCESS;
    3529             : }
    3530             : 
    3531             : struct ospf6_external_aggr_rt *
    3532           0 : ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p)
    3533             : {
    3534           0 :         struct route_node *rn;
    3535             : 
    3536           0 :         rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
    3537           0 :         if (rn) {
    3538           0 :                 route_unlock_node(rn);
    3539           0 :                 return rn->info;
    3540             :         }
    3541             : 
    3542             :         return NULL;
    3543             : }
    3544             : 
    3545             : 
    3546           0 : int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
    3547             :                                       route_tag_t tag, int metric, int mtype)
    3548             : {
    3549           0 :         struct ospf6_external_aggr_rt *aggregator;
    3550             : 
    3551           0 :         aggregator = ospf6_external_aggr_config_lookup(ospf6, p);
    3552             : 
    3553           0 :         if (aggregator) {
    3554           0 :                 if (CHECK_FLAG(aggregator->aggrflags,
    3555             :                                OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
    3556           0 :                         UNSET_FLAG(aggregator->aggrflags,
    3557             :                                    OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
    3558           0 :                 else if ((aggregator->tag == tag)
    3559           0 :                          && (aggregator->metric == metric)
    3560           0 :                          && (aggregator->mtype == mtype))
    3561             :                         return OSPF6_SUCCESS;
    3562             : 
    3563           0 :                 aggregator->tag = tag;
    3564           0 :                 aggregator->metric = metric;
    3565           0 :                 aggregator->mtype = mtype;
    3566             : 
    3567           0 :                 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
    3568             :                                          OSPF6_ROUTE_AGGR_MODIFY);
    3569             :         } else {
    3570           0 :                 aggregator = ospf6_external_aggr_new(p);
    3571           0 :                 if (!aggregator)
    3572             :                         return OSPF6_FAILURE;
    3573             : 
    3574           0 :                 aggregator->tag = tag;
    3575           0 :                 aggregator->metric = metric;
    3576           0 :                 aggregator->mtype = mtype;
    3577             : 
    3578           0 :                 ospf6_external_aggr_add(ospf6, aggregator);
    3579           0 :                 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
    3580             :                                                 OSPF6_ROUTE_AGGR_ADD);
    3581             :         }
    3582             : 
    3583             :         return OSPF6_SUCCESS;
    3584             : }
    3585             : 
    3586           0 : int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
    3587             :                                         struct prefix *p)
    3588             : {
    3589           0 :         struct route_node *rn;
    3590           0 :         struct ospf6_external_aggr_rt *aggr;
    3591             : 
    3592           0 :         rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
    3593           0 :         if (!rn)
    3594             :                 return OSPF6_INVALID;
    3595             : 
    3596           0 :         aggr = rn->info;
    3597             : 
    3598           0 :         route_unlock_node(rn);
    3599             : 
    3600           0 :         if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) {
    3601           0 :                 ospf6_asbr_summary_config_delete(ospf6, rn);
    3602           0 :                 ospf6_external_aggregator_free(aggr);
    3603           0 :                 return OSPF6_SUCCESS;
    3604             :         }
    3605             : 
    3606           0 :         ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
    3607             :                                 OSPF6_ROUTE_AGGR_DEL);
    3608             : 
    3609           0 :         return OSPF6_SUCCESS;
    3610             : }
    3611             : 
    3612          53 : void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
    3613             :                                                struct ospf6_route *rt,
    3614             :                                                struct prefix *p)
    3615             : {
    3616             : 
    3617          53 :         struct ospf6_external_aggr_rt *aggr;
    3618          53 :         struct ospf6_external_info *info;
    3619          53 :         struct prefix prefix_id;
    3620             : 
    3621          53 :         if (!is_default_prefix(p)) {
    3622          53 :                 aggr = ospf6_external_aggr_match(ospf6,
    3623             :                                                 p);
    3624             : 
    3625          53 :                 if (aggr) {
    3626             : 
    3627           0 :                         if (IS_OSPF6_DEBUG_AGGR)
    3628           0 :                                 zlog_debug("%s: Send Aggregate LSA (%pFX)",
    3629             :                                 __func__,
    3630             :                                 &aggr->p);
    3631             : 
    3632           0 :                         ospf6_originate_summary_lsa(
    3633             :                                 ospf6, aggr, rt);
    3634             : 
    3635             :                         /* Handling the case where the
    3636             :                          * external route prefix
    3637             :                          * and aggegate prefix is same
    3638             :                          * If same don't flush the
    3639             :                          * originated
    3640             :                          * external LSA.
    3641             :                          */
    3642           0 :                         ospf6_handle_aggregated_exnl_rt(
    3643             :                                         ospf6, aggr, rt);
    3644           0 :                         return;
    3645             :                 }
    3646             :         }
    3647             : 
    3648          53 :         info = rt->route_option;
    3649             : 
    3650             :         /* When the info->id = 0, it means it is being originated for the
    3651             :          * first time.
    3652             :          */
    3653          53 :         if (!info->id) {
    3654          18 :                 info->id = ospf6->external_id++;
    3655             :         } else {
    3656          35 :                 prefix_id.family = AF_INET;
    3657          35 :                 prefix_id.prefixlen = 32;
    3658          35 :                 prefix_id.u.prefix4.s_addr = htonl(info->id);
    3659             :         }
    3660             : 
    3661          53 :         rt->path.origin.id = htonl(info->id);
    3662             : 
    3663          53 :         if (IS_OSPF6_DEBUG_ASBR) {
    3664           0 :                 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
    3665             :                            &prefix_id.u.prefix4, p, rt->path.metric_type);
    3666             :         }
    3667             : 
    3668          53 :         ospf6_originate_type5_type7_lsas(rt, ospf6);
    3669             : 
    3670             : }
    3671             : 
    3672           4 : void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6)
    3673             : {
    3674           4 :         struct route_node *rn = NULL;
    3675           4 :         struct ospf6_external_aggr_rt *aggr;
    3676             : 
    3677           4 :         if (IS_OSPF6_DEBUG_AGGR)
    3678           0 :                 zlog_debug("Unset the origination bit for all aggregator");
    3679             : 
    3680             :         /* Resetting the running external ID counter so that the origination
    3681             :          * of external LSAs starts from the beginning 0.0.0.1
    3682             :          */
    3683           4 :         ospf6->external_id = OSPF6_EXT_INIT_LS_ID;
    3684             : 
    3685           4 :         for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
    3686           0 :                 if (!rn->info)
    3687           0 :                         continue;
    3688             : 
    3689           0 :                 aggr = rn->info;
    3690             : 
    3691           0 :                 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
    3692             :         }
    3693           4 : }

Generated by: LCOV version v1.16-topotato