back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_ext.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 101 795 12.7 %
Date: 2023-02-24 19:38:44 Functions: 9 41 22.0 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
       3             :  * Advertisement
       4             :  *
       5             :  * Module name: Extended Prefix/Link Opaque LSA
       6             :  *
       7             :  * Author: Olivier Dugeon <olivier.dugeon@orange.com>
       8             :  * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
       9             :  *
      10             :  * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
      11             :  *
      12             :  * This program is free software; you can redistribute it and/or modify it
      13             :  * under the terms of the GNU General Public License as published by the Free
      14             :  * Software Foundation; either version 2 of the License, or (at your option)
      15             :  * any later version.
      16             :  *
      17             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      18             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      19             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      20             :  * more details.
      21             :  *
      22             :  * You should have received a copy of the GNU General Public License along
      23             :  * with this program; see the file COPYING; if not, write to the Free Software
      24             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      25             :  */
      26             : 
      27             : #include <zebra.h>
      28             : #include <math.h>
      29             : #include <stdio.h>
      30             : #include <stdlib.h>
      31             : 
      32             : #include "linklist.h"
      33             : #include "prefix.h"
      34             : #include "if.h"
      35             : #include "table.h"
      36             : #include "memory.h"
      37             : #include "command.h"
      38             : #include "vty.h"
      39             : #include "stream.h"
      40             : #include "log.h"
      41             : #include "thread.h"
      42             : #include "hash.h"
      43             : #include "sockunion.h" /* for inet_aton() */
      44             : #include "network.h"
      45             : #include "if.h"
      46             : #include "libospf.h" /* for ospf interface types */
      47             : 
      48             : #include "ospfd/ospfd.h"
      49             : #include "ospfd/ospf_interface.h"
      50             : #include "ospfd/ospf_ism.h"
      51             : #include "ospfd/ospf_asbr.h"
      52             : #include "ospfd/ospf_lsa.h"
      53             : #include "ospfd/ospf_lsdb.h"
      54             : #include "ospfd/ospf_neighbor.h"
      55             : #include "ospfd/ospf_nsm.h"
      56             : #include "ospfd/ospf_flood.h"
      57             : #include "ospfd/ospf_packet.h"
      58             : #include "ospfd/ospf_spf.h"
      59             : #include "ospfd/ospf_dump.h"
      60             : #include "ospfd/ospf_route.h"
      61             : #include "ospfd/ospf_ase.h"
      62             : #include "ospfd/ospf_zebra.h"
      63             : #include "ospfd/ospf_sr.h"
      64             : #include "ospfd/ospf_ext.h"
      65             : #include "ospfd/ospf_errors.h"
      66             : 
      67             : /* Following structure are internal use only. */
      68             : 
      69             : /*
      70             :  * Global variable to manage Extended Prefix/Link Opaque LSA on this node.
      71             :  * Note that all parameter values are stored in network byte order.
      72             :  */
      73             : static struct ospf_ext_lp OspfEXT;
      74             : 
      75             : /*
      76             :  * -----------------------------------------------------------------------
      77             :  * Following are initialize/terminate functions for Extended Prefix/Link
      78             :  * Opaque LSA handling.
      79             :  * -----------------------------------------------------------------------
      80             :  */
      81             : 
      82             : /* Extended Prefix Opaque LSA related callback functions */
      83             : static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json,
      84             :                                     struct ospf_lsa *lsa);
      85             : static int ospf_ext_pref_lsa_originate(void *arg);
      86             : static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa);
      87             : static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
      88             :                                        enum lsa_opcode opcode);
      89             : /* Extended Link Opaque LSA related callback functions */
      90             : static int ospf_ext_link_new_if(struct interface *ifp);
      91             : static int ospf_ext_link_del_if(struct interface *ifp);
      92             : static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status);
      93             : static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status);
      94             : static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json,
      95             :                                     struct ospf_lsa *lsa);
      96             : static int ospf_ext_link_lsa_originate(void *arg);
      97             : static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa);
      98             : static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
      99             :                                        enum lsa_opcode opcode);
     100             : static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op);
     101             : static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa);
     102             : static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa);
     103             : static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti);
     104             : static void del_ext_info(void *val);
     105             : 
     106             : /*
     107             :  * Extended Link/Prefix initialization
     108             :  *
     109             :  * @param - none
     110             :  *
     111             :  * @return - 0 if OK, <> 0 otherwise
     112             :  */
     113           4 : int ospf_ext_init(void)
     114             : {
     115           4 :         int rc = 0;
     116             : 
     117           4 :         memset(&OspfEXT, 0, sizeof(OspfEXT));
     118           4 :         OspfEXT.enabled = false;
     119             :         /* Only Area flooding is supported yet */
     120           4 :         OspfEXT.scope = OSPF_OPAQUE_AREA_LSA;
     121             :         /* Initialize interface list */
     122           4 :         OspfEXT.iflist = list_new();
     123           4 :         OspfEXT.iflist->del = del_ext_info;
     124             : 
     125           4 :         zlog_info("EXT (%s): Register Extended Link Opaque LSA", __func__);
     126           4 :         rc = ospf_register_opaque_functab(
     127             :                 OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_EXTENDED_LINK_LSA,
     128             :                 ospf_ext_link_new_if,   /* new if */
     129             :                 ospf_ext_link_del_if,   /* del if */
     130             :                 ospf_ext_ism_change,    /* ism change */
     131             :                 ospf_ext_link_nsm_change,    /* nsm change */
     132             :                 NULL,                        /* Write router config. */
     133             :                 NULL,                        /* Write interface conf. */
     134             :                 NULL,                        /* Write debug config. */
     135             :                 ospf_ext_link_show_info,     /* Show LSA info */
     136             :                 ospf_ext_link_lsa_originate, /* Originate LSA */
     137             :                 ospf_ext_link_lsa_refresh,   /* Refresh LSA */
     138             :                 ospf_ext_link_lsa_update,    /* new_lsa_hook */
     139             :                 NULL);                       /* del_lsa_hook */
     140             : 
     141           4 :         if (rc != 0) {
     142           0 :                 flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
     143             :                           "EXT (%s): Failed to register Extended Link LSA",
     144             :                           __func__);
     145           0 :                 return rc;
     146             :         }
     147             : 
     148           4 :         zlog_info("EXT (%s): Register Extended Prefix Opaque LSA", __func__);
     149           8 :         rc = ospf_register_opaque_functab(
     150           4 :                 OspfEXT.scope, OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
     151             :                 NULL,                        /* new if handle by link */
     152             :                 NULL,                        /* del if handle by link */
     153             :                 NULL,                        /* ism change */
     154             :                 NULL,                        /* nsm change */
     155             :                 ospf_sr_config_write_router, /* Write router config. */
     156             :                 NULL,                        /* Write interface conf. */
     157             :                 NULL,                        /* Write debug config. */
     158             :                 ospf_ext_pref_show_info,     /* Show LSA info */
     159             :                 ospf_ext_pref_lsa_originate, /* Originate LSA */
     160             :                 ospf_ext_pref_lsa_refresh,   /* Refresh LSA */
     161             :                 ospf_ext_pref_lsa_update,    /* new_lsa_hook */
     162             :                 NULL);                       /* del_lsa_hook */
     163           4 :         if (rc != 0) {
     164           0 :                 flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
     165             :                           "EXT (%s): Failed to register Extended Prefix LSA",
     166             :                           __func__);
     167           0 :                 return rc;
     168             :         }
     169             : 
     170             :         return rc;
     171             : }
     172             : 
     173             : /*
     174             :  * Extended Link/Prefix termination function
     175             :  *
     176             :  * @param - none
     177             :  * @return - none
     178             :  */
     179           0 : void ospf_ext_term(void)
     180             : {
     181             : 
     182           0 :         if ((OspfEXT.scope == OSPF_OPAQUE_AREA_LSA)
     183           0 :             || (OspfEXT.scope == OSPF_OPAQUE_AS_LSA))
     184           0 :                 ospf_delete_opaque_functab(OspfEXT.scope,
     185             :                                            OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
     186             : 
     187           0 :         ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
     188             :                                    OPAQUE_TYPE_EXTENDED_LINK_LSA);
     189             : 
     190           0 :         list_delete(&OspfEXT.iflist);
     191           0 :         OspfEXT.scope = 0;
     192           0 :         OspfEXT.enabled = false;
     193             : 
     194           0 :         return;
     195             : }
     196             : 
     197             : /*
     198             :  * Extended Link/Prefix finish function
     199             :  *
     200             :  * @param - none
     201             :  * @return - none
     202             :  */
     203           4 : void ospf_ext_finish(void)
     204             : {
     205             : 
     206           4 :         struct listnode *node;
     207           4 :         struct ext_itf *exti;
     208             : 
     209             :         /* Flush Router Info LSA */
     210          21 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
     211          13 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     212           0 :                         ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
     213             : 
     214           4 :         OspfEXT.enabled = false;
     215           4 : }
     216             : 
     217             : /*
     218             :  * ---------------------------------------------------------------------
     219             :  * Following are control functions for Extended Prefix/Link Opaque LSA
     220             :  * parameters management.
     221             :  * ---------------------------------------------------------------------
     222             :  */
     223             : 
     224             : /* Functions to free memory space */
     225           0 : static void del_ext_info(void *val)
     226             : {
     227           0 :         XFREE(MTYPE_OSPF_EXT_PARAMS, val);
     228           0 : }
     229             : 
     230             : /* Increment instance value for Extended Prefix Opaque LSAs Opaque ID field */
     231           0 : static uint32_t get_ext_pref_instance_value(void)
     232             : {
     233           0 :         static uint32_t seqno = 0;
     234             : 
     235           0 :         if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
     236           0 :                 seqno += 1;
     237             :         else
     238           0 :                 seqno = 1; /* Avoid zero. */
     239             : 
     240           0 :         return seqno;
     241             : }
     242             : 
     243             : /* Increment instance value for Extended Link Opaque LSAs Opaque ID field */
     244          33 : static uint32_t get_ext_link_instance_value(void)
     245             : {
     246          33 :         static uint32_t seqno = 0;
     247             : 
     248          33 :         if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
     249          33 :                 seqno += 1;
     250             :         else
     251           0 :                 seqno = 1; /* Avoid zero. */
     252             : 
     253          33 :         return seqno;
     254             : }
     255             : 
     256             : /* Lookup Extended Prefix/Links by ifp from OspfEXT struct iflist */
     257          80 : static struct ext_itf *lookup_ext_by_ifp(struct interface *ifp)
     258             : {
     259          80 :         struct listnode *node;
     260          80 :         struct ext_itf *exti;
     261             : 
     262         231 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
     263         138 :                 if (exti->ifp == ifp)
     264          67 :                         return exti;
     265             : 
     266             :         return NULL;
     267             : }
     268             : 
     269             : /* Lookup Extended Prefix/Links by LSA ID from OspfEXT struct iflist */
     270           0 : static struct ext_itf *lookup_ext_by_instance(struct ospf_lsa *lsa)
     271             : {
     272           0 :         struct listnode *node;
     273           0 :         struct ext_itf *exti;
     274           0 :         uint32_t key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr));
     275           0 :         uint8_t type = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
     276             : 
     277             : 
     278           0 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
     279           0 :                 if ((exti->instance == key) && (exti->type == type))
     280           0 :                         return exti;
     281             : 
     282             :         return NULL;
     283             : }
     284             : 
     285             : /*
     286             :  * ----------------------------------------------------------------------
     287             :  * The underlying subsection defines setters and unsetters to create and
     288             :  * delete tlvs and subtlvs
     289             :  * ----------------------------------------------------------------------
     290             :  */
     291             : 
     292             : /* Extended Prefix TLV - RFC7684 section 2.1 */
     293           0 : static void set_ext_prefix(struct ext_itf *exti, uint8_t route_type,
     294             :                            uint8_t flags, struct prefix_ipv4 p)
     295             : {
     296             : 
     297           0 :         TLV_TYPE(exti->prefix) = htons(EXT_TLV_PREFIX);
     298             :         /* Warning: Size must be adjust depending of subTLV's */
     299           0 :         TLV_LEN(exti->prefix) = htons(EXT_TLV_PREFIX_SIZE);
     300           0 :         exti->prefix.route_type = route_type;
     301           0 :         exti->prefix.flags = flags;
     302             :         /* Only Address Family Ipv4 (0) is defined in RFC 7684 */
     303           0 :         exti->prefix.af = 0;
     304           0 :         exti->prefix.pref_length = p.prefixlen;
     305           0 :         exti->prefix.address = p.prefix;
     306             : 
     307           0 :         SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
     308             : }
     309             : 
     310             : /* Extended Link TLV - RFC7684 section 3.1 */
     311          16 : static void set_ext_link(struct ext_itf *exti, uint8_t type, struct in_addr id,
     312             :                          struct in_addr data)
     313             : {
     314             : 
     315          16 :         TLV_TYPE(exti->link) = htons(EXT_TLV_LINK);
     316             :         /* Warning: Size must be adjust depending of subTLV's */
     317          16 :         TLV_LEN(exti->link) = htons(EXT_TLV_LINK_SIZE);
     318          16 :         exti->link.link_type = type;
     319          16 :         exti->link.link_id = id;
     320          16 :         exti->link.link_data = data;
     321             : }
     322             : 
     323             : /* Prefix SID SubTLV - section 5 */
     324           0 : static void set_prefix_sid(struct ext_itf *exti, uint8_t algorithm,
     325             :                            uint32_t value, int value_type, uint8_t flags)
     326             : {
     327             : 
     328           0 :         if ((algorithm != SR_ALGORITHM_SPF)
     329             :             && (algorithm != SR_ALGORITHM_STRICT_SPF)) {
     330             :                 flog_err(EC_OSPF_INVALID_ALGORITHM,
     331             :                          "EXT (%s): unrecognized algorithm, not SPF or S-SPF",
     332             :                          __func__);
     333             :                 return;
     334             :         }
     335             : 
     336             :         /* Update flags according to the type of value field: label or index */
     337           0 :         if (value_type == SID_LABEL)
     338             :                 SET_FLAG(flags, EXT_SUBTLV_PREFIX_SID_VFLG);
     339             : 
     340             :         /* set prefix sid subtlv for an extended prefix tlv */
     341           0 :         TLV_TYPE(exti->node_sid) = htons(EXT_SUBTLV_PREFIX_SID);
     342           0 :         exti->node_sid.algorithm = algorithm;
     343           0 :         exti->node_sid.flags = flags;
     344           0 :         exti->node_sid.mtid = 0; /* Multi-Topology is not supported */
     345             : 
     346             :         /* Set Label or Index value */
     347           0 :         if (value_type == SID_LABEL) {
     348             :                 TLV_LEN(exti->node_sid) =
     349             :                         htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE));
     350             :                 exti->node_sid.value = htonl(SET_LABEL(value));
     351             :         } else {
     352           0 :                 TLV_LEN(exti->node_sid) =
     353             :                         htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE));
     354           0 :                 exti->node_sid.value = htonl(value);
     355             :         }
     356             : }
     357             : 
     358             : /* Adjacency SID SubTLV - section 6.1 */
     359           0 : static void set_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
     360             :                         int value_type)
     361             : {
     362           0 :         int index;
     363           0 :         uint8_t flags;
     364             : 
     365             :         /* Determine which ADJ_SID must be set: nominal or backup */
     366           0 :         if (backup) {
     367             :                 flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
     368             :                 index = 1;
     369             :         } else {
     370           0 :                 index = 0;
     371           0 :                 flags = 0;
     372             :         }
     373             : 
     374             :         /* Set Header */
     375           0 :         TLV_TYPE(exti->adj_sid[index]) = htons(EXT_SUBTLV_ADJ_SID);
     376             : 
     377             :         /* Only Local ADJ-SID is supported for the moment */
     378           0 :         SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
     379             : 
     380           0 :         exti->adj_sid[index].mtid = 0; /* Multi-Topology is not supported */
     381             : 
     382             :         /* Adjust Length, Flags and Value depending on the type of Label */
     383           0 :         if (value_type == SID_LABEL) {
     384           0 :                 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
     385           0 :                 TLV_LEN(exti->adj_sid[index]) =
     386             :                         htons(SID_LABEL_SIZE(EXT_SUBTLV_ADJ_SID_SIZE));
     387           0 :                 exti->adj_sid[index].value = htonl(SET_LABEL(value));
     388             :         } else {
     389             :                 UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
     390             :                 TLV_LEN(exti->adj_sid[index]) =
     391             :                         htons(SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE));
     392             :                 exti->adj_sid[index].value = htonl(value);
     393             :         }
     394             : 
     395           0 :         exti->adj_sid[index].flags = flags; /* Set computed flags */
     396           0 :         exti->adj_sid[index].mtid = 0;   /* Multi-Topology is not supported */
     397           0 :         exti->adj_sid[index].weight = 0; /* Load-Balancing is not supported */
     398           0 : }
     399             : 
     400             : /* LAN Adjacency SID SubTLV - section 6.2 */
     401           0 : static void set_lan_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
     402             :                             int value_type, struct in_addr neighbor_id)
     403             : {
     404             : 
     405           0 :         int index;
     406           0 :         uint8_t flags;
     407             : 
     408             :         /* Determine which ADJ_SID must be set: nominal or backup */
     409           0 :         if (backup) {
     410             :                 flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
     411             :                 index = 1;
     412             :         } else {
     413           0 :                 index = 0;
     414           0 :                 flags = 0;
     415             :         }
     416             : 
     417             :         /* Set Header */
     418           0 :         TLV_TYPE(exti->lan_sid[index]) = htons(EXT_SUBTLV_LAN_ADJ_SID);
     419             : 
     420             :         /* Only Local ADJ-SID is supported for the moment */
     421           0 :         SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
     422             : 
     423             :         /* Adjust Length, Flags and Value depending on the type of Label */
     424           0 :         if (value_type == SID_LABEL) {
     425           0 :                 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
     426           0 :                 TLV_LEN(exti->lan_sid[index]) =
     427             :                         htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE));
     428           0 :                 exti->lan_sid[index].value = htonl(SET_LABEL(value));
     429             :         } else {
     430             :                 UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
     431             :                 TLV_LEN(exti->lan_sid[index]) =
     432             :                         htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE));
     433             :                 exti->lan_sid[index].value = htonl(value);
     434             :         }
     435             : 
     436           0 :         exti->lan_sid[index].flags = flags; /* Set computed flags */
     437           0 :         exti->lan_sid[index].mtid = 0;   /* Multi-Topology is not supported */
     438           0 :         exti->lan_sid[index].weight = 0; /* Load-Balancing is not supported */
     439           0 :         exti->lan_sid[index].neighbor_id = neighbor_id;
     440             : }
     441             : 
     442           0 : static void unset_adjacency_sid(struct ext_itf *exti)
     443             : {
     444             :         /* Reset Adjacency TLV */
     445           0 :         if (exti->type == ADJ_SID) {
     446           0 :                 TLV_TYPE(exti->adj_sid[0]) = 0;
     447           0 :                 TLV_TYPE(exti->adj_sid[1]) = 0;
     448             :         }
     449             :         /* or Lan-Adjacency TLV */
     450           0 :         if (exti->type == LAN_ADJ_SID) {
     451           0 :                 TLV_TYPE(exti->lan_sid[0]) = 0;
     452           0 :                 TLV_TYPE(exti->lan_sid[1]) = 0;
     453             :         }
     454             : }
     455             : 
     456             : /* Experimental SubTLV from Cisco */
     457           0 : static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif)
     458             : {
     459             : 
     460           0 :         TLV_TYPE(exti->rmt_itf_addr) = htons(EXT_SUBTLV_RMT_ITF_ADDR);
     461           0 :         TLV_LEN(exti->rmt_itf_addr) = htons(sizeof(struct in_addr));
     462           0 :         exti->rmt_itf_addr.value = rmtif;
     463             : }
     464             : 
     465             : /* Delete Extended LSA */
     466          18 : static void ospf_extended_lsa_delete(struct ext_itf *exti)
     467             : {
     468             : 
     469             :         /* Avoid deleting LSA if Extended is not enable */
     470          18 :         if (!OspfEXT.enabled)
     471             :                 return;
     472             : 
     473             :         /* Process only Active Extended Prefix/Link LSA */
     474           0 :         if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
     475             :                 return;
     476             : 
     477           0 :         osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__,
     478             :                   exti->stype == LOCAL_SID ? "Prefix" : "",
     479             :                   exti->stype == ADJ_SID ? "Adjacency" : "",
     480             :                   exti->stype == LAN_ADJ_SID ? "LAN-Adjacency" : "",
     481             :                   exti->ifp->name);
     482             : 
     483             :         /* Flush LSA if already engaged */
     484           0 :         if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
     485           0 :                 ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
     486           0 :                 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
     487             :         }
     488             : 
     489             :         /* De-activate this Extended Prefix/Link and remove corresponding
     490             :          * Segment-Routing Prefix-SID or (LAN)-ADJ-SID */
     491           0 :         if (exti->stype == ADJ_SID || exti->stype == LAN_ADJ_SID)
     492           0 :                 ospf_ext_link_delete_adj_sid(exti);
     493             :         else
     494           0 :                 ospf_sr_ext_itf_delete(exti);
     495             : }
     496             : 
     497             : /*
     498             :  * Update Extended prefix SID index for Loopback interface type
     499             :  *
     500             :  * @param ifname - Loopback interface name
     501             :  * @param index - new value for the prefix SID of this interface
     502             :  * @param p - prefix for this interface or NULL if Extended Prefix
     503             :  * should be remove
     504             :  *
     505             :  * @return instance number if update is OK, 0 otherwise
     506             :  */
     507           0 : uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
     508             :                                         struct prefix_ipv4 *p, uint8_t flags)
     509             : {
     510           0 :         int rc = 0;
     511           0 :         struct ext_itf *exti;
     512             : 
     513             :         /* Find Extended Prefix interface */
     514           0 :         exti = lookup_ext_by_ifp(ifp);
     515           0 :         if (exti == NULL)
     516             :                 return rc;
     517             : 
     518           0 :         if (p != NULL) {
     519           0 :                 osr_debug("EXT (%s): Schedule new prefix %pFX with index %u on interface %s", __func__, p, index, ifp->name);
     520             : 
     521             :                 /* Set first Extended Prefix then the Prefix SID information */
     522           0 :                 set_ext_prefix(exti, OSPF_PATH_INTRA_AREA, EXT_TLV_PREF_NFLG,
     523             :                                *p);
     524           0 :                 set_prefix_sid(exti, SR_ALGORITHM_SPF, index, SID_INDEX, flags);
     525             : 
     526             :                 /* Try to Schedule LSA */
     527           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
     528           0 :                         if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     529           0 :                                 ospf_ext_pref_lsa_schedule(exti,
     530             :                                                            REFRESH_THIS_LSA);
     531             :                         else
     532           0 :                                 ospf_ext_pref_lsa_schedule(
     533             :                                         exti, REORIGINATE_THIS_LSA);
     534             :                 }
     535             :         } else {
     536           0 :                 osr_debug("EXT (%s): Remove prefix for interface %s", __func__,
     537             :                           ifp->name);
     538             : 
     539           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     540           0 :                         ospf_ext_pref_lsa_schedule(exti, FLUSH_THIS_LSA);
     541             :         }
     542             : 
     543           0 :         return SET_OPAQUE_LSID(exti->type, exti->instance);
     544             : }
     545             : 
     546             : /**
     547             :  * Update Adjacecny-SID for Extended Link LSA
     548             :  *
     549             :  * @param exti  Extended Link information
     550             :  */
     551           0 : static void ospf_ext_link_update_adj_sid(struct ext_itf *exti)
     552             : {
     553           0 :         mpls_label_t label;
     554           0 :         mpls_label_t bck_label;
     555             : 
     556             :         /* Process only (LAN)Adjacency-SID Type */
     557           0 :         if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
     558             :                 return;
     559             : 
     560             :         /* Request Primary & Backup Labels from Label Manager */
     561           0 :         bck_label = ospf_sr_local_block_request_label();
     562           0 :         label = ospf_sr_local_block_request_label();
     563           0 :         if (bck_label == MPLS_INVALID_LABEL || label == MPLS_INVALID_LABEL) {
     564           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     565           0 :                         ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
     566           0 :                 return;
     567             :         }
     568             : 
     569             :         /* Set Adjacency-SID, backup first */
     570           0 :         if (exti->stype == ADJ_SID) {
     571           0 :                 set_adj_sid(exti, true, bck_label, SID_LABEL);
     572           0 :                 set_adj_sid(exti, false, label, SID_LABEL);
     573             :         } else {
     574           0 :                 set_lan_adj_sid(exti, true, bck_label, SID_LABEL,
     575             :                                 exti->lan_sid[0].neighbor_id);
     576           0 :                 set_lan_adj_sid(exti, false, label, SID_LABEL,
     577             :                                 exti->lan_sid[1].neighbor_id);
     578             :         }
     579             : 
     580             :         /* Finally, add corresponding SR Link in SRDB & MPLS LFIB */
     581           0 :         SET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
     582           0 :         ospf_sr_ext_itf_add(exti);
     583             : }
     584             : 
     585             : /**
     586             :  * Delete Adjacecny-SID for Extended Link LSA
     587             :  *
     588             :  * @param exti  Extended Link information
     589             :  */
     590           0 : static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti)
     591             : {
     592             :         /* Process only (LAN)Adjacency-SID Type */
     593           0 :         if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
     594             :                 return;
     595             : 
     596             :         /* Release Primary & Backup Labels from Label Manager */
     597           0 :         if (exti->stype == ADJ_SID) {
     598           0 :                 ospf_sr_local_block_release_label(exti->adj_sid[0].value);
     599           0 :                 ospf_sr_local_block_release_label(exti->adj_sid[1].value);
     600             :         } else {
     601           0 :                 ospf_sr_local_block_release_label(exti->lan_sid[0].value);
     602           0 :                 ospf_sr_local_block_release_label(exti->lan_sid[1].value);
     603             :         }
     604             :         /* And reset corresponding TLV */
     605           0 :         unset_adjacency_sid(exti);
     606             : 
     607             :         /* Finally, remove corresponding SR Link in SRDB & MPLS LFIB */
     608           0 :         UNSET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
     609           0 :         ospf_sr_ext_itf_delete(exti);
     610             : }
     611             : 
     612             : /**
     613             :  * Update Extended Link LSA once Segment Routing Label Block has been changed.
     614             :  */
     615           0 : void ospf_ext_link_srlb_update(void)
     616             : {
     617           0 :         struct listnode *node;
     618           0 :         struct ext_itf *exti;
     619             : 
     620             : 
     621           0 :         osr_debug("EXT (%s): Update Extended Links with new SRLB", __func__);
     622             : 
     623             :         /* Update all Extended Link Adjaceny-SID  */
     624           0 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
     625             :                 /* Skip Extended Prefix */
     626           0 :                 if (exti->stype == PREF_SID || exti->stype == LOCAL_SID)
     627           0 :                         continue;
     628             : 
     629             :                 /* Skip inactive Extended Link */
     630           0 :                 if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
     631           0 :                         continue;
     632             : 
     633           0 :                 ospf_ext_link_update_adj_sid(exti);
     634             :         }
     635           0 : }
     636             : 
     637             : /*
     638             :  * Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
     639             :  *
     640             :  * @param enable To activate or not Segment Routing Extended LSA flooding
     641             :  *
     642             :  * @return none
     643             :  */
     644           0 : void ospf_ext_update_sr(bool enable)
     645             : {
     646           0 :         struct listnode *node;
     647           0 :         struct ext_itf *exti;
     648             : 
     649           0 :         osr_debug("EXT (%s): %s Extended LSAs for Segment Routing ", __func__,
     650             :                   enable ? "Enable" : "Disable");
     651             : 
     652           0 :         if (enable) {
     653           0 :                 OspfEXT.enabled = true;
     654             : 
     655             :                 /* Refresh LSAs if already engaged or originate */
     656           0 :                 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
     657             :                         /* Skip Inactive Extended Link */
     658           0 :                         if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
     659           0 :                                 continue;
     660             : 
     661             :                         /* Update Extended Link (LAN)Adj-SID if not set  */
     662           0 :                         if (!CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
     663           0 :                                 ospf_ext_link_update_adj_sid(exti);
     664             : 
     665             :                         /* Finally, flood the extended Link */
     666           0 :                         if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     667           0 :                                 ospf_ext_lsa_schedule(exti, REFRESH_THIS_LSA);
     668             :                         else
     669           0 :                                 ospf_ext_lsa_schedule(exti,
     670             :                                                       REORIGINATE_THIS_LSA);
     671             :                 }
     672             :         } else {
     673             :                 /* Start by Removing Extended LSA */
     674           0 :                 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
     675           0 :                         ospf_extended_lsa_delete(exti);
     676             : 
     677             :                 /* And then disable Extended Link/Prefix */
     678           0 :                 OspfEXT.enabled = false;
     679             :         }
     680           0 : }
     681             : 
     682             : /*
     683             :  * -----------------------------------------------------------------------
     684             :  * Following are callback functions against generic Opaque-LSAs handling
     685             :  * -----------------------------------------------------------------------
     686             :  */
     687             : 
     688             : /* Add new Interface in Extended Interface List */
     689          13 : static int ospf_ext_link_new_if(struct interface *ifp)
     690             : {
     691          13 :         struct ext_itf *new;
     692          13 :         int rc = -1;
     693             : 
     694          13 :         if (lookup_ext_by_ifp(ifp) != NULL) {
     695          13 :                 rc = 0; /* Do nothing here. */
     696             :                 return rc;
     697             :         }
     698             : 
     699          13 :         new = XCALLOC(MTYPE_OSPF_EXT_PARAMS, sizeof(struct ext_itf));
     700             : 
     701             :         /* initialize new information and link back the interface */
     702          13 :         new->ifp = ifp;
     703          13 :         new->flags = EXT_LPFLG_LSA_INACTIVE;
     704             : 
     705          13 :         listnode_add(OspfEXT.iflist, new);
     706             : 
     707          13 :         rc = 0;
     708          13 :         return rc;
     709             : }
     710             : 
     711             : /* Remove existing Interface from Extended Interface List */
     712           0 : static int ospf_ext_link_del_if(struct interface *ifp)
     713             : {
     714           0 :         struct ext_itf *exti;
     715           0 :         int rc = -1;
     716             : 
     717           0 :         exti = lookup_ext_by_ifp(ifp);
     718           0 :         if (exti != NULL) {
     719             :                 /* Flush LSA and remove Adjacency SID */
     720           0 :                 ospf_extended_lsa_delete(exti);
     721             : 
     722             :                 /* Dequeue listnode entry from the list. */
     723           0 :                 listnode_delete(OspfEXT.iflist, exti);
     724             : 
     725           0 :                 XFREE(MTYPE_OSPF_EXT_PARAMS, exti);
     726             : 
     727           0 :                 rc = 0;
     728             :         } else {
     729           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
     730             :                           "EXT (%s): interface %s is not found", __func__,
     731             :                           ifp ? ifp->name : "-");
     732             :         }
     733             : 
     734           0 :         return rc;
     735             : }
     736             : 
     737             : /*
     738             :  * Determine if an Interface belongs to an Extended Link Adjacency or
     739             :  * Extended Prefix SID type and allocate new instance value accordingly
     740             :  */
     741          51 : static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status)
     742             : {
     743          51 :         struct ext_itf *exti;
     744             : 
     745             :         /* Get interface information for Segment Routing */
     746          51 :         exti = lookup_ext_by_ifp(oi->ifp);
     747          51 :         if (exti == NULL) {
     748           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
     749             :                           "EXT (%s): Cannot get Extended info. from OI(%s)",
     750             :                           __func__, IF_NAME(oi));
     751           0 :                 return;
     752             :         }
     753             : 
     754             :         /* Reset Extended information if ospf interface goes Down */
     755          51 :         if (oi->state == ISM_Down) {
     756          18 :                 ospf_extended_lsa_delete(exti);
     757          18 :                 exti->area = NULL;
     758          18 :                 exti->flags = EXT_LPFLG_LSA_INACTIVE;
     759          18 :                 return;
     760             :         }
     761             : 
     762             :         /* Determine if interface is related to a Prefix or an Adjacency SID */
     763          33 :         if (oi->type == OSPF_IFTYPE_LOOPBACK) {
     764           0 :                 exti->stype = PREF_SID;
     765           0 :                 exti->type = OPAQUE_TYPE_EXTENDED_PREFIX_LSA;
     766           0 :                 exti->instance = get_ext_pref_instance_value();
     767           0 :                 exti->area = oi->area;
     768             : 
     769             :                 /* Complete SRDB if the interface belongs to a Prefix */
     770           0 :                 if (OspfEXT.enabled) {
     771           0 :                         osr_debug("EXT (%s): Set Prefix SID to interface %s ",
     772             :                                   __func__, oi->ifp->name);
     773           0 :                         ospf_sr_update_local_prefix(oi->ifp, oi->address);
     774             :                 }
     775             :         } else {
     776             :                 /* Determine if interface is related to Adj. or LAN Adj. SID */
     777          33 :                 if (oi->state == ISM_DR)
     778           9 :                         exti->stype = LAN_ADJ_SID;
     779             :                 else
     780          24 :                         exti->stype = ADJ_SID;
     781             : 
     782          33 :                 exti->type = OPAQUE_TYPE_EXTENDED_LINK_LSA;
     783          33 :                 exti->instance = get_ext_link_instance_value();
     784          33 :                 exti->area = oi->area;
     785             : 
     786             :                 /*
     787             :                  * Note: Adjacency SID information are completed when ospf
     788             :                  * adjacency become up see ospf_ext_link_nsm_change()
     789             :                  */
     790          33 :                 if (OspfEXT.enabled)
     791           0 :                         osr_debug(
     792             :                                 "EXT (%s): Set %sAdjacency SID for interface %s ",
     793             :                                 __func__, exti->stype == ADJ_SID ? "" : "LAN-",
     794             :                                 oi->ifp->name);
     795             :         }
     796             : }
     797             : 
     798             : /*
     799             :  * Finish Extended Link configuration and flood corresponding LSA
     800             :  * when OSPF adjacency on this link fire up
     801             :  */
     802          52 : static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
     803             : {
     804          52 :         struct ospf_interface *oi = nbr->oi;
     805          52 :         struct ext_itf *exti;
     806             : 
     807             :         /* Process Link only when neighbor old or new state is NSM Full */
     808          52 :         if (nbr->state != NSM_Full && old_status != NSM_Full)
     809             :                 return;
     810             : 
     811             :         /* Get interface information for Segment Routing */
     812          16 :         exti = lookup_ext_by_ifp(oi->ifp);
     813          16 :         if (exti == NULL) {
     814           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
     815             :                           "EXT (%s): Cannot get Extended info. from OI(%s)",
     816             :                           __func__, IF_NAME(oi));
     817           0 :                 return;
     818             :         }
     819             : 
     820             :         /* Check that we have a valid area and ospf context */
     821          16 :         if (oi->area == NULL || oi->area->ospf == NULL) {
     822           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
     823             :                           "EXT (%s): Cannot refer to OSPF from OI(%s)",
     824             :                           __func__, IF_NAME(oi));
     825           0 :                 return;
     826             :         }
     827             : 
     828             :         /* Remove Extended Link if Neighbor State goes Down or Deleted */
     829          16 :         if (OspfEXT.enabled
     830           0 :             && (nbr->state == NSM_Down || nbr->state == NSM_Deleted)) {
     831           0 :                 ospf_ext_link_delete_adj_sid(exti);
     832           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     833           0 :                         ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
     834           0 :                 exti->flags = EXT_LPFLG_LSA_INACTIVE;
     835           0 :                 return;
     836             :         }
     837             : 
     838             :         /* Keep Area information in combination with SR info. */
     839          16 :         exti->area = oi->area;
     840             : 
     841             :         /* Process only Adjacency/LAN SID */
     842          16 :         if (exti->stype == PREF_SID)
     843             :                 return;
     844             : 
     845          16 :         switch (oi->state) {
     846           0 :         case ISM_PointToPoint:
     847             :                 /* Segment ID is an Adjacency one */
     848           0 :                 exti->stype = ADJ_SID;
     849             : 
     850             :                 /* Set Extended Link TLV with link_id == Nbr Router ID */
     851           0 :                 set_ext_link(exti, OSPF_IFTYPE_POINTOPOINT, nbr->router_id,
     852           0 :                              oi->address->u.prefix4);
     853             : 
     854             :                 /* And Remote Interface address */
     855           0 :                 set_rmt_itf_addr(exti, nbr->address.u.prefix4);
     856             : 
     857           0 :                 break;
     858             : 
     859          10 :         case ISM_DR:
     860             :                 /* Segment ID is a LAN Adjacency for the DR only */
     861          10 :                 exti->stype = LAN_ADJ_SID;
     862             : 
     863             :                 /* Set Extended Link TLV with link_id == DR */
     864          10 :                 set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
     865          10 :                              oi->address->u.prefix4);
     866             : 
     867             :                 /* Set Neighbor ID */
     868          10 :                 exti->lan_sid[0].neighbor_id = nbr->router_id;
     869          10 :                 exti->lan_sid[1].neighbor_id = nbr->router_id;
     870             : 
     871          10 :                 break;
     872             : 
     873           6 :         case ISM_DROther:
     874             :         case ISM_Backup:
     875             :                 /* Segment ID is an Adjacency if not the DR */
     876           6 :                 exti->stype = ADJ_SID;
     877             : 
     878             :                 /* Set Extended Link TLV with link_id == DR */
     879           6 :                 set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
     880           6 :                              oi->address->u.prefix4);
     881             : 
     882           6 :                 break;
     883             : 
     884           0 :         default:
     885           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
     886           0 :                         ospf_ext_link_delete_adj_sid(exti);
     887           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     888           0 :                         ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
     889           0 :                 exti->flags = EXT_LPFLG_LSA_INACTIVE;
     890           0 :                 return;
     891             :         }
     892             : 
     893          16 :         SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
     894             : 
     895          16 :         if (OspfEXT.enabled) {
     896           0 :                 osr_debug("EXT (%s): Set %sAdjacency SID for interface %s ",
     897             :                           __func__, exti->stype == ADJ_SID ? "" : "LAN-",
     898             :                           oi->ifp->name);
     899             : 
     900             :                 /* Update (LAN)Adjacency SID */
     901           0 :                 ospf_ext_link_update_adj_sid(exti);
     902             : 
     903             :                 /* flood this links params if everything is ok */
     904           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
     905           0 :                         ospf_ext_link_lsa_schedule(exti, REFRESH_THIS_LSA);
     906             :                 else
     907           0 :                         ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA);
     908             :         }
     909             : }
     910             : 
     911             : /* Callbacks to handle Extended Link Segment Routing LSA information */
     912         161 : static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa)
     913             : {
     914             :         /* Sanity Check */
     915         161 :         if (lsa == NULL) {
     916           0 :                 flog_warn(EC_OSPF_LSA_NULL, "EXT (%s): Abort! LSA is NULL",
     917             :                           __func__);
     918           0 :                 return -1;
     919             :         }
     920             : 
     921             :         /* Process only Opaque LSA */
     922         161 :         if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
     923         161 :             && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
     924             :                 return 0;
     925             : 
     926             :         /* Process only Extended Link LSA */
     927           0 :         if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
     928             :             != OPAQUE_TYPE_EXTENDED_LINK_LSA)
     929             :                 return 0;
     930             : 
     931             :         /* Check if it is not my LSA */
     932           0 :         if (IS_LSA_SELF(lsa))
     933             :                 return 0;
     934             : 
     935             :         /* Check if Extended is enable */
     936           0 :         if (!OspfEXT.enabled)
     937             :                 return 0;
     938             : 
     939             :         /* Call Segment Routing LSA update or deletion */
     940           0 :         if (!IS_LSA_MAXAGE(lsa))
     941           0 :                 ospf_sr_ext_link_lsa_update(lsa);
     942             :         else
     943           0 :                 ospf_sr_ext_link_lsa_delete(lsa);
     944             : 
     945             :         return 0;
     946             : }
     947             : 
     948             : /* Callbacks to handle Extended Prefix Segment Routing LSA information */
     949         161 : static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa)
     950             : {
     951             : 
     952             :         /* Sanity Check */
     953         161 :         if (lsa == NULL) {
     954           0 :                 flog_warn(EC_OSPF_LSA_NULL, "EXT (%s): Abort! LSA is NULL",
     955             :                           __func__);
     956           0 :                 return -1;
     957             :         }
     958             : 
     959             :         /* Process only Opaque LSA */
     960         161 :         if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
     961         161 :             && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
     962             :                 return 0;
     963             : 
     964             :         /* Process only Extended Prefix LSA */
     965           0 :         if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
     966             :             != OPAQUE_TYPE_EXTENDED_PREFIX_LSA)
     967             :                 return 0;
     968             : 
     969             :         /* Check if it is not my LSA */
     970           0 :         if (IS_LSA_SELF(lsa))
     971             :                 return 0;
     972             : 
     973             :         /* Check if Extended is enable */
     974           0 :         if (!OspfEXT.enabled)
     975             :                 return 0;
     976             : 
     977             :         /* Call Segment Routing LSA update or deletion */
     978           0 :         if (!IS_LSA_MAXAGE(lsa))
     979           0 :                 ospf_sr_ext_prefix_lsa_update(lsa);
     980             :         else
     981           0 :                 ospf_sr_ext_prefix_lsa_delete(lsa);
     982             : 
     983             :         return 0;
     984             : }
     985             : 
     986             : /*
     987             :  * -------------------------------------------------------
     988             :  * Following are OSPF protocol processing functions for
     989             :  * Extended Prefix/Link Opaque LSA
     990             :  * -------------------------------------------------------
     991             :  */
     992             : 
     993           0 : static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
     994             : {
     995           0 :         stream_put(s, tlvh, sizeof(struct tlv_header));
     996             : }
     997             : 
     998           0 : static void build_tlv(struct stream *s, struct tlv_header *tlvh)
     999             : {
    1000             : 
    1001           0 :         if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) {
    1002           0 :                 build_tlv_header(s, tlvh);
    1003           0 :                 stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
    1004             :         }
    1005           0 : }
    1006             : 
    1007             : /* Build an Extended Prefix Opaque LSA body for extended prefix TLV */
    1008           0 : static void ospf_ext_pref_lsa_body_set(struct stream *s, struct ext_itf *exti)
    1009             : {
    1010             : 
    1011             :         /* Sanity check */
    1012           0 :         if ((exti == NULL) || (exti->stype != PREF_SID))
    1013             :                 return;
    1014             : 
    1015             :         /* Adjust Extended Prefix TLV size */
    1016           0 :         TLV_LEN(exti->prefix) = htons(ntohs(TLV_LEN(exti->node_sid))
    1017             :                                       + EXT_TLV_PREFIX_SIZE + TLV_HDR_SIZE);
    1018             : 
    1019             :         /* Build LSA body for an Extended Prefix TLV */
    1020           0 :         build_tlv_header(s, &exti->prefix.header);
    1021           0 :         stream_put(s, TLV_DATA(&exti->prefix.header), EXT_TLV_PREFIX_SIZE);
    1022             :         /* Then add Prefix SID SubTLV */
    1023           0 :         build_tlv(s, &exti->node_sid.header);
    1024             : }
    1025             : 
    1026             : /* Build an Extended Link Opaque LSA body for extended link TLV */
    1027           0 : static void ospf_ext_link_lsa_body_set(struct stream *s, struct ext_itf *exti)
    1028             : {
    1029           0 :         size_t size;
    1030             : 
    1031             :         /* Sanity check */
    1032           0 :         if ((exti == NULL)
    1033           0 :             || ((exti->stype != ADJ_SID) && (exti->stype != LAN_ADJ_SID)))
    1034             :                 return;
    1035             : 
    1036           0 :         if (exti->stype == ADJ_SID) {
    1037             :                 /* Adjust Extended Link TLV size for Adj. SID */
    1038           0 :                 size = EXT_TLV_LINK_SIZE + 2 * EXT_SUBTLV_ADJ_SID_SIZE
    1039             :                        + 2 * TLV_HDR_SIZE;
    1040           0 :                 if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
    1041           0 :                         size = size + EXT_SUBTLV_RMT_ITF_ADDR_SIZE
    1042             :                                + TLV_HDR_SIZE;
    1043           0 :                 TLV_LEN(exti->link) = htons(size);
    1044             : 
    1045             :                 /* Build LSA body for an Extended Link TLV with Adj. SID */
    1046           0 :                 build_tlv_header(s, &exti->link.header);
    1047           0 :                 stream_put(s, TLV_DATA(&exti->link.header), EXT_TLV_LINK_SIZE);
    1048             :                 /* then add Adjacency SubTLVs */
    1049           0 :                 build_tlv(s, &exti->adj_sid[1].header);
    1050           0 :                 build_tlv(s, &exti->adj_sid[0].header);
    1051             : 
    1052             :                 /* Add Cisco experimental SubTLV if interface is PtoP */
    1053           0 :                 if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
    1054           0 :                         build_tlv(s, &exti->rmt_itf_addr.header);
    1055             :         } else {
    1056             :                 /* Adjust Extended Link TLV size for LAN SID */
    1057           0 :                 size = EXT_TLV_LINK_SIZE
    1058             :                        + 2 * (EXT_SUBTLV_LAN_ADJ_SID_SIZE + TLV_HDR_SIZE);
    1059           0 :                 TLV_LEN(exti->link) = htons(size);
    1060             : 
    1061             :                 /* Build LSA body for an Extended Link TLV with LAN SID */
    1062           0 :                 build_tlv_header(s, &exti->link.header);
    1063           0 :                 stream_put(s, TLV_DATA(&exti->link.header), EXT_TLV_LINK_SIZE);
    1064             :                 /* then add LAN-Adjacency SubTLVs */
    1065           0 :                 build_tlv(s, &exti->lan_sid[1].header);
    1066           0 :                 build_tlv(s, &exti->lan_sid[0].header);
    1067             :         }
    1068             : }
    1069             : 
    1070             : /* Create new Extended Prefix opaque-LSA for every extended prefix */
    1071           0 : static struct ospf_lsa *ospf_ext_pref_lsa_new(struct ospf_area *area,
    1072             :                                               struct ext_itf *exti)
    1073             : {
    1074           0 :         struct stream *s;
    1075           0 :         struct lsa_header *lsah;
    1076           0 :         struct ospf_lsa *new = NULL;
    1077           0 :         struct ospf *top;
    1078           0 :         uint8_t options, lsa_type;
    1079           0 :         struct in_addr lsa_id;
    1080           0 :         struct in_addr router_id;
    1081           0 :         uint32_t tmp;
    1082           0 :         uint16_t length;
    1083             : 
    1084             :         /* Sanity Check */
    1085           0 :         if (exti == NULL)
    1086             :                 return NULL;
    1087             : 
    1088             :         /* Create a stream for LSA. */
    1089           0 :         s = stream_new(OSPF_MAX_LSA_SIZE);
    1090             : 
    1091             :         /* Prepare LSA Header */
    1092           0 :         lsah = (struct lsa_header *)STREAM_DATA(s);
    1093             : 
    1094           0 :         lsa_type = OspfEXT.scope;
    1095             : 
    1096             :         /*
    1097             :          * LSA ID is a variable number identifying different instances of
    1098             :          * Extended Prefix Opaque LSA from the same router see RFC 7684
    1099             :          */
    1100           0 :         tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
    1101           0 :         lsa_id.s_addr = htonl(tmp);
    1102             : 
    1103           0 :         options = OSPF_OPTION_O; /* Don't forget this :-) */
    1104             : 
    1105             :         /* Fix Options and Router ID depending of the flooding scope */
    1106           0 :         if ((OspfEXT.scope == OSPF_OPAQUE_AS_LSA) || (area == NULL)) {
    1107           0 :                 options = OSPF_OPTION_E;
    1108           0 :                 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
    1109           0 :                 router_id.s_addr = top ? top->router_id.s_addr : 0;
    1110             :         } else {
    1111           0 :                 options |= LSA_OPTIONS_GET(area); /* Get area default option */
    1112           0 :                 options |= LSA_OPTIONS_NSSA_GET(area);
    1113           0 :                 router_id = area->ospf->router_id;
    1114             :         }
    1115             : 
    1116             :         /* Set opaque-LSA header fields. */
    1117           0 :         lsa_header_set(s, options, lsa_type, lsa_id, router_id);
    1118             : 
    1119           0 :         osr_debug(
    1120             :                 "EXT (%s): LSA[Type%u:%pI4]: Create an Opaque-LSA Extended Prefix Opaque LSA instance",
    1121             :                 __func__, lsa_type, &lsa_id);
    1122             : 
    1123             :         /* Set opaque-LSA body fields. */
    1124           0 :         ospf_ext_pref_lsa_body_set(s, exti);
    1125             : 
    1126             :         /* Set length. */
    1127           0 :         length = stream_get_endp(s);
    1128           0 :         lsah->length = htons(length);
    1129             : 
    1130             :         /* Now, create an OSPF LSA instance. */
    1131           0 :         new = ospf_lsa_new_and_data(length);
    1132             : 
    1133             :         /* Segment Routing belongs only to default VRF */
    1134           0 :         new->vrf_id = VRF_DEFAULT;
    1135           0 :         new->area = area;
    1136           0 :         SET_FLAG(new->flags, OSPF_LSA_SELF);
    1137           0 :         memcpy(new->data, lsah, length);
    1138           0 :         stream_free(s);
    1139             : 
    1140           0 :         return new;
    1141             : }
    1142             : 
    1143             : /* Create new Extended Link opaque-LSA for every extended link TLV */
    1144           0 : static struct ospf_lsa *ospf_ext_link_lsa_new(struct ospf_area *area,
    1145             :                                               struct ext_itf *exti)
    1146             : {
    1147           0 :         struct stream *s;
    1148           0 :         struct lsa_header *lsah;
    1149           0 :         struct ospf_lsa *new = NULL;
    1150           0 :         uint8_t options, lsa_type;
    1151           0 :         struct in_addr lsa_id;
    1152           0 :         uint32_t tmp;
    1153           0 :         uint16_t length;
    1154             : 
    1155             :         /* Sanity Check */
    1156           0 :         if (exti == NULL)
    1157             :                 return NULL;
    1158             : 
    1159             :         /* Create a stream for LSA. */
    1160           0 :         s = stream_new(OSPF_MAX_LSA_SIZE);
    1161           0 :         lsah = (struct lsa_header *)STREAM_DATA(s);
    1162             : 
    1163           0 :         options = OSPF_OPTION_O;          /* Don't forget this :-) */
    1164           0 :         options |= LSA_OPTIONS_GET(area); /* Get area default option */
    1165           0 :         options |= LSA_OPTIONS_NSSA_GET(area);
    1166             :         /* Extended Link Opaque LSA are only flooded within an area */
    1167           0 :         lsa_type = OSPF_OPAQUE_AREA_LSA;
    1168             : 
    1169             :         /*
    1170             :          * LSA ID is a variable number identifying different instances of
    1171             :          * Extended Link Opaque LSA from the same router see RFC 7684
    1172             :          */
    1173           0 :         tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
    1174           0 :         lsa_id.s_addr = htonl(tmp);
    1175             : 
    1176           0 :         osr_debug(
    1177             :                 "EXT (%s) LSA[Type%u:%pI4]: Create an Opaque-LSA Extended Link Opaque LSA instance",
    1178             :                 __func__, lsa_type, &lsa_id);
    1179             : 
    1180             :         /* Set opaque-LSA header fields. */
    1181           0 :         lsa_header_set(s, options, lsa_type, lsa_id, area->ospf->router_id);
    1182             : 
    1183             :         /* Set opaque-LSA body fields. */
    1184           0 :         ospf_ext_link_lsa_body_set(s, exti);
    1185             : 
    1186             :         /* Set length. */
    1187           0 :         length = stream_get_endp(s);
    1188           0 :         lsah->length = htons(length);
    1189             : 
    1190             :         /* Now, create an OSPF LSA instance. */
    1191           0 :         new = ospf_lsa_new_and_data(length);
    1192             : 
    1193             :         /* Segment Routing belongs only to default VRF */
    1194           0 :         new->vrf_id = VRF_DEFAULT;
    1195           0 :         new->area = area;
    1196           0 :         SET_FLAG(new->flags, OSPF_LSA_SELF);
    1197           0 :         memcpy(new->data, lsah, length);
    1198           0 :         stream_free(s);
    1199             : 
    1200           0 :         return new;
    1201             : }
    1202             : 
    1203             : /*
    1204             :  * Process the origination of an Extended Prefix Opaque LSA
    1205             :  * for every extended prefix TLV
    1206             :  */
    1207           0 : static int ospf_ext_pref_lsa_originate1(struct ospf_area *area,
    1208             :                                         struct ext_itf *exti)
    1209             : {
    1210           0 :         struct ospf_lsa *new;
    1211           0 :         int rc = -1;
    1212             : 
    1213             : 
    1214             :         /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
    1215           0 :         new = ospf_ext_pref_lsa_new(area, exti);
    1216           0 :         if (new == NULL) {
    1217           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1218             :                           "EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
    1219           0 :                 return rc;
    1220             :         }
    1221             : 
    1222             :         /* Install this LSA into LSDB. */
    1223           0 :         if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
    1224           0 :                 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
    1225             :                           "EXT (%s): ospf_lsa_install() error", __func__);
    1226           0 :                 ospf_lsa_unlock(&new);
    1227           0 :                 return rc;
    1228             :         }
    1229             : 
    1230             :         /* Now this Extended Prefix Opaque LSA info parameter entry has
    1231             :          * associated LSA.
    1232             :          */
    1233           0 :         SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
    1234             : 
    1235             :         /* Update new LSA origination count. */
    1236           0 :         area->ospf->lsa_originate_count++;
    1237             : 
    1238             :         /* Flood new LSA through area. */
    1239           0 :         ospf_flood_through_area(area, NULL /*nbr */, new);
    1240             : 
    1241           0 :         osr_debug(
    1242             :                 "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSAExtended Prefix Opaque LSA: Area(%pI4), Link(%s)",
    1243             :                 __func__, new->data->type, &new->data->id,
    1244             :                 &area->area_id, exti->ifp->name);
    1245           0 :         if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
    1246           0 :                 ospf_lsa_header_dump(new->data);
    1247             : 
    1248           0 :         rc = 0;
    1249             : 
    1250             :         return rc;
    1251             : }
    1252             : 
    1253             : /*
    1254             :  * Process the origination of an Extended Link Opaque LSA
    1255             :  * for every extended link TLV
    1256             :  */
    1257           0 : static int ospf_ext_link_lsa_originate1(struct ospf_area *area,
    1258             :                                         struct ext_itf *exti)
    1259             : {
    1260           0 :         struct ospf_lsa *new;
    1261           0 :         int rc = -1;
    1262             : 
    1263             :         /* Create new Opaque-LSA/Extended Link Opaque LSA instance. */
    1264           0 :         new = ospf_ext_link_lsa_new(area, exti);
    1265           0 :         if (new == NULL) {
    1266           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1267             :                           "EXT (%s): ospf_ext_link_lsa_new() error", __func__);
    1268           0 :                 return rc;
    1269             :         }
    1270             : 
    1271             :         /* Install this LSA into LSDB. */
    1272           0 :         if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
    1273           0 :                 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
    1274             :                           "EXT (%s): ospf_lsa_install() error", __func__);
    1275           0 :                 ospf_lsa_unlock(&new);
    1276           0 :                 return rc;
    1277             :         }
    1278             : 
    1279             :         /* Now this link-parameter entry has associated LSA. */
    1280           0 :         SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
    1281             : 
    1282             :         /* Update new LSA origination count. */
    1283           0 :         area->ospf->lsa_originate_count++;
    1284             : 
    1285             :         /* Flood new LSA through area. */
    1286           0 :         ospf_flood_through_area(area, NULL /*nbr */, new);
    1287             : 
    1288           0 :         osr_debug(
    1289             :                 "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSA Extended Link Opaque LSA: Area(%pI4), Link(%s)",
    1290             :                 __func__, new->data->type, &new->data->id,
    1291             :                 &area->area_id, exti->ifp->name);
    1292           0 :         if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
    1293           0 :                 ospf_lsa_header_dump(new->data);
    1294             : 
    1295           0 :         rc = 0;
    1296             : 
    1297             :         return rc;
    1298             : }
    1299             : 
    1300             : /* Trigger the origination of Extended Prefix Opaque LSAs */
    1301           0 : static int ospf_ext_pref_lsa_originate(void *arg)
    1302             : {
    1303           0 :         struct ospf_area *area = (struct ospf_area *)arg;
    1304           0 :         struct listnode *node;
    1305           0 :         struct ext_itf *exti;
    1306           0 :         int rc = -1;
    1307             : 
    1308           0 :         if (!OspfEXT.enabled) {
    1309           0 :                 zlog_info(
    1310             :                         "EXT (%s): Segment Routing functionality is Disabled now",
    1311             :                         __func__);
    1312           0 :                 rc = 0; /* This is not an error case. */
    1313           0 :                 return rc;
    1314             :         }
    1315           0 :         osr_debug("EXT (%s): Start Originate Prefix LSA for area %pI4",
    1316             :                   __func__, &area->area_id);
    1317             : 
    1318             :         /* Check if Extended Prefix Opaque LSA is already engaged */
    1319           0 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
    1320             : 
    1321             :                 /* Process only Prefix SID */
    1322           0 :                 if (exti->stype != PREF_SID)
    1323           0 :                         continue;
    1324             : 
    1325             :                 /* Process only Extended Prefix with valid Area ID */
    1326           0 :                 if ((exti->area == NULL)
    1327           0 :                     || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
    1328           0 :                         continue;
    1329             : 
    1330           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
    1331           0 :                         if (CHECK_FLAG(exti->flags,
    1332             :                                        EXT_LPFLG_LSA_FORCED_REFRESH)) {
    1333           0 :                                 flog_warn(
    1334             :                                         EC_OSPF_EXT_LSA_UNEXPECTED,
    1335             :                                         "EXT (%s): Refresh instead of Originate",
    1336             :                                         __func__);
    1337           0 :                                 UNSET_FLAG(exti->flags,
    1338             :                                            EXT_LPFLG_LSA_FORCED_REFRESH);
    1339           0 :                                 ospf_ext_pref_lsa_schedule(exti,
    1340             :                                                            REFRESH_THIS_LSA);
    1341             :                         }
    1342           0 :                         continue;
    1343             :                 }
    1344             : 
    1345             :                 /* Ok, let's try to originate an LSA */
    1346           0 :                 osr_debug(
    1347             :                         "EXT (%s): Let's finally re-originate the LSA 7.0.0.%u for Itf %s", __func__, exti->instance,
    1348             :                         exti->ifp ? exti->ifp->name : "");
    1349           0 :                 ospf_ext_pref_lsa_originate1(area, exti);
    1350             :         }
    1351             : 
    1352           0 :         rc = 0;
    1353             :         return rc;
    1354             : }
    1355             : 
    1356             : /* Trigger the origination of Extended Link Opaque LSAs */
    1357           0 : static int ospf_ext_link_lsa_originate(void *arg)
    1358             : {
    1359           0 :         struct ospf_area *area = (struct ospf_area *)arg;
    1360           0 :         struct listnode *node;
    1361           0 :         struct ext_itf *exti;
    1362           0 :         int rc = -1;
    1363             : 
    1364           0 :         if (!OspfEXT.enabled) {
    1365           0 :                 zlog_info(
    1366             :                         "EXT (%s): Segment Routing functionality is Disabled now",
    1367             :                         __func__);
    1368           0 :                 rc = 0; /* This is not an error case. */
    1369           0 :                 return rc;
    1370             :         }
    1371             : 
    1372             :         /* Check if Extended Prefix Opaque LSA is already engaged */
    1373           0 :         for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
    1374             :                 /* Process only Adjacency or LAN SID */
    1375           0 :                 if (exti->stype == PREF_SID)
    1376           0 :                         continue;
    1377             : 
    1378             :                 /* Skip Inactive Extended Link */
    1379           0 :                 if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
    1380           0 :                         continue;
    1381             : 
    1382             :                 /* Process only Extended Link with valid Area ID */
    1383           0 :                 if ((exti->area == NULL)
    1384           0 :                     || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
    1385           0 :                         continue;
    1386             : 
    1387             :                 /* Check if LSA not already engaged */
    1388           0 :                 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
    1389           0 :                         if (CHECK_FLAG(exti->flags,
    1390             :                                        EXT_LPFLG_LSA_FORCED_REFRESH)) {
    1391           0 :                                 flog_warn(
    1392             :                                         EC_OSPF_EXT_LSA_UNEXPECTED,
    1393             :                                         "EXT (%s): Refresh instead of Originate",
    1394             :                                         __func__);
    1395           0 :                                 UNSET_FLAG(exti->flags,
    1396             :                                            EXT_LPFLG_LSA_FORCED_REFRESH);
    1397           0 :                                 ospf_ext_link_lsa_schedule(exti,
    1398             :                                                            REFRESH_THIS_LSA);
    1399             :                         }
    1400           0 :                         continue;
    1401             :                 }
    1402             : 
    1403             :                 /* Ok, let's try to originate an LSA */
    1404           0 :                 osr_debug(
    1405             :                         "EXT (%s): Let's finally reoriginate the LSA 8.0.0.%u for Itf %s through the Area %pI4", __func__,
    1406             :                         exti->instance,      exti->ifp ? exti->ifp->name : "-",
    1407             :                         &area->area_id);
    1408           0 :                 ospf_ext_link_lsa_originate1(area, exti);
    1409             :         }
    1410             : 
    1411           0 :         rc = 0;
    1412             :         return rc;
    1413             : }
    1414             : 
    1415             : /* Refresh an Extended Prefix Opaque LSA */
    1416           0 : static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa)
    1417             : {
    1418           0 :         struct ospf_lsa *new = NULL;
    1419           0 :         struct ospf_area *area = lsa->area;
    1420           0 :         struct ospf *top;
    1421           0 :         struct ext_itf *exti;
    1422             : 
    1423           0 :         if (!OspfEXT.enabled) {
    1424             :                 /*
    1425             :                  * This LSA must have flushed before due to Extended Prefix
    1426             :                  * Opaque LSA status change.
    1427             :                  * It seems a slip among routers in the routing domain.
    1428             :                  */
    1429           0 :                 zlog_info(
    1430             :                         "EXT (%s): Segment Routing functionality is Disabled",
    1431             :                         __func__);
    1432             :                 /* Flush it anyway. */
    1433           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1434             :         }
    1435             : 
    1436             :         /* Lookup this lsa corresponding Extended parameters */
    1437           0 :         exti = lookup_ext_by_instance(lsa);
    1438           0 :         if (exti == NULL) {
    1439           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1440             :                           "EXT (%s): Invalid parameter LSA ID", __func__);
    1441             :                 /* Flush it anyway. */
    1442           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1443             :         }
    1444             : 
    1445             :         /* Check if Interface was not disable in the interval */
    1446           0 :         if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
    1447           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1448             :                           "EXT (%s): Interface was Disabled: Flush it!",
    1449             :                           __func__);
    1450             :                 /* Flush it anyway. */
    1451           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1452             :         }
    1453             : 
    1454             :         /* If the lsa's age reached to MaxAge, start flushing procedure. */
    1455           0 :         if (IS_LSA_MAXAGE(lsa)) {
    1456           0 :                 if (exti)
    1457           0 :                         UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
    1458           0 :                 ospf_opaque_lsa_flush_schedule(lsa);
    1459           0 :                 return NULL;
    1460             :         }
    1461             : 
    1462             :         /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
    1463           0 :         new = ospf_ext_pref_lsa_new(area, exti);
    1464             : 
    1465           0 :         if (new == NULL) {
    1466           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1467             :                           "EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
    1468           0 :                 return NULL;
    1469             :         }
    1470           0 :         new->data->ls_seqnum = lsa_seqnum_increment(lsa);
    1471             : 
    1472             :         /*
    1473             :          * Install this LSA into LSDB
    1474             :          * Given "lsa" will be freed in the next function
    1475             :          * As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use
    1476             :          * ospf_lookup() to get ospf instance
    1477             :          */
    1478           0 :         if (area)
    1479           0 :                 top = area->ospf;
    1480             :         else
    1481           0 :                 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
    1482             : 
    1483           0 :         if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
    1484           0 :                 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
    1485             :                           "EXT (%s): ospf_lsa_install() error", __func__);
    1486           0 :                 ospf_lsa_unlock(&new);
    1487           0 :                 return NULL;
    1488             :         }
    1489             : 
    1490             :         /* Flood updated LSA through the Prefix Area according to the RFC7684 */
    1491           0 :         ospf_flood_through_area(area, NULL /*nbr */, new);
    1492             : 
    1493             :         /* Debug logging. */
    1494           0 :         osr_debug("EXT (%s): LSA[Type%u:%pI4] Refresh Extended Prefix LSA",
    1495             :                   __func__, new->data->type, &new->data->id);
    1496           0 :         if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
    1497           0 :                 ospf_lsa_header_dump(new->data);
    1498             : 
    1499             : 
    1500           0 :         return new;
    1501             : }
    1502             : 
    1503             : /* Refresh an Extended Link Opaque LSA */
    1504           0 : static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa)
    1505             : {
    1506           0 :         struct ext_itf *exti;
    1507           0 :         struct ospf_area *area = lsa->area;
    1508           0 :         struct ospf *top = area->ospf;
    1509           0 :         struct ospf_lsa *new = NULL;
    1510             : 
    1511           0 :         if (!OspfEXT.enabled) {
    1512             :                 /*
    1513             :                  * This LSA must have flushed before due to OSPF-SR status
    1514             :                  * change. It seems a slip among routers in the routing domain.
    1515             :                  */
    1516           0 :                 zlog_info("EXT (%s): Segment Routing functionality is Disabled",
    1517             :                           __func__);
    1518             :                 /* Flush it anyway. */
    1519           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1520             :         }
    1521             : 
    1522             :         /* Lookup this LSA corresponding Extended parameters */
    1523           0 :         exti = lookup_ext_by_instance(lsa);
    1524           0 :         if (exti == NULL) {
    1525           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1526             :                           "EXT (%s): Invalid parameter LSA ID", __func__);
    1527             :                 /* Flush it anyway. */
    1528           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1529             :         }
    1530             : 
    1531             :         /* Check if Interface was not disable in the interval */
    1532           0 :         if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
    1533           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1534             :                           "EXT (%s): Interface was Disabled: Flush it!",
    1535             :                           __func__);
    1536           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1537             :         }
    1538             : 
    1539             :         /* If the lsa's age reached to MaxAge, start flushing procedure */
    1540           0 :         if (IS_LSA_MAXAGE(lsa)) {
    1541           0 :                 if (exti)
    1542           0 :                         UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
    1543           0 :                 ospf_opaque_lsa_flush_schedule(lsa);
    1544           0 :                 return NULL;
    1545             :         }
    1546             : 
    1547             :         /* Create new Opaque-LSA/Extended Link instance */
    1548           0 :         new = ospf_ext_link_lsa_new(area, exti);
    1549           0 :         if (new == NULL) {
    1550           0 :                 flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1551             :                           "EXT (%s): Error creating new LSA", __func__);
    1552           0 :                 return NULL;
    1553             :         }
    1554           0 :         new->data->ls_seqnum = lsa_seqnum_increment(lsa);
    1555             : 
    1556             :         /* Install this LSA into LSDB. */
    1557             :         /* Given "lsa" will be freed in the next function */
    1558           0 :         if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
    1559           0 :                 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
    1560             :                           "EXT (%s): Error installing new LSA", __func__);
    1561           0 :                 ospf_lsa_unlock(&new);
    1562           0 :                 return NULL;
    1563             :         }
    1564             : 
    1565             :         /* Flood updated LSA through the link Area according to the RFC7684 */
    1566           0 :         ospf_flood_through_area(area, NULL /*nbr */, new);
    1567             : 
    1568             :         /* Debug logging. */
    1569           0 :         osr_debug("EXT (%s): LSA[Type%u:%pI4]: Refresh Extended Link LSA",
    1570             :                   __func__, new->data->type, &new->data->id);
    1571           0 :         if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
    1572           0 :                 ospf_lsa_header_dump(new->data);
    1573             : 
    1574           0 :         return new;
    1575             : }
    1576             : 
    1577             : /* Schedule Extended Prefix Opaque LSA origination/refreshment/flushing */
    1578           0 : static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
    1579             :                                        enum lsa_opcode opcode)
    1580             : {
    1581           0 :         struct ospf_lsa lsa;
    1582           0 :         struct lsa_header lsah;
    1583           0 :         struct ospf *top;
    1584           0 :         uint32_t tmp;
    1585             : 
    1586           0 :         memset(&lsa, 0, sizeof(lsa));
    1587           0 :         memset(&lsah, 0, sizeof(lsah));
    1588             : 
    1589             :         /* Sanity Check */
    1590           0 :         if (exti == NULL)
    1591           0 :                 return;
    1592             : 
    1593             :         /* Check if the corresponding link is ready to be flooded */
    1594           0 :         if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
    1595             :                 return;
    1596             : 
    1597           0 :         osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
    1598             :                   opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
    1599             :                   opcode == REFRESH_THIS_LSA ? "Refresh" : "",
    1600             :                   opcode == FLUSH_THIS_LSA ? "Flush" : "",
    1601             :                   exti->ifp ? exti->ifp->name : "-");
    1602             : 
    1603             :         /* Verify Area */
    1604           0 :         if (exti->area == NULL) {
    1605           0 :                 osr_debug(
    1606             :                         "EXT (%s): Area is not yet set. Try to use Backbone Area",
    1607             :                         __func__);
    1608             : 
    1609           0 :                 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
    1610           0 :                 struct in_addr backbone = {.s_addr = INADDR_ANY};
    1611           0 :                 exti->area = ospf_area_lookup_by_area_id(top, backbone);
    1612           0 :                 if (exti->area == NULL) {
    1613           0 :                         flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1614             :                                   "EXT (%s): Unable to set Area", __func__);
    1615           0 :                         return;
    1616             :                 }
    1617             :         }
    1618             :         /* Set LSA header information */
    1619           0 :         lsa.area = exti->area;
    1620           0 :         lsa.data = &lsah;
    1621           0 :         lsah.type = OSPF_OPAQUE_AREA_LSA;
    1622           0 :         tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
    1623           0 :         lsah.id.s_addr = htonl(tmp);
    1624             : 
    1625           0 :         switch (opcode) {
    1626           0 :         case REORIGINATE_THIS_LSA:
    1627           0 :                 ospf_opaque_lsa_reoriginate_schedule(
    1628             :                         (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
    1629             :                         OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
    1630           0 :                 break;
    1631           0 :         case REFRESH_THIS_LSA:
    1632           0 :                 ospf_opaque_lsa_refresh_schedule(&lsa);
    1633           0 :                 break;
    1634           0 :         case FLUSH_THIS_LSA:
    1635           0 :                 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
    1636           0 :                 ospf_opaque_lsa_flush_schedule(&lsa);
    1637           0 :                 break;
    1638             :         }
    1639             : }
    1640             : 
    1641             : /* Schedule Extended Link Opaque LSA origination/refreshment/flushing */
    1642           0 : static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
    1643             :                                        enum lsa_opcode opcode)
    1644             : {
    1645           0 :         struct ospf_lsa lsa;
    1646           0 :         struct lsa_header lsah;
    1647           0 :         struct ospf *top;
    1648           0 :         uint32_t tmp;
    1649             : 
    1650           0 :         memset(&lsa, 0, sizeof(lsa));
    1651           0 :         memset(&lsah, 0, sizeof(lsah));
    1652             : 
    1653             :         /* Sanity Check */
    1654           0 :         if (exti == NULL)
    1655           0 :                 return;
    1656             : 
    1657             :         /* Check if the corresponding link is ready to be flooded */
    1658           0 :         if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
    1659             :                 return;
    1660             : 
    1661           0 :         osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
    1662             :                   opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
    1663             :                   opcode == REFRESH_THIS_LSA ? "Refresh" : "",
    1664             :                   opcode == FLUSH_THIS_LSA ? "Flush" : "",
    1665             :                   exti->ifp ? exti->ifp->name : "-");
    1666             : 
    1667             :         /* Verify Area */
    1668           0 :         if (exti->area == NULL) {
    1669           0 :                 osr_debug(
    1670             :                         "EXT (%s): Area is not yet set. Try to use Backbone Area",
    1671             :                         __func__);
    1672             : 
    1673           0 :                 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
    1674           0 :                 struct in_addr backbone = {.s_addr = INADDR_ANY};
    1675           0 :                 exti->area = ospf_area_lookup_by_area_id(top, backbone);
    1676           0 :                 if (exti->area == NULL) {
    1677           0 :                         flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED,
    1678             :                                   "EXT (%s): Unable to set Area", __func__);
    1679           0 :                         return;
    1680             :                 }
    1681             :         }
    1682             :         /* Set LSA header information */
    1683           0 :         lsa.area = exti->area;
    1684           0 :         lsa.data = &lsah;
    1685           0 :         lsah.type = OSPF_OPAQUE_AREA_LSA;
    1686           0 :         tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
    1687           0 :         lsah.id.s_addr = htonl(tmp);
    1688             : 
    1689           0 :         switch (opcode) {
    1690           0 :         case REORIGINATE_THIS_LSA:
    1691           0 :                 ospf_opaque_lsa_reoriginate_schedule(
    1692             :                         (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
    1693             :                         OPAQUE_TYPE_EXTENDED_LINK_LSA);
    1694           0 :                 break;
    1695           0 :         case REFRESH_THIS_LSA:
    1696           0 :                 ospf_opaque_lsa_refresh_schedule(&lsa);
    1697           0 :                 break;
    1698           0 :         case FLUSH_THIS_LSA:
    1699           0 :                 ospf_opaque_lsa_flush_schedule(&lsa);
    1700           0 :                 break;
    1701             :         }
    1702             : }
    1703             : 
    1704             : /* Schedule Extended Link or Prefix depending of the Type of LSA */
    1705           0 : static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
    1706             : {
    1707             : 
    1708           0 :         if (exti->stype == PREF_SID)
    1709           0 :                 ospf_ext_pref_lsa_schedule(exti, op);
    1710             :         else
    1711           0 :                 ospf_ext_link_lsa_schedule(exti, op);
    1712           0 : }
    1713             : 
    1714             : /*
    1715             :  * ------------------------------------
    1716             :  * Following are vty show functions.
    1717             :  * ------------------------------------
    1718             :  */
    1719             : 
    1720             : #define check_tlv_size(size, msg)                                              \
    1721             :         do {                                                                   \
    1722             :                 if (ntohs(tlvh->length) != size) {                             \
    1723             :                         vty_out(vty, "  Wrong %s TLV size: %d(%d). Abort!\n",  \
    1724             :                                 msg, ntohs(tlvh->length), size);               \
    1725             :                         return size + TLV_HDR_SIZE;                            \
    1726             :                 }                                                              \
    1727             :         } while (0)
    1728             : 
    1729             : /* Cisco experimental SubTLV */
    1730           0 : static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
    1731             :                                                struct tlv_header *tlvh)
    1732             : {
    1733           0 :         struct ext_subtlv_rmt_itf_addr *top =
    1734             :                 (struct ext_subtlv_rmt_itf_addr *)tlvh;
    1735             : 
    1736           0 :         check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address");
    1737             : 
    1738           0 :         vty_out(vty,
    1739             :                 "  Remote Interface Address Sub-TLV: Length %u\n   Address: %pI4\n",
    1740           0 :                 ntohs(top->header.length), &top->value);
    1741             : 
    1742           0 :         return TLV_SIZE(tlvh);
    1743             : }
    1744             : 
    1745             : /* Adjacency SID SubTLV */
    1746           0 : static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
    1747             :                                           struct tlv_header *tlvh)
    1748             : {
    1749           0 :         struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh;
    1750             : 
    1751           0 :         check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID");
    1752             : 
    1753           0 :         vty_out(vty,
    1754             :                 "  Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
    1755           0 :                 ntohs(top->header.length), top->flags, top->mtid, top->weight,
    1756             :                 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
    1757             :                                                                      : "Index",
    1758           0 :                 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
    1759           0 :                         ? GET_LABEL(ntohl(top->value))
    1760           0 :                         : ntohl(top->value));
    1761             : 
    1762           0 :         return TLV_SIZE(tlvh);
    1763             : }
    1764             : 
    1765             : /* LAN Adjacency SubTLV */
    1766           0 : static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
    1767             :                                               struct tlv_header *tlvh)
    1768             : {
    1769           0 :         struct ext_subtlv_lan_adj_sid *top =
    1770             :                 (struct ext_subtlv_lan_adj_sid *)tlvh;
    1771             : 
    1772           0 :         check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID");
    1773             : 
    1774           0 :         vty_out(vty,
    1775             :                 "  LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
    1776           0 :                 ntohs(top->header.length), top->flags, top->mtid, top->weight,
    1777             :                 &top->neighbor_id,
    1778             :                 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
    1779             :                                                                      : "Index",
    1780           0 :                 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
    1781           0 :                         ? GET_LABEL(ntohl(top->value))
    1782           0 :                         : ntohl(top->value));
    1783             : 
    1784           0 :         return TLV_SIZE(tlvh);
    1785             : }
    1786             : 
    1787           0 : static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
    1788             :                                      size_t buf_size)
    1789             : {
    1790           0 :         if (TLV_SIZE(tlvh) > buf_size) {
    1791           0 :                 vty_out(vty, "    TLV size %d exceeds buffer size. Abort!",
    1792           0 :                         TLV_SIZE(tlvh));
    1793           0 :                 return buf_size;
    1794             :         }
    1795             : 
    1796           0 :         vty_out(vty, "    Unknown TLV: [type(0x%x), length(0x%x)]\n",
    1797           0 :                 ntohs(tlvh->type), ntohs(tlvh->length));
    1798             : 
    1799           0 :         return TLV_SIZE(tlvh);
    1800             : }
    1801             : 
    1802             : /* Extended Link Sub TLVs */
    1803           0 : static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
    1804             :                                    size_t buf_size)
    1805             : {
    1806           0 :         struct ext_tlv_link *top = (struct ext_tlv_link *)ext;
    1807           0 :         struct tlv_header *tlvh;
    1808           0 :         uint16_t length = ntohs(top->header.length);
    1809           0 :         uint16_t sum = 0;
    1810             : 
    1811             :         /* Verify that TLV length is valid against remaining buffer size */
    1812           0 :         if (length > buf_size) {
    1813           0 :                 vty_out(vty,
    1814             :                         "  Extended Link TLV size %d exceeds buffer size. Abort!\n",
    1815             :                         length);
    1816           0 :                 return buf_size;
    1817             :         }
    1818             : 
    1819           0 :         vty_out(vty,
    1820             :                 "  Extended Link TLV: Length %u\n  Link Type: 0x%x\n"
    1821             :                 "  Link ID: %pI4\n",
    1822           0 :                 ntohs(top->header.length), top->link_type,
    1823             :                 &top->link_id);
    1824           0 :         vty_out(vty, "     Link data: %pI4\n", &top->link_data);
    1825             : 
    1826             :         /* Skip Extended TLV and parse sub-TLVs */
    1827           0 :         length -= EXT_TLV_LINK_SIZE;
    1828           0 :         tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
    1829             :                                      + EXT_TLV_LINK_SIZE);
    1830           0 :         for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
    1831           0 :                 switch (ntohs(tlvh->type)) {
    1832           0 :                 case EXT_SUBTLV_ADJ_SID:
    1833           0 :                         sum += show_vty_ext_link_adj_sid(vty, tlvh);
    1834           0 :                         break;
    1835           0 :                 case EXT_SUBTLV_LAN_ADJ_SID:
    1836           0 :                         sum += show_vty_ext_link_lan_adj_sid(vty, tlvh);
    1837           0 :                         break;
    1838           0 :                 case EXT_SUBTLV_RMT_ITF_ADDR:
    1839           0 :                         sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh);
    1840           0 :                         break;
    1841           0 :                 default:
    1842           0 :                         sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
    1843           0 :                         break;
    1844             :                 }
    1845             :         }
    1846             : 
    1847           0 :         return sum + sizeof(struct ext_tlv_link);
    1848             : }
    1849             : 
    1850             : /* Extended Link TLVs */
    1851           0 : static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json,
    1852             :                                     struct ospf_lsa *lsa)
    1853             : {
    1854           0 :         struct lsa_header *lsah = lsa->data;
    1855           0 :         struct tlv_header *tlvh;
    1856           0 :         uint16_t length = 0, sum = 0;
    1857             : 
    1858           0 :         if (json)
    1859             :                 return;
    1860             : 
    1861             :         /* Initialize TLV browsing */
    1862           0 :         length = lsa->size - OSPF_LSA_HEADER_SIZE;
    1863             : 
    1864           0 :         for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
    1865           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1866           0 :                 switch (ntohs(tlvh->type)) {
    1867           0 :                 case EXT_TLV_LINK:
    1868           0 :                         sum += show_vty_link_info(vty, tlvh, length - sum);
    1869           0 :                         break;
    1870           0 :                 default:
    1871           0 :                         sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
    1872           0 :                         break;
    1873             :                 }
    1874             :         }
    1875             : }
    1876             : 
    1877             : /* Prefix SID SubTLV */
    1878           0 : static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
    1879             :                                            struct tlv_header *tlvh)
    1880             : {
    1881           0 :         struct ext_subtlv_prefix_sid *top =
    1882             :                 (struct ext_subtlv_prefix_sid *)tlvh;
    1883             : 
    1884           0 :         check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID");
    1885             : 
    1886           0 :         vty_out(vty,
    1887             :                 "  Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
    1888           0 :                 ntohs(top->header.length), top->algorithm, top->flags,
    1889           0 :                 top->mtid,
    1890             :                 CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
    1891             :                                                                    : "Index",
    1892           0 :                 CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
    1893           0 :                         ? GET_LABEL(ntohl(top->value))
    1894           0 :                         : ntohl(top->value));
    1895             : 
    1896           0 :         return TLV_SIZE(tlvh);
    1897             : }
    1898             : 
    1899             : /* Extended Prefix SubTLVs */
    1900           0 : static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
    1901             :                                    size_t buf_size)
    1902             : {
    1903           0 :         struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext;
    1904           0 :         struct tlv_header *tlvh;
    1905           0 :         uint16_t length = ntohs(top->header.length);
    1906           0 :         uint16_t sum = 0;
    1907             : 
    1908             :         /* Verify that TLV length is valid against remaining buffer size */
    1909           0 :         if (length > buf_size) {
    1910           0 :                 vty_out(vty,
    1911             :                         "  Extended Link TLV size %d exceeds buffer size. Abort!\n",
    1912             :                         length);
    1913           0 :                 return buf_size;
    1914             :         }
    1915             : 
    1916           0 :         vty_out(vty,
    1917             :                 "  Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
    1918             :                 "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
    1919           0 :                 ntohs(top->header.length), top->route_type, top->af, top->flags,
    1920           0 :                 &top->address, top->pref_length);
    1921             : 
    1922             :         /* Skip Extended Prefix TLV and parse sub-TLVs */
    1923           0 :         length -= EXT_TLV_PREFIX_SIZE;
    1924           0 :         tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
    1925             :                                      + EXT_TLV_PREFIX_SIZE);
    1926           0 :         for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
    1927           0 :                 switch (ntohs(tlvh->type)) {
    1928           0 :                 case EXT_SUBTLV_PREFIX_SID:
    1929           0 :                         sum += show_vty_ext_pref_pref_sid(vty, tlvh);
    1930           0 :                         break;
    1931           0 :                 default:
    1932           0 :                         sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
    1933           0 :                         break;
    1934             :                 }
    1935             :         }
    1936             : 
    1937           0 :         return sum + sizeof(struct ext_tlv_prefix);
    1938             : }
    1939             : 
    1940             : /* Extended Prefix TLVs */
    1941           0 : static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json,
    1942             :                                     struct ospf_lsa *lsa)
    1943             : {
    1944           0 :         struct lsa_header *lsah = lsa->data;
    1945           0 :         struct tlv_header *tlvh;
    1946           0 :         uint16_t length = 0, sum = 0;
    1947             : 
    1948           0 :         if (json)
    1949             :                 return;
    1950             : 
    1951             :         /* Initialize TLV browsing */
    1952           0 :         length = lsa->size - OSPF_LSA_HEADER_SIZE;
    1953             : 
    1954           0 :         for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
    1955           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1956           0 :                 switch (ntohs(tlvh->type)) {
    1957           0 :                 case EXT_TLV_PREFIX:
    1958           0 :                         sum += show_vty_pref_info(vty, tlvh, length - sum);
    1959           0 :                         break;
    1960           0 :                 default:
    1961           0 :                         sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
    1962           0 :                         break;
    1963             :                 }
    1964             :         }
    1965             : }

Generated by: LCOV version v1.16-topotato