back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_sr.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 41 1298 3.2 %
Date: 2023-02-24 18:38:32 Functions: 5 64 7.8 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of Segment Routing
       3             :  * as per RFC 8665 - OSPF Extensions for Segment Routing
       4             :  * and RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
       5             :  *
       6             :  * Module name: Segment Routing
       7             :  *
       8             :  * Author: Olivier Dugeon <olivier.dugeon@orange.com>
       9             :  * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
      10             :  *
      11             :  * Copyright (C) 2016 - 2020 Orange Labs http://www.orange.com
      12             :  *
      13             :  * This program is free software; you can redistribute it and/or modify it
      14             :  * under the terms of the GNU General Public License as published by the Free
      15             :  * Software Foundation; either version 2 of the License, or (at your option)
      16             :  * any later version.
      17             :  *
      18             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      19             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      20             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      21             :  * more details.
      22             :  *
      23             :  * You should have received a copy of the GNU General Public License along
      24             :  * with this program; see the file COPYING; if not, write to the Free Software
      25             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      26             :  */
      27             : 
      28             : #ifdef HAVE_CONFIG_H
      29             : #include "config.h"
      30             : #endif
      31             : 
      32             : #include <math.h>
      33             : #include <stdio.h>
      34             : #include <stdlib.h>
      35             : #include <zebra.h>
      36             : 
      37             : #include "printfrr.h"
      38             : #include "command.h"
      39             : #include "hash.h"
      40             : #include "if.h"
      41             : #include "if.h"
      42             : #include "jhash.h"
      43             : #include "libospf.h" /* for ospf interface types */
      44             : #include "linklist.h"
      45             : #include "log.h"
      46             : #include "memory.h"
      47             : #include "monotime.h"
      48             : #include "network.h"
      49             : #include "prefix.h"
      50             : #include "sockunion.h" /* for inet_aton() */
      51             : #include "stream.h"
      52             : #include "table.h"
      53             : #include "thread.h"
      54             : #include "vty.h"
      55             : #include "zclient.h"
      56             : #include "sbuf.h"
      57             : #include <lib/json.h>
      58             : #include "ospf_errors.h"
      59             : 
      60             : #include "ospfd/ospfd.h"
      61             : #include "ospfd/ospf_interface.h"
      62             : #include "ospfd/ospf_ism.h"
      63             : #include "ospfd/ospf_asbr.h"
      64             : #include "ospfd/ospf_lsa.h"
      65             : #include "ospfd/ospf_lsdb.h"
      66             : #include "ospfd/ospf_neighbor.h"
      67             : #include "ospfd/ospf_nsm.h"
      68             : #include "ospfd/ospf_flood.h"
      69             : #include "ospfd/ospf_packet.h"
      70             : #include "ospfd/ospf_spf.h"
      71             : #include "ospfd/ospf_dump.h"
      72             : #include "ospfd/ospf_route.h"
      73             : #include "ospfd/ospf_ase.h"
      74             : #include "ospfd/ospf_sr.h"
      75             : #include "ospfd/ospf_ri.h"
      76             : #include "ospfd/ospf_ext.h"
      77             : #include "ospfd/ospf_zebra.h"
      78             : 
      79             : /*
      80             :  * Global variable to manage Segment Routing on this node.
      81             :  * Note that all parameter values are stored in network byte order.
      82             :  */
      83             : static struct ospf_sr_db OspfSR;
      84             : static void ospf_sr_register_vty(void);
      85             : static inline void del_adj_sid(struct sr_nhlfe nhlfe);
      86             : static int ospf_sr_start(struct ospf *ospf);
      87             : 
      88             : /*
      89             :  * Segment Routing Data Base functions
      90             :  */
      91             : 
      92             : /* Hash function for Segment Routing entry */
      93           0 : static unsigned int sr_hash(const void *p)
      94             : {
      95           0 :         const struct in_addr *rid = p;
      96             : 
      97           0 :         return jhash_1word(rid->s_addr, 0);
      98             : }
      99             : 
     100             : /* Compare 2 Router ID hash entries based on SR Node */
     101           0 : static bool sr_cmp(const void *p1, const void *p2)
     102             : {
     103           0 :         const struct sr_node *srn = p1;
     104           0 :         const struct in_addr *rid = p2;
     105             : 
     106           0 :         return IPV4_ADDR_SAME(&srn->adv_router, rid);
     107             : }
     108             : 
     109             : /* Functions to remove an SR Link */
     110           0 : static void del_sr_link(void *val)
     111             : {
     112           0 :         struct sr_link *srl = (struct sr_link *)val;
     113             : 
     114           0 :         del_adj_sid(srl->nhlfe[0]);
     115           0 :         del_adj_sid(srl->nhlfe[1]);
     116           0 :         XFREE(MTYPE_OSPF_SR_PARAMS, val);
     117           0 : }
     118             : 
     119             : /* Functions to remove an SR Prefix */
     120           0 : static void del_sr_pref(void *val)
     121             : {
     122           0 :         struct sr_prefix *srp = (struct sr_prefix *)val;
     123             : 
     124           0 :         ospf_zebra_delete_prefix_sid(srp);
     125           0 :         XFREE(MTYPE_OSPF_SR_PARAMS, val);
     126           0 : }
     127             : 
     128             : /* Allocate new Segment Routine node */
     129           0 : static struct sr_node *sr_node_new(struct in_addr *rid)
     130             : {
     131             : 
     132           0 :         if (rid == NULL)
     133             :                 return NULL;
     134             : 
     135           0 :         struct sr_node *new;
     136             : 
     137             :         /* Allocate Segment Routing node memory */
     138           0 :         new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_node));
     139             : 
     140             :         /* Default Algorithm, SRGB and MSD */
     141           0 :         for (int i = 0; i < ALGORITHM_COUNT; i++)
     142           0 :                 new->algo[i] = SR_ALGORITHM_UNSET;
     143             : 
     144           0 :         new->srgb.range_size = 0;
     145           0 :         new->srgb.lower_bound = 0;
     146           0 :         new->msd = 0;
     147             : 
     148             :         /* Create Link, Prefix and Range TLVs list */
     149           0 :         new->ext_link = list_new();
     150           0 :         new->ext_prefix = list_new();
     151           0 :         new->ext_link->del = del_sr_link;
     152           0 :         new->ext_prefix->del = del_sr_pref;
     153             : 
     154           0 :         IPV4_ADDR_COPY(&new->adv_router, rid);
     155           0 :         new->neighbor = NULL;
     156           0 :         new->instance = 0;
     157             : 
     158           0 :         osr_debug("  |-  Created new SR node for %pI4", &new->adv_router);
     159             :         return new;
     160             : }
     161             : 
     162             : /* Supposed to be used for testing */
     163           0 : struct sr_node *ospf_sr_node_create(struct in_addr *rid)
     164             : {
     165           0 :         struct sr_node *srn;
     166             : 
     167           0 :         srn = hash_get(OspfSR.neighbors, (void *)rid, (void *)sr_node_new);
     168             : 
     169           0 :         return srn;
     170             : }
     171             : 
     172             : /* Delete Segment Routing node */
     173           0 : static void sr_node_del(struct sr_node *srn)
     174             : {
     175             :         /* Sanity Check */
     176           0 :         if (srn == NULL)
     177             :                 return;
     178             : 
     179           0 :         osr_debug("  |- Delete SR node for %pI4", &srn->adv_router);
     180             : 
     181             :         /* Clean Extended Link */
     182           0 :         list_delete(&srn->ext_link);
     183             : 
     184             :         /* Clean Prefix List */
     185           0 :         list_delete(&srn->ext_prefix);
     186             : 
     187           0 :         XFREE(MTYPE_OSPF_SR_PARAMS, srn);
     188             : }
     189             : 
     190             : /* Get SR Node for a given nexthop */
     191           0 : static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf,
     192             :                                               struct in_addr nexthop)
     193             : {
     194           0 :         struct ospf_interface *oi = NULL;
     195           0 :         struct ospf_neighbor *nbr = NULL;
     196           0 :         struct listnode *node;
     197           0 :         struct route_node *rn;
     198           0 :         struct sr_node *srn;
     199           0 :         bool found;
     200             : 
     201             :         /* Sanity check */
     202           0 :         if (OspfSR.neighbors == NULL)
     203             :                 return NULL;
     204             : 
     205           0 :         osr_debug("      |-  Search SR-Node for nexthop %pI4", &nexthop);
     206             : 
     207             :         /* First, search neighbor Router ID for this nexthop */
     208           0 :         found = false;
     209           0 :         for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
     210           0 :                 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
     211           0 :                         nbr = rn->info;
     212           0 :                         if ((nbr) && (IPV4_ADDR_SAME(&nexthop, &nbr->src))) {
     213             :                                 found = true;
     214             :                                 break;
     215             :                         }
     216             :                 }
     217           0 :                 if (found)
     218             :                         break;
     219             :         }
     220             : 
     221           0 :         if (!found)
     222             :                 return NULL;
     223             : 
     224           0 :         osr_debug("      |-  Found nexthop Router ID %pI4", &nbr->router_id);
     225             : 
     226             :         /* Then, search SR Node */
     227           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, &nbr->router_id);
     228             : 
     229           0 :         return srn;
     230             : }
     231             : 
     232             : /*
     233             :  * Segment Routing Local Block management functions
     234             :  */
     235             : 
     236             : /**
     237             :  * It is necessary to known which label is already allocated to manage the range
     238             :  * of SRLB. This is particular useful when an interface flap (goes up / down
     239             :  * frequently). Here, SR will release and then allocate label for the Adjacency
     240             :  * for each concerned interface. If we don't care, there is a risk to run out of
     241             :  * label.
     242             :  *
     243             :  * For that purpose, a similar principle as already provided to manage chunk of
     244             :  * label is proposed. But, here, the label chunk has not a fix range of 64
     245             :  * labels that could be easily manage with a single variable of 64 bits size.
     246             :  * So, used_mark is used as a bit wise to mark label reserved (bit set) or not
     247             :  * (bit unset). Its size is equal to the number of label of the SRLB range round
     248             :  * up to 64 bits.
     249             :  *
     250             :  *  - sr__local_block_init() computes the number of 64 bits variables that are
     251             :  *    needed to manage the SRLB range and allocates this number.
     252             :  *  - ospf_sr_local_block_request_label() pick up the first available label and
     253             :  *    set corresponding bit
     254             :  *  - ospf_sr_local_block_release_label() release label by reseting the
     255             :  *    corresponding bit and set the next label to the first free position
     256             :  */
     257             : 
     258             : /**
     259             :  * Initialize Segment Routing Local Block from SRDB configuration and reserve
     260             :  * block of bits to manage label allocation.
     261             :  *
     262             :  * @param lower_bound   The lower bound of the SRLB range
     263             :  * @param upper_bound   The upper bound of the SRLB range
     264             :  *
     265             :  * @return              0 on success, -1 otherwise
     266             :  */
     267           0 : static int sr_local_block_init(uint32_t lower_bound, uint32_t upper_bound)
     268             : {
     269           0 :         struct sr_local_block *srlb = &OspfSR.srlb;
     270           0 :         uint32_t size;
     271             : 
     272             :         /* Check if SRLB is not already configured */
     273           0 :         if (srlb->reserved)
     274             :                 return 0;
     275             : 
     276             :         /*
     277             :          * Request SRLB to the label manager. If the allocation fails, return
     278             :          * an error to disable SR until a new SRLB is successfully allocated.
     279             :          */
     280           0 :         size = upper_bound - lower_bound + 1;
     281           0 :         if (ospf_zebra_request_label_range(lower_bound, size)) {
     282           0 :                 zlog_err("SR: Error reserving SRLB [%u/%u] %u labels",
     283             :                          lower_bound, upper_bound, size);
     284           0 :                 return -1;
     285             :         }
     286             : 
     287           0 :         osr_debug("SR: Got new SRLB [%u/%u], %u labels", lower_bound,
     288             :                   upper_bound, size);
     289             : 
     290             :         /* Initialize the SRLB */
     291           0 :         srlb->start = lower_bound;
     292           0 :         srlb->end = upper_bound;
     293           0 :         srlb->current = 0;
     294             : 
     295             :         /* Compute the needed Used Mark number and allocate them */
     296           0 :         srlb->max_block = size / SRLB_BLOCK_SIZE;
     297           0 :         if ((size % SRLB_BLOCK_SIZE) != 0)
     298           0 :                 srlb->max_block++;
     299           0 :         srlb->used_mark = XCALLOC(MTYPE_OSPF_SR_PARAMS,
     300             :                                   srlb->max_block * SRLB_BLOCK_SIZE);
     301           0 :         srlb->reserved = true;
     302             : 
     303           0 :         return 0;
     304             : }
     305             : 
     306           0 : static int sr_global_block_init(uint32_t start, uint32_t size)
     307             : {
     308           0 :         struct sr_global_block *srgb = &OspfSR.srgb;
     309             : 
     310             :         /* Check if already configured */
     311           0 :         if (srgb->reserved)
     312             :                 return 0;
     313             : 
     314             :         /* request chunk */
     315           0 :         uint32_t end = start + size - 1;
     316           0 :         if (ospf_zebra_request_label_range(start, size) < 0) {
     317           0 :                 zlog_err("SR: Error reserving SRGB [%u/%u], %u labels", start,
     318             :                          end, size);
     319           0 :                 return -1;
     320             :         }
     321             : 
     322           0 :         osr_debug("SR: Got new SRGB [%u/%u], %u labels", start, end, size);
     323             : 
     324             :         /* success */
     325           0 :         srgb->start = start;
     326           0 :         srgb->size = size;
     327           0 :         srgb->reserved = true;
     328           0 :         return 0;
     329             : }
     330             : 
     331             : /**
     332             :  * Remove Segment Routing Local Block.
     333             :  *
     334             :  */
     335           0 : static void sr_local_block_delete(void)
     336             : {
     337           0 :         struct sr_local_block *srlb = &OspfSR.srlb;
     338             : 
     339             :         /* Check if SRLB is not already delete */
     340           0 :         if (!srlb->reserved)
     341             :                 return;
     342             : 
     343           0 :         osr_debug("SR (%s): Remove SRLB [%u/%u]", __func__, srlb->start,
     344             :                   srlb->end);
     345             : 
     346             :         /* First release the label block */
     347           0 :         ospf_zebra_release_label_range(srlb->start, srlb->end);
     348             : 
     349             :         /* Then reset SRLB structure */
     350           0 :         if (srlb->used_mark != NULL)
     351           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srlb->used_mark);
     352             : 
     353           0 :         srlb->reserved = false;
     354             : }
     355             : 
     356             : /**
     357             :  * Remove Segment Routing Global block
     358             :  */
     359           0 : static void sr_global_block_delete(void)
     360             : {
     361           0 :         struct sr_global_block *srgb = &OspfSR.srgb;
     362             : 
     363           0 :         if (!srgb->reserved)
     364             :                 return;
     365             : 
     366           0 :         osr_debug("SR (%s): Remove SRGB [%u/%u]", __func__, srgb->start,
     367             :                   srgb->start + srgb->size - 1);
     368             : 
     369           0 :         ospf_zebra_release_label_range(srgb->start,
     370           0 :                                        srgb->start + srgb->size - 1);
     371             : 
     372           0 :         srgb->reserved = false;
     373             : }
     374             : 
     375             : 
     376             : /**
     377             :  * Request a label from the Segment Routing Local Block.
     378             :  *
     379             :  * @return      First available label on success or MPLS_INVALID_LABEL if the
     380             :  *              block of labels is full
     381             :  */
     382           0 : mpls_label_t ospf_sr_local_block_request_label(void)
     383             : {
     384           0 :         struct sr_local_block *srlb = &OspfSR.srlb;
     385           0 :         mpls_label_t label;
     386           0 :         uint32_t index;
     387           0 :         uint32_t pos;
     388           0 :         uint32_t size = srlb->end - srlb->start + 1;
     389             : 
     390             :         /* Check if we ran out of available labels */
     391           0 :         if (srlb->current >= size)
     392             :                 return MPLS_INVALID_LABEL;
     393             : 
     394             :         /* Get first available label and mark it used */
     395           0 :         label = srlb->current + srlb->start;
     396           0 :         index = srlb->current / SRLB_BLOCK_SIZE;
     397           0 :         pos = 1ULL << (srlb->current % SRLB_BLOCK_SIZE);
     398           0 :         srlb->used_mark[index] |= pos;
     399             : 
     400             :         /* Jump to the next free position */
     401           0 :         srlb->current++;
     402           0 :         pos = srlb->current % SRLB_BLOCK_SIZE;
     403           0 :         while (srlb->current < size) {
     404           0 :                 if (pos == 0)
     405           0 :                         index++;
     406           0 :                 if (!((1ULL << pos) & srlb->used_mark[index]))
     407             :                         break;
     408             :                 else {
     409           0 :                         srlb->current++;
     410           0 :                         pos = srlb->current % SRLB_BLOCK_SIZE;
     411             :                 }
     412             :         }
     413             : 
     414           0 :         if (srlb->current == size)
     415           0 :                 zlog_warn(
     416             :                         "SR: Warning, SRLB is depleted and next label request will fail");
     417             : 
     418             :         return label;
     419             : }
     420             : 
     421             : /**
     422             :  * Release label in the Segment Routing Local Block.
     423             :  *
     424             :  * @param label Label to be release
     425             :  *
     426             :  * @return      0 on success or -1 if label falls outside SRLB
     427             :  */
     428           0 : int ospf_sr_local_block_release_label(mpls_label_t label)
     429             : {
     430           0 :         struct sr_local_block *srlb = &OspfSR.srlb;
     431           0 :         uint32_t index;
     432           0 :         uint32_t pos;
     433             : 
     434             :         /* Check that label falls inside the SRLB */
     435           0 :         if ((label < srlb->start) || (label > srlb->end)) {
     436           0 :                 flog_warn(EC_OSPF_SR_SID_OVERFLOW,
     437             :                           "%s: Returning label %u is outside SRLB [%u/%u]",
     438             :                           __func__, label, srlb->start, srlb->end);
     439           0 :                 return -1;
     440             :         }
     441             : 
     442           0 :         index = (label - srlb->start) / SRLB_BLOCK_SIZE;
     443           0 :         pos = 1ULL << ((label - srlb->start) % SRLB_BLOCK_SIZE);
     444           0 :         srlb->used_mark[index] &= ~pos;
     445             :         /* Reset current to the first available position */
     446           0 :         for (index = 0; index < srlb->max_block; index++) {
     447           0 :                 if (srlb->used_mark[index] != 0xFFFFFFFFFFFFFFFF) {
     448           0 :                         for (pos = 0; pos < SRLB_BLOCK_SIZE; pos++)
     449           0 :                                 if (!((1ULL << pos) & srlb->used_mark[index])) {
     450           0 :                                         srlb->current =
     451           0 :                                                 index * SRLB_BLOCK_SIZE + pos;
     452           0 :                                         break;
     453             :                                 }
     454             :                         break;
     455             :                 }
     456             :         }
     457             : 
     458             :         return 0;
     459             : }
     460             : 
     461             : /*
     462             :  * Segment Routing Initialization functions
     463             :  */
     464             : 
     465             : /**
     466             :  * Thread function to re-attempt connection to the Label Manager and thus be
     467             :  * able to start Segment Routing.
     468             :  *
     469             :  * @param start         Thread structure that contains area as argument
     470             :  *
     471             :  * @return              1 on success
     472             :  */
     473           0 : static void sr_start_label_manager(struct thread *start)
     474             : {
     475           0 :         struct ospf *ospf;
     476             : 
     477           0 :         ospf = THREAD_ARG(start);
     478             : 
     479             :         /* re-attempt to start SR & Label Manager connection */
     480           0 :         ospf_sr_start(ospf);
     481           0 : }
     482             : 
     483             : /* Segment Routing starter function */
     484           0 : static int ospf_sr_start(struct ospf *ospf)
     485             : {
     486           0 :         struct route_node *rn;
     487           0 :         struct ospf_lsa *lsa;
     488           0 :         struct sr_node *srn;
     489           0 :         int rc = 0;
     490             : 
     491           0 :         osr_debug("SR (%s): Start Segment Routing", __func__);
     492             : 
     493             :         /* Initialize self SR Node if not already done */
     494           0 :         if (OspfSR.self == NULL) {
     495           0 :                 srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id),
     496             :                                (void *)sr_node_new);
     497             : 
     498             :                 /* Complete & Store self SR Node */
     499           0 :                 srn->srgb.range_size = OspfSR.srgb.size;
     500           0 :                 srn->srgb.lower_bound = OspfSR.srgb.start;
     501           0 :                 srn->srlb.lower_bound = OspfSR.srlb.start;
     502           0 :                 srn->srlb.range_size = OspfSR.srlb.end - OspfSR.srlb.start + 1;
     503           0 :                 srn->algo[0] = OspfSR.algo[0];
     504           0 :                 srn->msd = OspfSR.msd;
     505           0 :                 OspfSR.self = srn;
     506             :         }
     507             : 
     508             :         /* Then, start Label Manager if not ready */
     509           0 :         if (!ospf_zebra_label_manager_ready())
     510           0 :                 if (ospf_zebra_label_manager_connect() < 0) {
     511             :                         /* Re-attempt to connect to Label Manager in 1 sec. */
     512           0 :                         thread_add_timer(master, sr_start_label_manager, ospf,
     513             :                                          1, &OspfSR.t_start_lm);
     514           0 :                         osr_debug("  |- Failed to start the Label Manager");
     515           0 :                         return -1;
     516             :                 }
     517             : 
     518             :         /*
     519             :          * Request SRLB & SGRB to the label manager if not already reserved.
     520             :          * If the allocation fails, return an error to disable SR until a new
     521             :          * SRLB and/or SRGB are successfully allocated.
     522             :          */
     523           0 :         if (sr_local_block_init(OspfSR.srlb.start, OspfSR.srlb.end) < 0)
     524             :                 return -1;
     525             : 
     526           0 :         if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size) < 0)
     527             :                 return -1;
     528             : 
     529             :         /* SR is UP and ready to flood LSA */
     530           0 :         OspfSR.status = SR_UP;
     531             : 
     532             :         /* Set Router Information SR parameters */
     533           0 :         osr_debug("SR: Activate SR for Router Information LSA");
     534             : 
     535           0 :         ospf_router_info_update_sr(true, OspfSR.self);
     536             : 
     537             :         /* Update Ext LSA */
     538           0 :         osr_debug("SR: Activate SR for Extended Link/Prefix LSA");
     539             : 
     540           0 :         ospf_ext_update_sr(true);
     541             : 
     542           0 :         osr_debug("SR (%s): Update SR-DB from LSDB", __func__);
     543             : 
     544             :         /* Start by looking to Router Info & Extended LSA in lsdb */
     545           0 :         if ((ospf != NULL) && (ospf->backbone != NULL)) {
     546           0 :                 LSDB_LOOP (OPAQUE_AREA_LSDB(ospf->backbone), rn, lsa) {
     547           0 :                         if (IS_LSA_MAXAGE(lsa) || IS_LSA_SELF(lsa))
     548           0 :                                 continue;
     549           0 :                         int lsa_id =
     550           0 :                                 GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
     551           0 :                         switch (lsa_id) {
     552           0 :                         case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
     553           0 :                                 ospf_sr_ri_lsa_update(lsa);
     554           0 :                                 break;
     555           0 :                         case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
     556           0 :                                 ospf_sr_ext_prefix_lsa_update(lsa);
     557           0 :                                 break;
     558           0 :                         case OPAQUE_TYPE_EXTENDED_LINK_LSA:
     559           0 :                                 ospf_sr_ext_link_lsa_update(lsa);
     560           0 :                                 break;
     561             :                         default:
     562             :                                 break;
     563             :                         }
     564             :                 }
     565             :         }
     566             : 
     567           0 :         rc = 1;
     568             :         return rc;
     569             : }
     570             : 
     571             : /* Stop Segment Routing */
     572           4 : static void ospf_sr_stop(void)
     573             : {
     574             : 
     575           4 :         if (OspfSR.status == SR_OFF)
     576             :                 return;
     577             : 
     578           0 :         osr_debug("SR (%s): Stop Segment Routing", __func__);
     579             : 
     580             :         /* Disable any re-attempt to connect to Label Manager */
     581           0 :         THREAD_OFF(OspfSR.t_start_lm);
     582             : 
     583             :         /* Release SRGB if active */
     584           0 :         sr_global_block_delete();
     585             : 
     586             :         /* Release SRLB if active */
     587           0 :         sr_local_block_delete();
     588             : 
     589             :         /*
     590             :          * Remove all SR Nodes from the Hash table. Prefix and Link SID will
     591             :          * be remove though list_delete() call. See sr_node_del()
     592             :          */
     593           0 :         hash_clean(OspfSR.neighbors, (void *)sr_node_del);
     594           0 :         OspfSR.self = NULL;
     595           0 :         OspfSR.status = SR_OFF;
     596             : }
     597             : 
     598             : /*
     599             :  * Segment Routing initialize function
     600             :  *
     601             :  * @param - nothing
     602             :  *
     603             :  * @return 0 if OK, -1 otherwise
     604             :  */
     605           4 : int ospf_sr_init(void)
     606             : {
     607           4 :         int rc = -1;
     608             : 
     609           4 :         osr_debug("SR (%s): Initialize SR Data Base", __func__);
     610             : 
     611           4 :         memset(&OspfSR, 0, sizeof(OspfSR));
     612           4 :         OspfSR.status = SR_OFF;
     613             :         /* Only AREA flooding is supported in this release */
     614           4 :         OspfSR.scope = OSPF_OPAQUE_AREA_LSA;
     615             : 
     616             :         /* Initialize Algorithms, SRGB, SRLB and MSD TLVs */
     617             :         /* Only Algorithm SPF is supported */
     618           4 :         OspfSR.algo[0] = SR_ALGORITHM_SPF;
     619          16 :         for (int i = 1; i < ALGORITHM_COUNT; i++)
     620          12 :                 OspfSR.algo[i] = SR_ALGORITHM_UNSET;
     621             : 
     622           4 :         OspfSR.srgb.size = DEFAULT_SRGB_SIZE;
     623           4 :         OspfSR.srgb.start = DEFAULT_SRGB_LABEL;
     624           4 :         OspfSR.srgb.reserved = false;
     625             : 
     626           4 :         OspfSR.srlb.start = DEFAULT_SRLB_LABEL;
     627           4 :         OspfSR.srlb.end = DEFAULT_SRLB_END;
     628           4 :         OspfSR.srlb.reserved = false;
     629           4 :         OspfSR.msd = 0;
     630             : 
     631             :         /* Initialize Hash table for neighbor SR nodes */
     632           4 :         OspfSR.neighbors = hash_create(sr_hash, sr_cmp, "OSPF_SR");
     633           4 :         if (OspfSR.neighbors == NULL)
     634             :                 return rc;
     635             : 
     636             :         /* Register Segment Routing VTY command */
     637           4 :         ospf_sr_register_vty();
     638             : 
     639           4 :         rc = 0;
     640           4 :         return rc;
     641             : }
     642             : 
     643             : /*
     644             :  * Segment Routing termination function
     645             :  *
     646             :  * @param - nothing
     647             :  * @return - nothing
     648             :  */
     649           0 : void ospf_sr_term(void)
     650             : {
     651             : 
     652             :         /* Stop Segment Routing */
     653           0 :         ospf_sr_stop();
     654             : 
     655             :         /* Clear SR Node Table */
     656           0 :         if (OspfSR.neighbors)
     657           0 :                 hash_free(OspfSR.neighbors);
     658             : 
     659           0 : }
     660             : 
     661             : /*
     662             :  * Segment Routing finish function
     663             :  *
     664             :  * @param - nothing
     665             :  * @return - nothing
     666             :  */
     667           4 : void ospf_sr_finish(void)
     668             : {
     669             :         /* Stop Segment Routing */
     670           4 :         ospf_sr_stop();
     671           4 : }
     672             : 
     673             : /*
     674             :  * Following functions are used to manipulate the
     675             :  * Next Hop Label Forwarding entry (NHLFE)
     676             :  */
     677             : 
     678             : /* Compute label from index */
     679           0 : static mpls_label_t index2label(uint32_t index, struct sr_block srgb)
     680             : {
     681           0 :         mpls_label_t label;
     682             : 
     683           0 :         label = srgb.lower_bound + index;
     684           0 :         if (label > (srgb.lower_bound + srgb.range_size)) {
     685           0 :                 flog_warn(EC_OSPF_SR_SID_OVERFLOW,
     686             :                           "%s: SID index %u falls outside SRGB range",
     687             :                           __func__, index);
     688           0 :                 return MPLS_INVALID_LABEL;
     689             :         } else
     690             :                 return label;
     691             : }
     692             : 
     693             : /* Get the prefix sid for a specific router id */
     694           0 : mpls_label_t ospf_sr_get_prefix_sid_by_id(struct in_addr *id)
     695             : {
     696           0 :         struct sr_node *srn;
     697           0 :         struct sr_prefix *srp;
     698           0 :         mpls_label_t label;
     699             : 
     700           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, id);
     701             : 
     702           0 :         if (srn) {
     703             :                 /*
     704             :                  * TODO: Here we assume that the SRGBs are the same,
     705             :                  * and that the node's prefix SID is at the head of
     706             :                  * the list, probably needs tweaking.
     707             :                  */
     708           0 :                 srp = listnode_head(srn->ext_prefix);
     709           0 :                 label = index2label(srp->sid, srn->srgb);
     710             :         } else {
     711             :                 label = MPLS_INVALID_LABEL;
     712             :         }
     713             : 
     714           0 :         return label;
     715             : }
     716             : 
     717             : /* Get the adjacency sid for a specific 'root' id and 'neighbor' id */
     718           0 : mpls_label_t ospf_sr_get_adj_sid_by_id(struct in_addr *root_id,
     719             :                                        struct in_addr *neighbor_id)
     720             : {
     721           0 :         struct sr_node *srn;
     722           0 :         struct sr_link *srl;
     723           0 :         mpls_label_t label;
     724           0 :         struct listnode *node;
     725             : 
     726           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, root_id);
     727             : 
     728           0 :         label = MPLS_INVALID_LABEL;
     729             : 
     730           0 :         if (srn) {
     731           0 :                 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
     732           0 :                         if (srl->type == ADJ_SID
     733           0 :                             && srl->remote_id.s_addr == neighbor_id->s_addr) {
     734           0 :                                 label = srl->sid[0];
     735           0 :                                 break;
     736             :                         }
     737             :                 }
     738             :         }
     739             : 
     740           0 :         return label;
     741             : }
     742             : 
     743             : /* Get neighbor full structure from address */
     744           0 : static struct ospf_neighbor *get_neighbor_by_addr(struct ospf *top,
     745             :                                                   struct in_addr addr)
     746             : {
     747           0 :         struct ospf_neighbor *nbr;
     748           0 :         struct ospf_interface *oi;
     749           0 :         struct listnode *node;
     750           0 :         struct route_node *rn;
     751             : 
     752             :         /* Sanity Check */
     753           0 :         if (top == NULL)
     754             :                 return NULL;
     755             : 
     756           0 :         for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi))
     757           0 :                 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
     758           0 :                         nbr = rn->info;
     759           0 :                         if (!nbr)
     760           0 :                                 continue;
     761             : 
     762           0 :                         if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &addr) ||
     763           0 :                             IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
     764           0 :                                 route_unlock_node(rn);
     765           0 :                                 return nbr;
     766             :                         }
     767             :                 }
     768             :         return NULL;
     769             : }
     770             : 
     771             : /* Get OSPF Path from address */
     772           0 : static struct ospf_route *get_nexthop_by_addr(struct ospf *top,
     773             :                                               struct prefix_ipv4 p)
     774             : {
     775           0 :         struct route_node *rn;
     776             : 
     777             :         /* Sanity Check */
     778           0 :         if (top == NULL)
     779             :                 return NULL;
     780             : 
     781           0 :         osr_debug("      |-  Search Nexthop for prefix %pFX",
     782             :                   (struct prefix *)&p);
     783             : 
     784           0 :         rn = route_node_lookup(top->new_table, (struct prefix *)&p);
     785             : 
     786             :         /*
     787             :          * Check if we found an OSPF route. May be NULL if SPF has not
     788             :          * yet populate routing table for this prefix.
     789             :          */
     790           0 :         if (rn == NULL)
     791             :                 return NULL;
     792             : 
     793           0 :         route_unlock_node(rn);
     794           0 :         return rn->info;
     795             : }
     796             : 
     797             : /* Compute NHLFE entry for Extended Link */
     798           0 : static int compute_link_nhlfe(struct sr_link *srl)
     799             : {
     800           0 :         struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
     801           0 :         struct ospf_neighbor *nh;
     802           0 :         int rc = 0;
     803             : 
     804           0 :         osr_debug("    |-  Compute NHLFE for link %pI4", &srl->itf_addr);
     805             : 
     806             :         /* First determine the OSPF Neighbor */
     807           0 :         nh = get_neighbor_by_addr(top, srl->nhlfe[0].nexthop);
     808             : 
     809             :         /* Neighbor could be not found when OSPF Adjacency just fire up
     810             :          * because SPF don't yet populate routing table. This NHLFE will
     811             :          * be fixed later when SR SPF schedule will be called.
     812             :          */
     813           0 :         if (nh == NULL)
     814             :                 return rc;
     815             : 
     816           0 :         osr_debug("    |-  Found nexthop %pI4", &nh->router_id);
     817             : 
     818             :         /* Set ifindex for this neighbor */
     819           0 :         srl->nhlfe[0].ifindex = nh->oi->ifp->ifindex;
     820           0 :         srl->nhlfe[1].ifindex = nh->oi->ifp->ifindex;
     821             : 
     822             :         /* Update neighbor address for LAN_ADJ_SID */
     823           0 :         if (srl->type == LAN_ADJ_SID) {
     824           0 :                 IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &nh->src);
     825           0 :                 IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &nh->src);
     826             :         }
     827             : 
     828             :         /* Set Input & Output Label */
     829           0 :         if (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
     830           0 :                 srl->nhlfe[0].label_in = srl->sid[0];
     831             :         else
     832           0 :                 srl->nhlfe[0].label_in =
     833           0 :                         index2label(srl->sid[0], srl->srn->srgb);
     834           0 :         if (CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
     835           0 :                 srl->nhlfe[1].label_in = srl->sid[1];
     836             :         else
     837           0 :                 srl->nhlfe[1].label_in =
     838           0 :                         index2label(srl->sid[1], srl->srn->srgb);
     839             : 
     840           0 :         srl->nhlfe[0].label_out = MPLS_LABEL_IMPLICIT_NULL;
     841           0 :         srl->nhlfe[1].label_out = MPLS_LABEL_IMPLICIT_NULL;
     842             : 
     843           0 :         rc = 1;
     844           0 :         return rc;
     845             : }
     846             : 
     847             : /**
     848             :  * Compute output label for the given Prefix-SID.
     849             :  *
     850             :  * @param srp           Segment Routing Prefix
     851             :  * @param srnext        Segment Routing nexthop node
     852             :  *
     853             :  * @return              MPLS label or MPLS_INVALID_LABEL in case of error
     854             :  */
     855           0 : static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
     856             :                                         const struct sr_node *srnext)
     857             : {
     858             :         /* Check if the nexthop SR Node is the last hop? */
     859           0 :         if (srnext == srp->srn) {
     860             :                 /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
     861           0 :                 if (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
     862             :                         return MPLS_LABEL_IMPLICIT_NULL;
     863             : 
     864             :                 /* SR-Node requests Explicit NULL Label */
     865           0 :                 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
     866             :                         return MPLS_LABEL_IPV4_EXPLICIT_NULL;
     867             :                 /* Fallthrough */
     868             :         }
     869             : 
     870             :         /* Return SID value as MPLS label if it is an Absolute SID */
     871           0 :         if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG
     872             :                                            | EXT_SUBTLV_PREFIX_SID_LFLG)) {
     873             :                 /*
     874             :                  * V/L SIDs have local significance, so only adjacent routers
     875             :                  * can use them (RFC8665 section #5)
     876             :                  */
     877           0 :                 if (srp->srn != srnext)
     878             :                         return MPLS_INVALID_LABEL;
     879           0 :                 return srp->sid;
     880             :         }
     881             : 
     882             :         /* Return MPLS label as SRGB lower bound + SID index as per RFC 8665 */
     883           0 :         return (index2label(srp->sid, srnext->srgb));
     884             : }
     885             : 
     886             : /*
     887             :  * Compute NHLFE entry for Extended Prefix
     888             :  *
     889             :  * @param srp - Segment Routing Prefix
     890             :  *
     891             :  * @return -1 if no route is found, 0 if there is no SR route ready
     892             :  *         and 1 if success or update
     893             :  */
     894           0 : static int compute_prefix_nhlfe(struct sr_prefix *srp)
     895             : {
     896           0 :         struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
     897           0 :         struct ospf_path *path;
     898           0 :         struct listnode *node;
     899           0 :         struct sr_node *srnext;
     900           0 :         int rc = -1;
     901             : 
     902           0 :         osr_debug("    |-  Compute NHLFE for prefix %pFX",
     903             :                   (struct prefix *)&srp->prefv4);
     904             : 
     905             : 
     906             :         /* First determine the nexthop */
     907           0 :         srp->route = get_nexthop_by_addr(top, srp->prefv4);
     908             : 
     909             :         /* Nexthop could be not found when OSPF Adjacency just fire up
     910             :          * because SPF don't yet populate routing table. This NHLFE will
     911             :          * be fixed later when SR SPF schedule will be called.
     912             :          */
     913           0 :         if (srp->route == NULL)
     914             :                 return rc;
     915             : 
     916             :         /* Compute Input Label with self SRGB */
     917           0 :         srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
     918             : 
     919           0 :         rc = 0;
     920           0 :         for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
     921             : 
     922           0 :                 osr_debug("    |-  Process new route via %pI4 for this prefix",
     923             :                           &path->nexthop);
     924             : 
     925             :                 /*
     926             :                  * Get SR-Node for this nexthop. Could be not yet available
     927             :                  * as Extended Link / Prefix and Router Information are flooded
     928             :                  * after LSA Type 1 & 2 which populate the OSPF Route Table
     929             :                  */
     930           0 :                 srnext = get_sr_node_by_nexthop(top, path->nexthop);
     931           0 :                 if (srnext == NULL)
     932           0 :                         continue;
     933             : 
     934             :                 /* And store this information for later update */
     935           0 :                 srnext->neighbor = OspfSR.self;
     936           0 :                 path->srni.nexthop = srnext;
     937             : 
     938             :                 /*
     939             :                  * SR Node could be known, but SRGB could be not initialize
     940             :                  * This is due to the fact that Extended Link / Prefix could
     941             :                  * be received before corresponding Router Information LSA
     942             :                  */
     943           0 :                 if (srnext == NULL || srnext->srgb.lower_bound == 0
     944           0 :                     || srnext->srgb.range_size == 0) {
     945           0 :                         osr_debug(
     946             :                                 "    |-  SR-Node %pI4 not ready. Stop process",
     947             :                                 &srnext->adv_router);
     948           0 :                         path->srni.label_out = MPLS_INVALID_LABEL;
     949           0 :                         continue;
     950             :                 }
     951             : 
     952           0 :                 osr_debug("    |-  Found SRGB %u/%u for next hop SR-Node %pI4",
     953             :                           srnext->srgb.range_size, srnext->srgb.lower_bound,
     954             :                           &srnext->adv_router);
     955             : 
     956             :                 /* Compute Output Label with Nexthop SR Node SRGB */
     957           0 :                 path->srni.label_out = sr_prefix_out_label(srp, srnext);
     958             : 
     959           0 :                 osr_debug("    |-  Computed new labels in: %u out: %u",
     960             :                           srp->label_in, path->srni.label_out);
     961             :                 rc = 1;
     962             :         }
     963             :         return rc;
     964             : }
     965             : 
     966             : /* Add new NHLFE entry for Adjacency SID */
     967           0 : static inline void add_adj_sid(struct sr_nhlfe nhlfe)
     968             : {
     969           0 :         if (nhlfe.label_in != 0)
     970           0 :                 ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, nhlfe);
     971             : }
     972             : 
     973             : /* Remove NHLFE entry for Adjacency SID */
     974           0 : static inline void del_adj_sid(struct sr_nhlfe nhlfe)
     975             : {
     976           0 :         if (nhlfe.label_in != 0)
     977           0 :                 ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
     978             : }
     979             : 
     980             : /* Update NHLFE entry for Adjacency SID */
     981           0 : static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2)
     982             : {
     983           0 :         del_adj_sid(n1);
     984           0 :         add_adj_sid(n2);
     985           0 : }
     986             : 
     987             : /*
     988             :  * Functions to parse and get Extended Link / Prefix
     989             :  * TLVs and SubTLVs
     990             :  */
     991             : 
     992             : /* Extended Link SubTLVs Getter */
     993           0 : static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size)
     994             : {
     995             : 
     996           0 :         struct sr_link *srl;
     997           0 :         struct ext_tlv_link *link = (struct ext_tlv_link *)tlvh;
     998           0 :         struct ext_subtlv_adj_sid *adj_sid;
     999           0 :         struct ext_subtlv_lan_adj_sid *lan_sid;
    1000           0 :         struct ext_subtlv_rmt_itf_addr *rmt_itf;
    1001             : 
    1002           0 :         struct tlv_header *sub_tlvh;
    1003           0 :         uint16_t length = 0, sum = 0, i = 0;
    1004             : 
    1005             :         /* Check TLV size */
    1006           0 :         if ((ntohs(tlvh->length) > size)
    1007           0 :             || ntohs(tlvh->length) < EXT_TLV_LINK_SIZE) {
    1008           0 :                 zlog_warn("Wrong Extended Link TLV size. Abort!");
    1009           0 :                 return NULL;
    1010             :         }
    1011             : 
    1012           0 :         srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
    1013             : 
    1014             :         /* Initialize TLV browsing */
    1015           0 :         length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
    1016           0 :         sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
    1017             :                                          + EXT_TLV_LINK_SIZE);
    1018           0 :         for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
    1019           0 :                 switch (ntohs(sub_tlvh->type)) {
    1020           0 :                 case EXT_SUBTLV_ADJ_SID:
    1021           0 :                         adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh;
    1022           0 :                         srl->type = ADJ_SID;
    1023           0 :                         i = CHECK_FLAG(adj_sid->flags,
    1024             :                                        EXT_SUBTLV_LINK_ADJ_SID_BFLG)
    1025             :                                     ? 1
    1026             :                                     : 0;
    1027           0 :                         srl->flags[i] = adj_sid->flags;
    1028           0 :                         if (CHECK_FLAG(adj_sid->flags,
    1029             :                                        EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1030           0 :                                 srl->sid[i] = GET_LABEL(ntohl(adj_sid->value));
    1031             :                         else
    1032           0 :                                 srl->sid[i] = ntohl(adj_sid->value);
    1033           0 :                         IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop, &link->link_id);
    1034             :                         break;
    1035           0 :                 case EXT_SUBTLV_LAN_ADJ_SID:
    1036           0 :                         lan_sid = (struct ext_subtlv_lan_adj_sid *)sub_tlvh;
    1037           0 :                         srl->type = LAN_ADJ_SID;
    1038           0 :                         i = CHECK_FLAG(lan_sid->flags,
    1039             :                                        EXT_SUBTLV_LINK_ADJ_SID_BFLG)
    1040             :                                     ? 1
    1041             :                                     : 0;
    1042           0 :                         srl->flags[i] = lan_sid->flags;
    1043           0 :                         if (CHECK_FLAG(lan_sid->flags,
    1044             :                                        EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1045           0 :                                 srl->sid[i] = GET_LABEL(ntohl(lan_sid->value));
    1046             :                         else
    1047           0 :                                 srl->sid[i] = ntohl(lan_sid->value);
    1048           0 :                         IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop,
    1049             :                                        &lan_sid->neighbor_id);
    1050             :                         break;
    1051           0 :                 case EXT_SUBTLV_RMT_ITF_ADDR:
    1052           0 :                         rmt_itf = (struct ext_subtlv_rmt_itf_addr *)sub_tlvh;
    1053           0 :                         IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &rmt_itf->value);
    1054           0 :                         IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &rmt_itf->value);
    1055             :                         break;
    1056             :                 default:
    1057             :                         break;
    1058             :                 }
    1059           0 :                 sum += TLV_SIZE(sub_tlvh);
    1060             :         }
    1061             : 
    1062           0 :         IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data);
    1063             : 
    1064           0 :         osr_debug("  |-  Found primary %u and backup %u Adj/Lan Sid for %pI4",
    1065             :                   srl->sid[0], srl->sid[1], &srl->itf_addr);
    1066             : 
    1067             :         return srl;
    1068             : }
    1069             : 
    1070             : /* Extended Prefix SubTLVs Getter */
    1071           0 : static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh,
    1072             :                                             size_t size)
    1073             : {
    1074             : 
    1075           0 :         struct sr_prefix *srp;
    1076           0 :         struct ext_tlv_prefix *pref = (struct ext_tlv_prefix *)tlvh;
    1077           0 :         struct ext_subtlv_prefix_sid *psid;
    1078             : 
    1079           0 :         struct tlv_header *sub_tlvh;
    1080           0 :         uint16_t length = 0, sum = 0;
    1081             : 
    1082             :         /* Check TLV size */
    1083           0 :         if ((ntohs(tlvh->length) > size)
    1084           0 :             || ntohs(tlvh->length) < EXT_TLV_PREFIX_SIZE) {
    1085           0 :                 zlog_warn("Wrong Extended Link TLV size. Abort!");
    1086           0 :                 return NULL;
    1087             :         }
    1088             : 
    1089           0 :         srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
    1090             : 
    1091             :         /* Initialize TLV browsing */
    1092           0 :         length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
    1093           0 :         sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
    1094             :                                          + EXT_TLV_PREFIX_SIZE);
    1095           0 :         for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
    1096           0 :                 switch (ntohs(sub_tlvh->type)) {
    1097           0 :                 case EXT_SUBTLV_PREFIX_SID:
    1098           0 :                         psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
    1099           0 :                         if (psid->algorithm != SR_ALGORITHM_SPF) {
    1100           0 :                                 flog_err(EC_OSPF_INVALID_ALGORITHM,
    1101             :                                          "SR (%s): Unsupported Algorithm",
    1102             :                                          __func__);
    1103           0 :                                 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    1104           0 :                                 return NULL;
    1105             :                         }
    1106           0 :                         srp->type = PREF_SID;
    1107           0 :                         srp->flags = psid->flags;
    1108           0 :                         if (CHECK_FLAG(psid->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
    1109           0 :                                 srp->sid = GET_LABEL(ntohl(psid->value));
    1110             :                         else
    1111           0 :                                 srp->sid = ntohl(psid->value);
    1112           0 :                         IPV4_ADDR_COPY(&srp->prefv4.prefix, &pref->address);
    1113           0 :                         srp->prefv4.prefixlen = pref->pref_length;
    1114           0 :                         srp->prefv4.family = AF_INET;
    1115           0 :                         apply_mask_ipv4(&srp->prefv4);
    1116           0 :                         break;
    1117             :                 default:
    1118             :                         break;
    1119             :                 }
    1120           0 :                 sum += TLV_SIZE(sub_tlvh);
    1121             :         }
    1122             : 
    1123           0 :         osr_debug("  |-  Found SID %u for prefix %pFX", srp->sid,
    1124             :                   (struct prefix *)&srp->prefv4);
    1125             : 
    1126             :         return srp;
    1127             : }
    1128             : 
    1129             : /*
    1130             :  * Functions to manipulate Segment Routing Link & Prefix structures
    1131             :  */
    1132             : 
    1133             : /* Compare two Segment Link: return 0 if equal, 1 otherwise */
    1134           0 : static inline int sr_link_cmp(struct sr_link *srl1, struct sr_link *srl2)
    1135             : {
    1136           0 :         if ((srl1->sid[0] == srl2->sid[0]) && (srl1->sid[1] == srl2->sid[1])
    1137           0 :             && (srl1->type == srl2->type) && (srl1->flags[0] == srl2->flags[0])
    1138           0 :             && (srl1->flags[1] == srl2->flags[1]))
    1139             :                 return 0;
    1140             :         else
    1141           0 :                 return 1;
    1142             : }
    1143             : 
    1144             : /* Compare two Segment Prefix: return 0 if equal, 1 otherwise */
    1145           0 : static inline int sr_prefix_cmp(struct sr_prefix *srp1, struct sr_prefix *srp2)
    1146             : {
    1147           0 :         if ((srp1->sid == srp2->sid) && (srp1->flags == srp2->flags))
    1148             :                 return 0;
    1149             :         else
    1150           0 :                 return 1;
    1151             : }
    1152             : 
    1153             : /* Update Segment Link of given Segment Routing Node */
    1154           0 : static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl,
    1155             :                                 uint8_t lsa_flags)
    1156             : {
    1157           0 :         struct listnode *node;
    1158           0 :         struct sr_link *lk;
    1159           0 :         bool found = false;
    1160           0 :         bool config = true;
    1161             : 
    1162             :         /* Sanity check */
    1163           0 :         if ((srn == NULL) || (srl == NULL))
    1164             :                 return;
    1165             : 
    1166           0 :         osr_debug("  |-  Process Extended Link Adj/Lan-SID");
    1167             : 
    1168             :         /* Detect if Adj/Lan_Adj SID must be configured */
    1169           0 :         if (!CHECK_FLAG(lsa_flags, OSPF_LSA_SELF)
    1170           0 :             && (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
    1171           0 :                 || CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG)))
    1172           0 :                 config = false;
    1173             : 
    1174             :         /* Search for existing Segment Link */
    1175           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, lk))
    1176           0 :                 if (lk->instance == srl->instance) {
    1177             :                         found = true;
    1178             :                         break;
    1179             :                 }
    1180             : 
    1181           0 :         osr_debug("  |-  %s SR Link 8.0.0.%u for SR node %pI4",
    1182             :                   found ? "Update" : "Add", GET_OPAQUE_ID(srl->instance),
    1183             :                   &srn->adv_router);
    1184             : 
    1185             :         /* if not found, add new Segment Link and install NHLFE */
    1186           0 :         if (!found) {
    1187             :                 /* Complete SR-Link and add it to SR-Node list */
    1188           0 :                 srl->srn = srn;
    1189           0 :                 IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
    1190           0 :                 listnode_add(srn->ext_link, srl);
    1191             :                 /* Try to set MPLS table */
    1192           0 :                 if (config && compute_link_nhlfe(srl)) {
    1193           0 :                         add_adj_sid(srl->nhlfe[0]);
    1194           0 :                         add_adj_sid(srl->nhlfe[1]);
    1195             :                 }
    1196             :         } else {
    1197             :                 /* Update SR-Link if they are different */
    1198           0 :                 if (sr_link_cmp(lk, srl)) {
    1199             :                         /* Try to set MPLS table */
    1200           0 :                         if (config) {
    1201           0 :                                 if (compute_link_nhlfe(srl)) {
    1202           0 :                                         update_adj_sid(lk->nhlfe[0],
    1203             :                                                        srl->nhlfe[0]);
    1204           0 :                                         update_adj_sid(lk->nhlfe[1],
    1205             :                                                        srl->nhlfe[1]);
    1206             :                                 } else {
    1207           0 :                                         del_adj_sid(lk->nhlfe[0]);
    1208           0 :                                         del_adj_sid(lk->nhlfe[1]);
    1209             :                                 }
    1210             :                         }
    1211             :                         /* Replace SR-Link in SR-Node Adjacency List */
    1212           0 :                         listnode_delete(srn->ext_link, lk);
    1213           0 :                         XFREE(MTYPE_OSPF_SR_PARAMS, lk);
    1214           0 :                         srl->srn = srn;
    1215           0 :                         IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
    1216           0 :                         listnode_add(srn->ext_link, srl);
    1217             :                 } else {
    1218             :                         /*
    1219             :                          * This is just an LSA refresh.
    1220             :                          * Stop processing and free SR Link
    1221             :                          */
    1222           0 :                         XFREE(MTYPE_OSPF_SR_PARAMS, srl);
    1223             :                 }
    1224             :         }
    1225             : }
    1226             : 
    1227             : /* Update Segment Prefix of given Segment Routing Node */
    1228           0 : static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp)
    1229             : {
    1230             : 
    1231           0 :         struct listnode *node;
    1232           0 :         struct sr_prefix *pref;
    1233           0 :         bool found = false;
    1234             : 
    1235             :         /* Sanity check */
    1236           0 :         if (srn == NULL || srp == NULL)
    1237             :                 return;
    1238             : 
    1239           0 :         osr_debug("  |-  Process Extended Prefix SID %u", srp->sid);
    1240             : 
    1241             :         /* Process only Global Prefix SID */
    1242           0 :         if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_LFLG))
    1243             :                 return;
    1244             : 
    1245             :         /* Search for existing Segment Prefix */
    1246           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, pref))
    1247           0 :                 if (pref->instance == srp->instance
    1248           0 :                     && prefix_same((struct prefix *)&srp->prefv4,
    1249           0 :                                    &pref->prefv4)) {
    1250             :                         found = true;
    1251             :                         break;
    1252             :                 }
    1253             : 
    1254           0 :         osr_debug("  |-  %s SR LSA ID 7.0.0.%u for SR node %pI4",
    1255             :                   found ? "Update" : "Add", GET_OPAQUE_ID(srp->instance),
    1256             :                   &srn->adv_router);
    1257             : 
    1258             :         /* Complete SR-Prefix */
    1259           0 :         srp->srn = srn;
    1260           0 :         IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router);
    1261             : 
    1262             :         /* if not found, add new Segment Prefix and install NHLFE */
    1263           0 :         if (!found) {
    1264             :                 /* Add it to SR-Node list ... */
    1265           0 :                 listnode_add(srn->ext_prefix, srp);
    1266             :                 /* ... and try to set MPLS table */
    1267           0 :                 if (compute_prefix_nhlfe(srp) == 1)
    1268           0 :                         ospf_zebra_update_prefix_sid(srp);
    1269             :         } else {
    1270             :                 /*
    1271             :                  * An old SR prefix exist. Check if something changes or if it
    1272             :                  * is just a refresh.
    1273             :                  */
    1274           0 :                 if (sr_prefix_cmp(pref, srp)) {
    1275           0 :                         if (compute_prefix_nhlfe(srp) == 1) {
    1276           0 :                                 ospf_zebra_delete_prefix_sid(pref);
    1277             :                                 /* Replace Segment Prefix */
    1278           0 :                                 listnode_delete(srn->ext_prefix, pref);
    1279           0 :                                 XFREE(MTYPE_OSPF_SR_PARAMS, pref);
    1280           0 :                                 listnode_add(srn->ext_prefix, srp);
    1281           0 :                                 ospf_zebra_update_prefix_sid(srp);
    1282             :                         } else {
    1283             :                                 /* New NHLFE was not found.
    1284             :                                  * Just free the SR Prefix
    1285             :                                  */
    1286           0 :                                 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    1287             :                         }
    1288             :                 } else {
    1289             :                         /* This is just an LSA refresh.
    1290             :                          * Stop processing and free SR Prefix
    1291             :                          */
    1292           0 :                         XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    1293             :                 }
    1294             :         }
    1295             : }
    1296             : 
    1297             : /*
    1298             :  * When change the FRR Self SRGB, update the NHLFE Input Label
    1299             :  * for all Extended Prefix with SID index through hash_iterate()
    1300             :  */
    1301           0 : static void update_in_nhlfe(struct hash_bucket *bucket, void *args)
    1302             : {
    1303           0 :         struct listnode *node;
    1304           0 :         struct sr_node *srn = (struct sr_node *)bucket->data;
    1305           0 :         struct sr_prefix *srp;
    1306             : 
    1307             :         /* Process Every Extended Prefix for this SR-Node */
    1308           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
    1309             :                 /* Process Self SRN only if NO-PHP is requested */
    1310           0 :                 if ((srn == OspfSR.self)
    1311           0 :                     && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
    1312           0 :                         continue;
    1313             : 
    1314             :                 /* Process only SID Index */
    1315           0 :                 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
    1316           0 :                         continue;
    1317             : 
    1318             :                 /* First, remove old MPLS table entries ... */
    1319           0 :                 ospf_zebra_delete_prefix_sid(srp);
    1320             :                 /* ... then compute new input label ... */
    1321           0 :                 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
    1322             :                 /* ... and install new MPLS LFIB */
    1323           0 :                 ospf_zebra_update_prefix_sid(srp);
    1324             :         }
    1325           0 : }
    1326             : 
    1327             : /*
    1328             :  * When SRGB has changed, update NHLFE Output Label for all Extended Prefix
    1329             :  * with SID index which use the given SR-Node as nexthop through hash_iterate()
    1330             :  */
    1331           0 : static void update_out_nhlfe(struct hash_bucket *bucket, void *args)
    1332             : {
    1333           0 :         struct listnode *node, *pnode;
    1334           0 :         struct sr_node *srn = (struct sr_node *)bucket->data;
    1335           0 :         struct sr_node *srnext = (struct sr_node *)args;
    1336           0 :         struct sr_prefix *srp;
    1337           0 :         struct ospf_path *path;
    1338             : 
    1339             :         /* Skip Self SR-Node */
    1340           0 :         if (srn == OspfSR.self)
    1341             :                 return;
    1342             : 
    1343           0 :         osr_debug("SR (%s): Update Out NHLFE for neighbor SR-Node %pI4",
    1344             :                   __func__, &srn->adv_router);
    1345             : 
    1346           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
    1347             :                 /* Skip Prefix that has not yet a valid route */
    1348           0 :                 if (srp->route == NULL)
    1349           0 :                         continue;
    1350             : 
    1351           0 :                 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, pnode, path)) {
    1352             :                         /* Skip path that has not next SR-Node as nexthop */
    1353           0 :                         if (path->srni.nexthop != srnext)
    1354           0 :                                 continue;
    1355             : 
    1356             :                         /* Compute new Output Label */
    1357           0 :                         path->srni.label_out = sr_prefix_out_label(srp, srnext);
    1358             :                 }
    1359             : 
    1360             :                 /* Finally update MPLS table */
    1361           0 :                 ospf_zebra_update_prefix_sid(srp);
    1362             :         }
    1363             : }
    1364             : 
    1365             : /*
    1366             :  * Following functions are call when new Segment Routing LSA are received
    1367             :  *  - Router Information: ospf_sr_ri_lsa_update() & ospf_sr_ri_lsa_delete()
    1368             :  *  - Extended Link: ospf_sr_ext_link_update() & ospf_sr_ext_link_delete()
    1369             :  *  - Extended Prefix: ospf_ext_prefix_update() & ospf_sr_ext_prefix_delete()
    1370             :  */
    1371             : 
    1372             : /* Update Segment Routing from Router Information LSA */
    1373           0 : void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
    1374             : {
    1375           0 :         struct sr_node *srn;
    1376           0 :         struct tlv_header *tlvh;
    1377           0 :         struct lsa_header *lsah = lsa->data;
    1378           0 :         struct ri_sr_tlv_sid_label_range *ri_srgb = NULL;
    1379           0 :         struct ri_sr_tlv_sid_label_range *ri_srlb = NULL;
    1380           0 :         struct ri_sr_tlv_sr_algorithm *algo = NULL;
    1381           0 :         struct sr_block srgb;
    1382           0 :         uint16_t length = 0, sum = 0;
    1383           0 :         uint8_t msd = 0;
    1384             : 
    1385           0 :         osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4",
    1386             :                   __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1387             :                   &lsah->adv_router);
    1388             : 
    1389             :         /* Sanity check */
    1390           0 :         if (IS_LSA_SELF(lsa))
    1391             :                 return;
    1392             : 
    1393           0 :         if (OspfSR.neighbors == NULL) {
    1394           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1395             :                          "SR (%s): Abort! no valid SR DataBase", __func__);
    1396           0 :                 return;
    1397             :         }
    1398             : 
    1399             :         /* Search SR Node in hash table from Router ID */
    1400           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
    1401           0 :                                             &lsah->adv_router);
    1402             : 
    1403             : 
    1404             :         /* Collect Router Information Sub TLVs */
    1405             :         /* Initialize TLV browsing */
    1406           0 :         length = lsa->size - OSPF_LSA_HEADER_SIZE;
    1407           0 :         srgb.range_size = 0;
    1408           0 :         srgb.lower_bound = 0;
    1409             : 
    1410           0 :         for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
    1411           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1412           0 :                 switch (ntohs(tlvh->type)) {
    1413           0 :                 case RI_SR_TLV_SR_ALGORITHM:
    1414           0 :                         algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
    1415           0 :                         break;
    1416           0 :                 case RI_SR_TLV_SRGB_LABEL_RANGE:
    1417           0 :                         ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
    1418           0 :                         break;
    1419           0 :                 case RI_SR_TLV_SRLB_LABEL_RANGE:
    1420           0 :                         ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh;
    1421           0 :                         break;
    1422           0 :                 case RI_SR_TLV_NODE_MSD:
    1423           0 :                         msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
    1424           0 :                         break;
    1425             :                 default:
    1426             :                         break;
    1427             :                 }
    1428           0 :                 sum += TLV_SIZE(tlvh);
    1429             :         }
    1430             : 
    1431             :         /* Check if Segment Routing Capabilities has been found */
    1432           0 :         if (ri_srgb == NULL) {
    1433             :                 /* Skip Router Information without SR capabilities
    1434             :                  * advertise by a non SR Node */
    1435           0 :                 if (srn == NULL) {
    1436             :                         return;
    1437             :                 } else {
    1438             :                         /* Remove SR Node that advertise Router Information
    1439             :                          * without SR capabilities. This could correspond to a
    1440             :                          * Node stopping Segment Routing */
    1441           0 :                         hash_release(OspfSR.neighbors, &(srn->adv_router));
    1442           0 :                         sr_node_del(srn);
    1443           0 :                         return;
    1444             :                 }
    1445             :         }
    1446             : 
    1447             :         /* Check that RI LSA belongs to the correct SR Node */
    1448           0 :         if ((srn != NULL) && (srn->instance != 0)
    1449           0 :             && (srn->instance != ntohl(lsah->id.s_addr))) {
    1450           0 :                 flog_err(EC_OSPF_SR_INVALID_LSA_ID,
    1451             :                          "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4/%u",
    1452             :                          __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1453             :                          &lsah->adv_router, srn->instance);
    1454           0 :                 return;
    1455             :         }
    1456             : 
    1457             :         /* OK. All things look good. Get SRGB */
    1458           0 :         srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size));
    1459           0 :         srgb.lower_bound = GET_LABEL(ntohl(ri_srgb->lower.value));
    1460             : 
    1461             :         /* Check if it is a new SR Node or not */
    1462           0 :         if (srn == NULL) {
    1463             :                 /* Get a new SR Node in hash table from Router ID */
    1464           0 :                 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
    1465             :                                                  &lsah->adv_router,
    1466             :                                                  (void *)sr_node_new);
    1467             :                 /* update LSA ID */
    1468           0 :                 srn->instance = ntohl(lsah->id.s_addr);
    1469             :                 /* Copy SRGB */
    1470           0 :                 srn->srgb.range_size = srgb.range_size;
    1471           0 :                 srn->srgb.lower_bound = srgb.lower_bound;
    1472             :         }
    1473             : 
    1474             :         /* Update Algorithm, SRLB and MSD if present */
    1475           0 :         if (algo != NULL) {
    1476             :                 int i;
    1477           0 :                 for (i = 0; i < ntohs(algo->header.length); i++)
    1478           0 :                         srn->algo[i] = algo->value[0];
    1479           0 :                 for (; i < ALGORITHM_COUNT; i++)
    1480           0 :                         srn->algo[i] = SR_ALGORITHM_UNSET;
    1481             :         } else {
    1482           0 :                 srn->algo[0] = SR_ALGORITHM_SPF;
    1483             :         }
    1484           0 :         srn->msd = msd;
    1485           0 :         if (ri_srlb != NULL) {
    1486           0 :                 srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size));
    1487           0 :                 srn->srlb.lower_bound = GET_LABEL(ntohl(ri_srlb->lower.value));
    1488             :         }
    1489             : 
    1490             :         /* Check if SRGB has changed */
    1491           0 :         if ((srn->srgb.range_size == srgb.range_size)
    1492           0 :             && (srn->srgb.lower_bound == srgb.lower_bound))
    1493             :                 return;
    1494             : 
    1495             :         /* Copy SRGB */
    1496           0 :         srn->srgb.range_size = srgb.range_size;
    1497           0 :         srn->srgb.lower_bound = srgb.lower_bound;
    1498             : 
    1499           0 :         osr_debug("  |- Update SR-Node[%pI4], SRGB[%u/%u], SRLB[%u/%u], Algo[%u], MSD[%u]",
    1500             :                   &srn->adv_router, srn->srgb.lower_bound, srn->srgb.range_size,
    1501             :                   srn->srlb.lower_bound, srn->srlb.range_size, srn->algo[0],
    1502             :                   srn->msd);
    1503             : 
    1504             :         /* ... and NHLFE if it is a neighbor SR node */
    1505           0 :         if (srn->neighbor == OspfSR.self)
    1506           0 :                 hash_iterate(OspfSR.neighbors, update_out_nhlfe, srn);
    1507             : }
    1508             : 
    1509             : /*
    1510             :  * Delete SR Node entry in hash table information corresponding to an expired
    1511             :  * Router Information LSA
    1512             :  */
    1513           0 : void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
    1514             : {
    1515           0 :         struct sr_node *srn;
    1516           0 :         struct lsa_header *lsah = lsa->data;
    1517             : 
    1518           0 :         osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", __func__,
    1519             :                   &lsah->adv_router, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)));
    1520             : 
    1521             :         /* Sanity check */
    1522           0 :         if (OspfSR.neighbors == NULL) {
    1523           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1524             :                          "SR (%s): Abort! no valid SR Data Base", __func__);
    1525           0 :                 return;
    1526             :         }
    1527             : 
    1528             :         /* Release Router ID entry in SRDB hash table */
    1529           0 :         srn = hash_release(OspfSR.neighbors, &(lsah->adv_router));
    1530             : 
    1531             :         /* Sanity check */
    1532           0 :         if (srn == NULL) {
    1533           0 :                 flog_err(EC_OSPF_SR_NODE_CREATE,
    1534             :                          "SR (%s): Abort! no entry in SRDB for SR Node %pI4",
    1535             :                          __func__, &lsah->adv_router);
    1536           0 :                 return;
    1537             :         }
    1538             : 
    1539           0 :         if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
    1540           0 :                 flog_err(
    1541             :                         EC_OSPF_SR_INVALID_LSA_ID,
    1542             :                         "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4",
    1543             :                         __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1544             :                         &lsah->adv_router);
    1545           0 :                 return;
    1546             :         }
    1547             : 
    1548             :         /* Remove SR node */
    1549           0 :         sr_node_del(srn);
    1550             : }
    1551             : 
    1552             : /* Update Segment Routing from Extended Link LSA */
    1553           0 : void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
    1554             : {
    1555           0 :         struct sr_node *srn;
    1556           0 :         struct tlv_header *tlvh;
    1557           0 :         struct lsa_header *lsah = lsa->data;
    1558           0 :         struct sr_link *srl;
    1559             : 
    1560           0 :         int length;
    1561             : 
    1562           0 :         osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4",
    1563             :                   __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1564             :                   &lsah->adv_router);
    1565             : 
    1566             :         /* Sanity check */
    1567           0 :         if (OspfSR.neighbors == NULL) {
    1568           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1569             :                          "SR (%s): Abort! no valid SR DataBase", __func__);
    1570           0 :                 return;
    1571             :         }
    1572             : 
    1573             :         /* Get SR Node in hash table from Router ID */
    1574           0 :         srn = (struct sr_node *)hash_get(OspfSR.neighbors,
    1575           0 :                                          (void *)&(lsah->adv_router),
    1576             :                                          (void *)sr_node_new);
    1577             : 
    1578             :         /* Initialize TLV browsing */
    1579           0 :         length = lsa->size - OSPF_LSA_HEADER_SIZE;
    1580           0 :         for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
    1581           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1582           0 :                 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
    1583             :                         /* Got Extended Link information */
    1584           0 :                         srl = get_ext_link_sid(tlvh, length);
    1585             :                         /* Update SID if not null */
    1586           0 :                         if (srl != NULL) {
    1587           0 :                                 srl->instance = ntohl(lsah->id.s_addr);
    1588           0 :                                 update_ext_link_sid(srn, srl, lsa->flags);
    1589             :                         }
    1590             :                 }
    1591           0 :                 length -= TLV_SIZE(tlvh);
    1592             :         }
    1593             : }
    1594             : 
    1595             : /* Delete Segment Routing from Extended Link LSA */
    1596           0 : void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
    1597             : {
    1598           0 :         struct listnode *node;
    1599           0 :         struct sr_link *srl;
    1600           0 :         struct sr_node *srn;
    1601           0 :         struct lsa_header *lsah = lsa->data;
    1602           0 :         uint32_t instance = ntohl(lsah->id.s_addr);
    1603             : 
    1604           0 :         osr_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %pI4",
    1605             :                   __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1606             :                   &lsah->adv_router);
    1607             : 
    1608             :         /* Sanity check */
    1609           0 :         if (OspfSR.neighbors == NULL) {
    1610           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1611             :                          "SR (%s): Abort! no valid SR DataBase", __func__);
    1612           0 :                 return;
    1613             :         }
    1614             : 
    1615             :         /* Search SR Node in hash table from Router ID */
    1616           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
    1617           0 :                                             (void *)&(lsah->adv_router));
    1618             : 
    1619             :         /*
    1620             :          * SR-Node may be NULL if it has been remove previously when
    1621             :          * processing Router Information LSA deletion
    1622             :          */
    1623           0 :         if (srn == NULL) {
    1624           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1625             :                          "SR (%s): Stop! no entry in SRDB for SR Node %pI4",
    1626             :                          __func__, &lsah->adv_router);
    1627           0 :                 return;
    1628             :         }
    1629             : 
    1630             :         /* Search for corresponding Segment Link */
    1631           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
    1632           0 :                 if (srl->instance == instance)
    1633             :                         break;
    1634             : 
    1635             :         /* Remove Segment Link if found. Note that for Neighbors, only Global
    1636             :          * Adj/Lan-Adj SID are stored in the SR-DB */
    1637           0 :         if ((srl != NULL) && (srl->instance == instance)) {
    1638           0 :                 del_adj_sid(srl->nhlfe[0]);
    1639           0 :                 del_adj_sid(srl->nhlfe[1]);
    1640           0 :                 listnode_delete(srn->ext_link, srl);
    1641           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
    1642             :         }
    1643             : }
    1644             : 
    1645             : /* Add (LAN)Adjacency-SID from Extended Link Information */
    1646           0 : void ospf_sr_ext_itf_add(struct ext_itf *exti)
    1647             : {
    1648           0 :         struct sr_node *srn = OspfSR.self;
    1649           0 :         struct sr_link *srl;
    1650             : 
    1651           0 :         osr_debug("SR (%s): Add Extended Link LSA 8.0.0.%u from self", __func__,
    1652             :                   exti->instance);
    1653             : 
    1654             :         /* Sanity check */
    1655           0 :         if (srn == NULL)
    1656             :                 return;
    1657             : 
    1658             :         /* Initialize new Segment Routing Link */
    1659           0 :         srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
    1660           0 :         srl->srn = srn;
    1661           0 :         srl->adv_router = srn->adv_router;
    1662           0 :         srl->itf_addr = exti->link.link_data;
    1663           0 :         srl->instance =
    1664           0 :                 SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
    1665           0 :         srl->remote_id = exti->link.link_id;
    1666           0 :         switch (exti->stype) {
    1667           0 :         case ADJ_SID:
    1668           0 :                 srl->type = ADJ_SID;
    1669             :                 /* Primary information */
    1670           0 :                 srl->flags[0] = exti->adj_sid[0].flags;
    1671           0 :                 if (CHECK_FLAG(exti->adj_sid[0].flags,
    1672             :                                EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1673           0 :                         srl->sid[0] = GET_LABEL(ntohl(exti->adj_sid[0].value));
    1674             :                 else
    1675           0 :                         srl->sid[0] = ntohl(exti->adj_sid[0].value);
    1676           0 :                 if (exti->rmt_itf_addr.header.type == 0)
    1677           0 :                         srl->nhlfe[0].nexthop = exti->link.link_id;
    1678             :                 else
    1679           0 :                         srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
    1680             :                 /* Backup Information if set */
    1681           0 :                 if (exti->adj_sid[1].header.type == 0)
    1682             :                         break;
    1683           0 :                 srl->flags[1] = exti->adj_sid[1].flags;
    1684           0 :                 if (CHECK_FLAG(exti->adj_sid[1].flags,
    1685             :                                EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1686           0 :                         srl->sid[1] = GET_LABEL(ntohl(exti->adj_sid[1].value));
    1687             :                 else
    1688           0 :                         srl->sid[1] = ntohl(exti->adj_sid[1].value);
    1689           0 :                 if (exti->rmt_itf_addr.header.type == 0)
    1690           0 :                         srl->nhlfe[1].nexthop = exti->link.link_id;
    1691             :                 else
    1692           0 :                         srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
    1693             :                 break;
    1694           0 :         case LAN_ADJ_SID:
    1695           0 :                 srl->type = LAN_ADJ_SID;
    1696             :                 /* Primary information */
    1697           0 :                 srl->flags[0] = exti->lan_sid[0].flags;
    1698           0 :                 if (CHECK_FLAG(exti->lan_sid[0].flags,
    1699             :                                EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1700           0 :                         srl->sid[0] = GET_LABEL(ntohl(exti->lan_sid[0].value));
    1701             :                 else
    1702           0 :                         srl->sid[0] = ntohl(exti->lan_sid[0].value);
    1703           0 :                 if (exti->rmt_itf_addr.header.type == 0)
    1704           0 :                         srl->nhlfe[0].nexthop = exti->lan_sid[0].neighbor_id;
    1705             :                 else
    1706           0 :                         srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
    1707             :                 /* Backup Information if set */
    1708           0 :                 if (exti->lan_sid[1].header.type == 0)
    1709             :                         break;
    1710           0 :                 srl->flags[1] = exti->lan_sid[1].flags;
    1711           0 :                 if (CHECK_FLAG(exti->lan_sid[1].flags,
    1712             :                                EXT_SUBTLV_LINK_ADJ_SID_VFLG))
    1713           0 :                         srl->sid[1] = GET_LABEL(ntohl(exti->lan_sid[1].value));
    1714             :                 else
    1715           0 :                         srl->sid[1] = ntohl(exti->lan_sid[1].value);
    1716           0 :                 if (exti->rmt_itf_addr.header.type == 0)
    1717           0 :                         srl->nhlfe[1].nexthop = exti->lan_sid[1].neighbor_id;
    1718             :                 else
    1719           0 :                         srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
    1720             :                 break;
    1721           0 :         case PREF_SID:
    1722             :         case LOCAL_SID:
    1723             :                 /* Wrong SID Type. Abort! */
    1724           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
    1725           0 :                 return;
    1726             :         }
    1727             : 
    1728             :         /* Segment Routing Link is ready, update it */
    1729           0 :         update_ext_link_sid(srn, srl, OSPF_LSA_SELF);
    1730             : }
    1731             : 
    1732             : /* Delete Prefix or (LAN)Adjacency-SID from Extended Link Information */
    1733           0 : void ospf_sr_ext_itf_delete(struct ext_itf *exti)
    1734             : {
    1735           0 :         struct listnode *node;
    1736           0 :         struct sr_node *srn = OspfSR.self;
    1737           0 :         struct sr_prefix *srp = NULL;
    1738           0 :         struct sr_link *srl = NULL;
    1739           0 :         uint32_t instance;
    1740             : 
    1741           0 :         osr_debug("SR (%s): Remove Extended LSA %u.0.0.%u from self",
    1742             :                   __func__, exti->stype == PREF_SID ? 7 : 8, exti->instance);
    1743             : 
    1744             :         /* Sanity check: SR-Node and Extended Prefix/Link list may have been
    1745             :          * removed earlier when stopping OSPF or OSPF-SR */
    1746           0 :         if (srn == NULL || srn->ext_prefix == NULL || srn->ext_link == NULL)
    1747             :                 return;
    1748             : 
    1749           0 :         if (exti->stype == PREF_SID) {
    1750           0 :                 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
    1751             :                                            exti->instance);
    1752           0 :                 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
    1753           0 :                         if (srp->instance == instance)
    1754             :                                 break;
    1755             : 
    1756             :                 /* Uninstall Segment Prefix SID if found */
    1757           0 :                 if ((srp != NULL) && (srp->instance == instance))
    1758           0 :                         ospf_zebra_delete_prefix_sid(srp);
    1759             :         } else {
    1760             :                 /* Search for corresponding Segment Link for self SR-Node */
    1761           0 :                 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA,
    1762             :                                            exti->instance);
    1763           0 :                 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
    1764           0 :                         if (srl->instance == instance)
    1765             :                                 break;
    1766             : 
    1767             :                 /* Remove Segment Link if found */
    1768           0 :                 if ((srl != NULL) && (srl->instance == instance)) {
    1769           0 :                         del_adj_sid(srl->nhlfe[0]);
    1770           0 :                         del_adj_sid(srl->nhlfe[1]);
    1771           0 :                         listnode_delete(srn->ext_link, srl);
    1772           0 :                         XFREE(MTYPE_OSPF_SR_PARAMS, srl);
    1773             :                 }
    1774             :         }
    1775             : }
    1776             : 
    1777             : /* Update Segment Routing from Extended Prefix LSA */
    1778           0 : void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
    1779             : {
    1780           0 :         struct sr_node *srn;
    1781           0 :         struct tlv_header *tlvh;
    1782           0 :         struct lsa_header *lsah = (struct lsa_header *)lsa->data;
    1783           0 :         struct sr_prefix *srp;
    1784             : 
    1785           0 :         int length;
    1786             : 
    1787           0 :         osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4",
    1788             :                   __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1789             :                   &lsah->adv_router);
    1790             : 
    1791             :         /* Sanity check */
    1792           0 :         if (OspfSR.neighbors == NULL) {
    1793           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1794             :                          "SR (%s): Abort! no valid SR DataBase", __func__);
    1795           0 :                 return;
    1796             :         }
    1797             : 
    1798             :         /* Get SR Node in hash table from Router ID */
    1799           0 :         srn = (struct sr_node *)hash_get(OspfSR.neighbors,
    1800           0 :                                          (void *)&(lsah->adv_router),
    1801             :                                          (void *)sr_node_new);
    1802             :         /* Initialize TLV browsing */
    1803           0 :         length = lsa->size - OSPF_LSA_HEADER_SIZE;
    1804           0 :         for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
    1805           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1806           0 :                 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
    1807             :                         /* Got Extended Link information */
    1808           0 :                         srp = get_ext_prefix_sid(tlvh, length);
    1809             :                         /* Update SID if not null */
    1810           0 :                         if (srp != NULL) {
    1811           0 :                                 srp->instance = ntohl(lsah->id.s_addr);
    1812           0 :                                 update_ext_prefix_sid(srn, srp);
    1813             :                         }
    1814             :                 }
    1815           0 :                 length -= TLV_SIZE(tlvh);
    1816             :         }
    1817             : }
    1818             : 
    1819             : /* Delete Segment Routing from Extended Prefix LSA */
    1820           0 : void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
    1821             : {
    1822           0 :         struct listnode *node;
    1823           0 :         struct sr_prefix *srp;
    1824           0 :         struct sr_node *srn;
    1825           0 :         struct lsa_header *lsah = (struct lsa_header *)lsa->data;
    1826           0 :         uint32_t instance = ntohl(lsah->id.s_addr);
    1827             : 
    1828           0 :         osr_debug("SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %pI4",
    1829             :                   __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1830             :                   &lsah->adv_router);
    1831             : 
    1832             :         /* Sanity check */
    1833           0 :         if (OspfSR.neighbors == NULL) {
    1834           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1835             :                          "SR (%s): Abort! no valid SR DataBase", __func__);
    1836           0 :                 return;
    1837             :         }
    1838             : 
    1839             :         /* Search SR Node in hash table from Router ID */
    1840           0 :         srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
    1841           0 :                                             (void *)&(lsah->adv_router));
    1842             : 
    1843             :         /*
    1844             :          * SR-Node may be NULL if it has been remove previously when
    1845             :          * processing Router Information LSA deletion
    1846             :          */
    1847           0 :         if (srn == NULL) {
    1848           0 :                 flog_err(EC_OSPF_SR_INVALID_DB,
    1849             :                          "SR (%s):  Stop! no entry in SRDB for SR Node %pI4",
    1850             :                          __func__, &lsah->adv_router);
    1851           0 :                 return;
    1852             :         }
    1853             : 
    1854             :         /* Search for corresponding Segment Prefix */
    1855           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
    1856           0 :                 if (srp->instance == instance)
    1857             :                         break;
    1858             : 
    1859             :         /* Remove Prefix if found */
    1860           0 :         if ((srp != NULL) && (srp->instance == instance)) {
    1861           0 :                 ospf_zebra_delete_prefix_sid(srp);
    1862           0 :                 listnode_delete(srn->ext_prefix, srp);
    1863           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    1864             :         } else {
    1865           0 :                 flog_err(
    1866             :                         EC_OSPF_SR_INVALID_DB,
    1867             :                         "SR (%s): Didn't found corresponding SR Prefix 7.0.0.%u for SR Node %pI4",
    1868             :                         __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
    1869             :                         &lsah->adv_router);
    1870             :         }
    1871             : }
    1872             : 
    1873             : /*
    1874             :  * Update Prefix SID. Call by ospf_ext_pref_ism_change to
    1875             :  * complete initial CLI command at startup.
    1876             :  *
    1877             :  * @param ifp - Loopback interface
    1878             :  * @param pref - Prefix address of this interface
    1879             :  *
    1880             :  * @return - void
    1881             :  */
    1882           0 : void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p)
    1883             : {
    1884           0 :         struct listnode *node;
    1885           0 :         struct sr_prefix *srp;
    1886             : 
    1887             :         /* Sanity Check */
    1888           0 :         if ((ifp == NULL) || (p == NULL))
    1889             :                 return;
    1890             : 
    1891             :         /*
    1892             :          * Search if there is a Segment Prefix that correspond to this
    1893             :          * interface or prefix, and update it if found
    1894             :          */
    1895           0 :         for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
    1896           0 :                 if ((srp->nhlfe.ifindex == ifp->ifindex)
    1897           0 :                     || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p->u.prefix4))
    1898           0 :                         && (srp->prefv4.prefixlen == p->prefixlen))) {
    1899             : 
    1900             :                         /* Update Interface & Prefix info */
    1901           0 :                         srp->nhlfe.ifindex = ifp->ifindex;
    1902           0 :                         IPV4_ADDR_COPY(&srp->prefv4.prefix, &p->u.prefix4);
    1903           0 :                         srp->prefv4.prefixlen = p->prefixlen;
    1904           0 :                         srp->prefv4.family = p->family;
    1905           0 :                         IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4);
    1906             : 
    1907             :                         /* OK. Let's Schedule Extended Prefix LSA */
    1908           0 :                         srp->instance = ospf_ext_schedule_prefix_index(
    1909           0 :                                 ifp, srp->sid, &srp->prefv4, srp->flags);
    1910             : 
    1911           0 :                         osr_debug(
    1912             :                                 "  |-  Update Node SID %pFX - %u for self SR Node",
    1913             :                                 (struct prefix *)&srp->prefv4, srp->sid);
    1914             : 
    1915             :                         /* Install SID if NO-PHP is set and not EXPLICIT-NULL */
    1916           0 :                         if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
    1917             :                             && !CHECK_FLAG(srp->flags,
    1918             :                                            EXT_SUBTLV_PREFIX_SID_EFLG)) {
    1919           0 :                                 srp->label_in = index2label(srp->sid,
    1920           0 :                                                             OspfSR.self->srgb);
    1921           0 :                                 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
    1922           0 :                                 ospf_zebra_update_prefix_sid(srp);
    1923             :                         }
    1924             :                 }
    1925             :         }
    1926             : }
    1927             : 
    1928             : /*
    1929             :  * Following functions are used to update MPLS LFIB after a SPF run
    1930             :  */
    1931             : 
    1932           0 : static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args)
    1933             : {
    1934             : 
    1935           0 :         struct sr_node *srn = (struct sr_node *)bucket->data;
    1936           0 :         struct listnode *node;
    1937           0 :         struct sr_prefix *srp;
    1938           0 :         bool old;
    1939           0 :         int rc;
    1940             : 
    1941           0 :         osr_debug("  |-  Update Prefix for SR Node %pI4", &srn->adv_router);
    1942             : 
    1943             :         /* Skip Self SR Node */
    1944           0 :         if (srn == OspfSR.self)
    1945             :                 return;
    1946             : 
    1947             :         /* Update Extended Prefix */
    1948           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
    1949             : 
    1950             :                 /* Keep track of valid route */
    1951           0 :                 old = srp->route != NULL;
    1952             : 
    1953             :                 /* Compute the new NHLFE */
    1954           0 :                 rc = compute_prefix_nhlfe(srp);
    1955             : 
    1956             :                 /* Check computation result */
    1957           0 :                 switch (rc) {
    1958             :                 /* Routes are not know, remove old NHLFE if any to avoid loop */
    1959           0 :                 case -1:
    1960           0 :                         if (old)
    1961           0 :                                 ospf_zebra_delete_prefix_sid(srp);
    1962             :                         break;
    1963             :                 /* Routes exist but are not ready, skip it */
    1964             :                 case 0:
    1965             :                         break;
    1966             :                 /* There is at least one route, update NHLFE */
    1967           0 :                 case 1:
    1968           0 :                         ospf_zebra_update_prefix_sid(srp);
    1969           0 :                         break;
    1970             :                 default:
    1971             :                         break;
    1972             :                 }
    1973             :         }
    1974             : }
    1975             : 
    1976          49 : void ospf_sr_update_task(struct ospf *ospf)
    1977             : {
    1978             : 
    1979          49 :         struct timeval start_time, stop_time;
    1980             : 
    1981             :         /* Check ospf and SR status */
    1982          49 :         if ((ospf == NULL) || (OspfSR.status != SR_UP))
    1983          49 :                 return;
    1984             : 
    1985           0 :         monotime(&start_time);
    1986             : 
    1987           0 :         osr_debug("SR (%s): Start SPF update", __func__);
    1988             : 
    1989           0 :         hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
    1990             :                                                  void *))ospf_sr_nhlfe_update,
    1991             :                      NULL);
    1992             : 
    1993           0 :         monotime(&stop_time);
    1994             : 
    1995           0 :         osr_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__,
    1996             :                   (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
    1997             :                           + (stop_time.tv_usec - start_time.tv_usec));
    1998             : }
    1999             : 
    2000             : /*
    2001             :  * --------------------------------------
    2002             :  * Following are vty command functions.
    2003             :  * --------------------------------------
    2004             :  */
    2005             : 
    2006             : /*
    2007             :  * Segment Routing Router configuration
    2008             :  *
    2009             :  * Must be centralize as it concerns both Extended Link/Prefix LSA
    2010             :  * and Router Information LSA. Choose to call it from Extended Prefix
    2011             :  * write_config() call back.
    2012             :  *
    2013             :  * @param vty VTY output
    2014             :  *
    2015             :  * @return none
    2016             :  */
    2017           0 : void ospf_sr_config_write_router(struct vty *vty)
    2018             : {
    2019           0 :         struct listnode *node;
    2020           0 :         struct sr_prefix *srp;
    2021           0 :         uint32_t upper;
    2022             : 
    2023           0 :         if (OspfSR.status == SR_UP)
    2024           0 :                 vty_out(vty, " segment-routing on\n");
    2025             : 
    2026           0 :         upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
    2027           0 :         if ((OspfSR.srgb.start != DEFAULT_SRGB_LABEL)
    2028           0 :             || (OspfSR.srgb.size != DEFAULT_SRGB_SIZE))
    2029           0 :                 vty_out(vty, " segment-routing global-block %u %u",
    2030             :                         OspfSR.srgb.start, upper);
    2031             : 
    2032           0 :         if ((OspfSR.srlb.start != DEFAULT_SRLB_LABEL) ||
    2033           0 :             (OspfSR.srlb.end != DEFAULT_SRLB_END)) {
    2034           0 :                 if ((OspfSR.srgb.start == DEFAULT_SRGB_LABEL) &&
    2035             :                     (OspfSR.srgb.size == DEFAULT_SRGB_SIZE))
    2036           0 :                         vty_out(vty, " segment-routing global-block %u %u",
    2037             :                                 OspfSR.srgb.start, upper);
    2038           0 :                 vty_out(vty, " local-block %u %u\n", OspfSR.srlb.start,
    2039             :                         OspfSR.srlb.end);
    2040             :         } else
    2041           0 :                 vty_out(vty, "\n");
    2042             : 
    2043           0 :         if (OspfSR.msd != 0)
    2044           0 :                 vty_out(vty, " segment-routing node-msd %u\n", OspfSR.msd);
    2045             : 
    2046           0 :         if (OspfSR.self != NULL) {
    2047           0 :                 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
    2048           0 :                         vty_out(vty, " segment-routing prefix %pFX index %u",
    2049             :                                 &srp->prefv4, srp->sid);
    2050           0 :                         if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
    2051           0 :                                 vty_out(vty, " explicit-null\n");
    2052           0 :                         else if (CHECK_FLAG(srp->flags,
    2053             :                                             EXT_SUBTLV_PREFIX_SID_NPFLG))
    2054           0 :                                 vty_out(vty, " no-php-flag\n");
    2055             :                         else
    2056           0 :                                 vty_out(vty, "\n");
    2057             :                 }
    2058             :         }
    2059           0 : }
    2060             : 
    2061           0 : DEFUN(ospf_sr_enable,
    2062             :        ospf_sr_enable_cmd,
    2063             :        "segment-routing on",
    2064             :        SR_STR
    2065             :        "Enable Segment Routing\n")
    2066             : {
    2067             : 
    2068           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
    2069             : 
    2070           0 :         if (OspfSR.status != SR_OFF)
    2071             :                 return CMD_SUCCESS;
    2072             : 
    2073           0 :         if (ospf->vrf_id != VRF_DEFAULT) {
    2074           0 :                 vty_out(vty,
    2075             :                         "Segment Routing is only supported in default VRF\n");
    2076           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2077             :         }
    2078             : 
    2079           0 :         osr_debug("SR: Segment Routing: OFF -> ON");
    2080             : 
    2081             :         /* Start Segment Routing */
    2082           0 :         OspfSR.status = SR_ON;
    2083           0 :         ospf_sr_start(ospf);
    2084             : 
    2085           0 :         return CMD_SUCCESS;
    2086             : }
    2087             : 
    2088           0 : DEFUN (no_ospf_sr_enable,
    2089             :        no_ospf_sr_enable_cmd,
    2090             :        "no segment-routing [on]",
    2091             :        NO_STR
    2092             :        SR_STR
    2093             :        "Disable Segment Routing\n")
    2094             : {
    2095             : 
    2096           0 :         if (OspfSR.status == SR_OFF)
    2097             :                 return CMD_SUCCESS;
    2098             : 
    2099           0 :         osr_debug("SR: Segment Routing: ON -> OFF");
    2100             : 
    2101             :         /* Start by Disabling Extended Link & Prefix LSA */
    2102           0 :         ospf_ext_update_sr(false);
    2103             : 
    2104             :         /* then, disable Router Information SR parameters */
    2105           0 :         ospf_router_info_update_sr(false, OspfSR.self);
    2106             : 
    2107             :         /* Finally, stop Segment Routing */
    2108           0 :         ospf_sr_stop();
    2109             : 
    2110           0 :         return CMD_SUCCESS;
    2111             : }
    2112             : 
    2113           0 : static int ospf_sr_enabled(struct vty *vty)
    2114             : {
    2115           0 :         if (OspfSR.status != SR_OFF)
    2116             :                 return 1;
    2117             : 
    2118           0 :         if (vty)
    2119           0 :                 vty_out(vty, "%% OSPF SR is not turned on\n");
    2120             : 
    2121             :         return 0;
    2122             : }
    2123             : 
    2124             : /* tell if two ranges [r1_lower, r1_upper] and [r2_lower,r2_upper] overlap */
    2125           0 : static bool ranges_overlap(uint32_t r1_lower, uint32_t r1_upper,
    2126             :                            uint32_t r2_lower, uint32_t r2_upper)
    2127             : {
    2128           0 :         return !((r1_upper < r2_lower) || (r1_lower > r2_upper));
    2129             : }
    2130             : 
    2131             : 
    2132             : /* tell if a range is valid */
    2133           0 : static bool sr_range_is_valid(uint32_t lower, uint32_t upper, uint32_t min_size)
    2134             : {
    2135           0 :         return (upper >= lower + min_size);
    2136             : }
    2137             : 
    2138             : /**
    2139             :  * Update SRGB and/or SRLB using new CLI values.
    2140             :  *
    2141             :  * @param gb_lower  Lower bound of the SRGB
    2142             :  * @param gb_upper  Upper bound of the SRGB
    2143             :  * @param lb_lower  Lower bound of the SRLB
    2144             :  * @param lb_upper  Upper bound of the SRLB
    2145             :  *
    2146             :  * @return          0 on success, -1 otherwise
    2147             :  */
    2148           0 : static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper,
    2149             :                             uint32_t lb_lower, uint32_t lb_upper)
    2150             : {
    2151             : 
    2152             :         /* Check if values have changed */
    2153           0 :         bool gb_changed, lb_changed;
    2154           0 :         uint32_t gb_size = gb_upper - gb_lower + 1;
    2155           0 :         uint32_t lb_size = lb_upper - lb_lower + 1;
    2156             : 
    2157           0 :         gb_changed =
    2158           0 :                 (OspfSR.srgb.size != gb_size || OspfSR.srgb.start != gb_lower);
    2159           0 :         lb_changed =
    2160           0 :                 (OspfSR.srlb.end != lb_upper || OspfSR.srlb.start != lb_lower);
    2161           0 :         if (!gb_changed && !lb_changed)
    2162             :                 return 0;
    2163             : 
    2164             :         /* Check if SR is correctly started i.e. Label Manager connected */
    2165           0 :         if (OspfSR.status != SR_UP) {
    2166           0 :                 OspfSR.srgb.size = gb_size;
    2167           0 :                 OspfSR.srgb.start = gb_lower;
    2168           0 :                 OspfSR.srlb.end = lb_upper;
    2169           0 :                 OspfSR.srlb.start = lb_lower;
    2170           0 :                 return 0;
    2171             :         }
    2172             : 
    2173             :         /* Release old SRGB if it has changed and is active. */
    2174           0 :         if (gb_changed) {
    2175             : 
    2176           0 :                 sr_global_block_delete();
    2177             : 
    2178             :                 /* Set new SRGB values - but do not reserve yet (we need to
    2179             :                  * release the SRLB too) */
    2180           0 :                 OspfSR.srgb.size = gb_size;
    2181           0 :                 OspfSR.srgb.start = gb_lower;
    2182           0 :                 if (OspfSR.self != NULL) {
    2183           0 :                         OspfSR.self->srgb.range_size = gb_size;
    2184           0 :                         OspfSR.self->srgb.lower_bound = gb_lower;
    2185             :                 }
    2186             :         }
    2187             :         /* Release old SRLB if it has changed and reserve new block as needed.
    2188             :          */
    2189           0 :         if (lb_changed) {
    2190             : 
    2191           0 :                 sr_local_block_delete();
    2192             : 
    2193             :                 /* Set new SRLB values */
    2194           0 :                 if (sr_local_block_init(lb_lower, lb_upper) < 0) {
    2195           0 :                         ospf_sr_stop();
    2196           0 :                         return -1;
    2197             :                 }
    2198           0 :                 if (OspfSR.self != NULL) {
    2199           0 :                         OspfSR.self->srlb.lower_bound = lb_lower;
    2200           0 :                         OspfSR.self->srlb.range_size = lb_size;
    2201             :                 }
    2202             :         }
    2203             : 
    2204             :         /*
    2205             :          * Try to reserve the new SRGB from the Label Manger. If the
    2206             :          * allocation fails, disable SR until new blocks are successfully
    2207             :          * allocated.
    2208             :          */
    2209           0 :         if (gb_changed) {
    2210           0 :                 if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size)
    2211             :                     < 0) {
    2212           0 :                         ospf_sr_stop();
    2213           0 :                         return -1;
    2214             :                 }
    2215             :         }
    2216             : 
    2217             :         /* Update Self SR-Node */
    2218           0 :         if (OspfSR.self != NULL) {
    2219             :                 /* SRGB is reserved, set Router Information parameters */
    2220           0 :                 ospf_router_info_update_sr(true, OspfSR.self);
    2221             : 
    2222             :                 /* and update NHLFE entries */
    2223           0 :                 if (gb_changed)
    2224           0 :                         hash_iterate(OspfSR.neighbors,
    2225             :                                      (void (*)(struct hash_bucket *,
    2226             :                                                void *))update_in_nhlfe,
    2227             :                                      NULL);
    2228             : 
    2229             :                 /* and update (LAN)-Adjacency SID */
    2230           0 :                 if (lb_changed)
    2231           0 :                         ospf_ext_link_srlb_update();
    2232             :         }
    2233             : 
    2234             :         return 0;
    2235             : }
    2236             : 
    2237           0 : DEFUN(sr_global_label_range, sr_global_label_range_cmd,
    2238             :       "segment-routing global-block (16-1048575) (16-1048575) [local-block (16-1048575) (16-1048575)]",
    2239             :       SR_STR
    2240             :       "Segment Routing Global Block label range\n"
    2241             :       "Lower-bound range in decimal (16-1048575)\n"
    2242             :       "Upper-bound range in decimal (16-1048575)\n"
    2243             :       "Segment Routing Local Block label range\n"
    2244             :       "Lower-bound range in decimal (16-1048575)\n"
    2245             :       "Upper-bound range in decimal (16-1048575)\n")
    2246             : {
    2247           0 :         uint32_t lb_upper, lb_lower;
    2248           0 :         uint32_t gb_upper, gb_lower;
    2249           0 :         int idx_gb_low = 2, idx_gb_up = 3;
    2250           0 :         int idx_lb_low = 5, idx_lb_up = 6;
    2251             : 
    2252             :         /* Get lower and upper bound for mandatory global-block */
    2253           0 :         gb_lower = strtoul(argv[idx_gb_low]->arg, NULL, 10);
    2254           0 :         gb_upper = strtoul(argv[idx_gb_up]->arg, NULL, 10);
    2255             : 
    2256             :         /* SRLB values are taken from vtysh if there, else use the known ones */
    2257           0 :         lb_upper = argc > idx_lb_up ? strtoul(argv[idx_lb_up]->arg, NULL, 10)
    2258             :                                     : OspfSR.srlb.end;
    2259           0 :         lb_lower = argc > idx_lb_low ? strtoul(argv[idx_lb_low]->arg, NULL, 10)
    2260             :                                      : OspfSR.srlb.start;
    2261             : 
    2262             :         /* check correctness of input SRGB */
    2263           0 :         if (!sr_range_is_valid(gb_lower, gb_upper, MIN_SRGB_SIZE)) {
    2264           0 :                 vty_out(vty, "Invalid SRGB range\n");
    2265           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2266             :         }
    2267             : 
    2268             :         /* check correctness of SRLB */
    2269           0 :         if (!sr_range_is_valid(lb_lower, lb_upper, MIN_SRLB_SIZE)) {
    2270           0 :                 vty_out(vty, "Invalid SRLB range\n");
    2271           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2272             :         }
    2273             : 
    2274             :         /* Validate SRGB against SRLB */
    2275           0 :         if (ranges_overlap(gb_lower, gb_upper, lb_lower, lb_upper)) {
    2276           0 :                 vty_out(vty,
    2277             :                         "New SR Global Block (%u/%u) conflicts with Local Block (%u/%u)\n",
    2278             :                         gb_lower, gb_upper, lb_lower, lb_upper);
    2279           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2280             :         }
    2281             : 
    2282           0 :         if (update_sr_blocks(gb_lower, gb_upper, lb_lower, lb_upper) < 0)
    2283             :                 return CMD_WARNING_CONFIG_FAILED;
    2284             :         else
    2285             :                 return CMD_SUCCESS;
    2286             : }
    2287             : 
    2288           0 : DEFUN(no_sr_global_label_range, no_sr_global_label_range_cmd,
    2289             :       "no segment-routing global-block [(16-1048575) (16-1048575) local-block (16-1048575) (16-1048575)]",
    2290             :       NO_STR SR_STR
    2291             :       "Segment Routing Global Block label range\n"
    2292             :       "Lower-bound range in decimal (16-1048575)\n"
    2293             :       "Upper-bound range in decimal (16-1048575)\n"
    2294             :       "Segment Routing Local Block label range\n"
    2295             :       "Lower-bound range in decimal (16-1048575)\n"
    2296             :       "Upper-bound range in decimal (16-1048575)\n")
    2297             : {
    2298           0 :         if (update_sr_blocks(DEFAULT_SRGB_LABEL, DEFAULT_SRGB_END,
    2299             :                              DEFAULT_SRLB_LABEL, DEFAULT_SRLB_END)
    2300             :             < 0)
    2301             :                 return CMD_WARNING_CONFIG_FAILED;
    2302             :         else
    2303           0 :                 return CMD_SUCCESS;
    2304             : }
    2305             : 
    2306           0 : DEFUN (sr_node_msd,
    2307             :        sr_node_msd_cmd,
    2308             :        "segment-routing node-msd (1-16)",
    2309             :        SR_STR
    2310             :        "Maximum Stack Depth for this router\n"
    2311             :        "Maximum number of label that could be stack (1-16)\n")
    2312             : {
    2313           0 :         uint32_t msd;
    2314           0 :         int idx = 1;
    2315             : 
    2316           0 :         if (!ospf_sr_enabled(vty))
    2317             :                 return CMD_WARNING_CONFIG_FAILED;
    2318             : 
    2319             :         /* Get MSD */
    2320           0 :         argv_find(argv, argc, "(1-16)", &idx);
    2321           0 :         msd = strtoul(argv[idx]->arg, NULL, 10);
    2322           0 :         if (msd < 1 || msd > MPLS_MAX_LABELS) {
    2323           0 :                 vty_out(vty, "MSD must be comprise between 1 and %u\n",
    2324             :                         MPLS_MAX_LABELS);
    2325           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2326             :         }
    2327             : 
    2328             :         /* Check if value has changed */
    2329           0 :         if (OspfSR.msd == msd)
    2330             :                 return CMD_SUCCESS;
    2331             : 
    2332             :         /* Set this router MSD */
    2333           0 :         OspfSR.msd = msd;
    2334           0 :         if (OspfSR.self != NULL) {
    2335           0 :                 OspfSR.self->msd = msd;
    2336             : 
    2337             :                 /* Set Router Information parameters if SR is UP */
    2338           0 :                 if (OspfSR.status == SR_UP)
    2339           0 :                         ospf_router_info_update_sr(true, OspfSR.self);
    2340             :         }
    2341             : 
    2342             :         return CMD_SUCCESS;
    2343             : }
    2344             : 
    2345           0 : DEFUN (no_sr_node_msd,
    2346             :         no_sr_node_msd_cmd,
    2347             :         "no segment-routing node-msd [(1-16)]",
    2348             :         NO_STR
    2349             :         SR_STR
    2350             :         "Maximum Stack Depth for this router\n"
    2351             :         "Maximum number of label that could be stack (1-16)\n")
    2352             : {
    2353             : 
    2354           0 :         if (!ospf_sr_enabled(vty))
    2355             :                 return CMD_WARNING_CONFIG_FAILED;
    2356             : 
    2357             :         /* unset this router MSD */
    2358           0 :         OspfSR.msd = 0;
    2359           0 :         if (OspfSR.self != NULL) {
    2360           0 :                 OspfSR.self->msd = 0;
    2361             : 
    2362             :                 /* Set Router Information parameters if SR is UP */
    2363           0 :                 if (OspfSR.status == SR_UP)
    2364           0 :                         ospf_router_info_update_sr(true, OspfSR.self);
    2365             :         }
    2366             : 
    2367             :         return CMD_SUCCESS;
    2368             : }
    2369             : 
    2370           0 : DEFUN (sr_prefix_sid,
    2371             :        sr_prefix_sid_cmd,
    2372             :        "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
    2373             :        SR_STR
    2374             :        "Prefix SID\n"
    2375             :        "IPv4 Prefix as A.B.C.D/M\n"
    2376             :        "SID index for this prefix in decimal (0-65535)\n"
    2377             :        "Index value inside SRGB (lower_bound < index < upper_bound)\n"
    2378             :        "Don't request Penultimate Hop Popping (PHP)\n"
    2379             :        "Upstream neighbor must replace prefix-sid with explicit null label\n")
    2380             : {
    2381           0 :         int idx = 0;
    2382           0 :         struct prefix p, pexist;
    2383           0 :         uint32_t index;
    2384           0 :         struct listnode *node;
    2385           0 :         struct sr_prefix *srp, *exist = NULL;
    2386           0 :         struct interface *ifp;
    2387           0 :         bool no_php_flag = false;
    2388           0 :         bool exp_null = false;
    2389           0 :         bool index_in_use = false;
    2390           0 :         uint8_t desired_flags = 0;
    2391             : 
    2392           0 :         if (!ospf_sr_enabled(vty))
    2393             :                 return CMD_WARNING_CONFIG_FAILED;
    2394             : 
    2395             :         /* Get network prefix */
    2396           0 :         argv_find(argv, argc, "A.B.C.D/M", &idx);
    2397           0 :         if (!str2prefix(argv[idx]->arg, &p)) {
    2398           0 :                 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
    2399           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2400             :         }
    2401             : 
    2402             :         /* Get & verify index value */
    2403           0 :         argv_find(argv, argc, "(0-65535)", &idx);
    2404           0 :         index = strtoul(argv[idx]->arg, NULL, 10);
    2405           0 :         if (index > OspfSR.srgb.size - 1) {
    2406           0 :                 vty_out(vty, "Index %u must be lower than range size %u\n",
    2407             :                         index, OspfSR.srgb.size);
    2408           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2409             :         }
    2410             : 
    2411             :         /* Get options */
    2412           0 :         no_php_flag = argv_find(argv, argc, "no-php-flag", &idx);
    2413           0 :         exp_null = argv_find(argv, argc, "explicit-null", &idx);
    2414             : 
    2415           0 :         desired_flags |= no_php_flag ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
    2416           0 :         desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
    2417           0 :         desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_EFLG : 0;
    2418             : 
    2419             :         /* Search for an existing Prefix-SID */
    2420           0 :         for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
    2421           0 :                 if (prefix_same((struct prefix *)&srp->prefv4, &p))
    2422           0 :                         exist = srp;
    2423           0 :                 if (srp->sid == index) {
    2424           0 :                         index_in_use = true;
    2425           0 :                         pexist = p;
    2426             :                 }
    2427             :         }
    2428             : 
    2429             :         /* done if prefix segment already there with same index and flags */
    2430           0 :         if (exist && exist->sid == index && exist->flags == desired_flags)
    2431             :                 return CMD_SUCCESS;
    2432             : 
    2433             :         /* deny if index is already in use by a distinct prefix */
    2434           0 :         if (!exist && index_in_use) {
    2435           0 :                 vty_out(vty, "Index %u is already used by %pFX\n", index,
    2436             :                         &pexist);
    2437           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2438             :         }
    2439             : 
    2440             :         /* First, remove old NHLFE if installed */
    2441           0 :         if (exist && CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
    2442           0 :             && !CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
    2443           0 :                 ospf_zebra_delete_prefix_sid(exist);
    2444             : 
    2445             :         /* Create new Extended Prefix to SRDB if not found */
    2446           0 :         if (exist == NULL) {
    2447           0 :                 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
    2448           0 :                 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p.u.prefix4);
    2449           0 :                 srp->prefv4.prefixlen = p.prefixlen;
    2450           0 :                 srp->prefv4.family = p.family;
    2451           0 :                 srp->sid = index;
    2452           0 :                 srp->type = LOCAL_SID;
    2453             :         } else {
    2454             :                 /* we work on the existing SR prefix */
    2455             :                 srp = exist;
    2456             :         }
    2457             : 
    2458             :         /* Reset labels to handle flag update */
    2459           0 :         srp->label_in = 0;
    2460           0 :         srp->nhlfe.label_out = 0;
    2461           0 :         srp->sid = index;
    2462           0 :         srp->flags = desired_flags;
    2463             : 
    2464             :         /* If NO PHP flag is present, compute NHLFE and set label */
    2465           0 :         if (no_php_flag) {
    2466           0 :                 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
    2467           0 :                 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
    2468             :         }
    2469             : 
    2470           0 :         osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
    2471             :                   (struct prefix *)&srp->prefv4);
    2472             : 
    2473             :         /* Get Interface and check if it is a Loopback */
    2474           0 :         ifp = if_lookup_prefix(&p, VRF_DEFAULT);
    2475           0 :         if (ifp == NULL) {
    2476             :                 /*
    2477             :                  * Interface could be not yet available i.e. when this
    2478             :                  * command is in the configuration file, OSPF is not yet
    2479             :                  * ready. In this case, store the prefix SID for latter
    2480             :                  * update of this Extended Prefix
    2481             :                  */
    2482           0 :                 if (exist == NULL)
    2483           0 :                         listnode_add(OspfSR.self->ext_prefix, srp);
    2484           0 :                 zlog_info(
    2485             :                         "Interface for prefix %pFX not found. Deferred LSA flooding",
    2486             :                         &p);
    2487           0 :                 return CMD_SUCCESS;
    2488             :         }
    2489             : 
    2490           0 :         if (!if_is_loopback(ifp)) {
    2491           0 :                 vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
    2492           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    2493           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2494             :         }
    2495           0 :         srp->nhlfe.ifindex = ifp->ifindex;
    2496             : 
    2497             :         /* Add SR Prefix if new */
    2498           0 :         if (!exist)
    2499           0 :                 listnode_add(OspfSR.self->ext_prefix, srp);
    2500             : 
    2501             :         /* Update Prefix SID if SR is UP */
    2502           0 :         if (OspfSR.status == SR_UP) {
    2503           0 :                 if (no_php_flag && !exp_null)
    2504           0 :                         ospf_zebra_update_prefix_sid(srp);
    2505             :         } else
    2506             :                 return CMD_SUCCESS;
    2507             : 
    2508             :         /* Finally, update Extended Prefix LSA id SR is UP */
    2509           0 :         srp->instance = ospf_ext_schedule_prefix_index(
    2510           0 :                 ifp, srp->sid, &srp->prefv4, srp->flags);
    2511           0 :         if (srp->instance == 0) {
    2512           0 :                 vty_out(vty, "Unable to set index %u for prefix %pFX\n",
    2513             :                         index, &p);
    2514           0 :                 return CMD_WARNING;
    2515             :         }
    2516             : 
    2517             :         return CMD_SUCCESS;
    2518             : }
    2519             : 
    2520           0 : DEFUN (no_sr_prefix_sid,
    2521             :        no_sr_prefix_sid_cmd,
    2522             :        "no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
    2523             :        NO_STR
    2524             :        SR_STR
    2525             :        "Prefix SID\n"
    2526             :        "IPv4 Prefix as A.B.C.D/M\n"
    2527             :        "SID index for this prefix in decimal (0-65535)\n"
    2528             :        "Index value inside SRGB (lower_bound < index < upper_bound)\n"
    2529             :        "Don't request Penultimate Hop Popping (PHP)\n"
    2530             :        "Upstream neighbor must replace prefix-sid with explicit null label\n")
    2531             : {
    2532           0 :         int idx = 0;
    2533           0 :         struct prefix p;
    2534           0 :         struct listnode *node;
    2535           0 :         struct sr_prefix *srp;
    2536           0 :         struct interface *ifp;
    2537           0 :         bool found = false;
    2538           0 :         int rc;
    2539             : 
    2540           0 :         if (!ospf_sr_enabled(vty))
    2541             :                 return CMD_WARNING_CONFIG_FAILED;
    2542             : 
    2543           0 :         if (OspfSR.status != SR_UP)
    2544             :                 return CMD_SUCCESS;
    2545             : 
    2546             :         /* Get network prefix */
    2547           0 :         argv_find(argv, argc, "A.B.C.D/M", &idx);
    2548           0 :         rc = str2prefix(argv[idx]->arg, &p);
    2549           0 :         if (!rc) {
    2550           0 :                 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
    2551           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2552             :         }
    2553             : 
    2554             :         /* check that the prefix is already set */
    2555           0 :         for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
    2556           0 :                 if (IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
    2557           0 :                     && (srp->prefv4.prefixlen == p.prefixlen)) {
    2558             :                         found = true;
    2559             :                         break;
    2560             :                 }
    2561             : 
    2562           0 :         if (!found) {
    2563           0 :                 vty_out(vty, "Prefix %s is not found. Abort!\n",
    2564           0 :                         argv[idx]->arg);
    2565           0 :                 return CMD_WARNING_CONFIG_FAILED;
    2566             :         }
    2567             : 
    2568           0 :         osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
    2569             :                   (struct prefix *)&srp->prefv4, srp->sid);
    2570             : 
    2571             :         /* Get Interface */
    2572           0 :         ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
    2573           0 :         if (ifp == NULL) {
    2574           0 :                 vty_out(vty, "interface for prefix %s not found.\n",
    2575           0 :                         argv[idx]->arg);
    2576             :                 /* silently remove from list */
    2577           0 :                 listnode_delete(OspfSR.self->ext_prefix, srp);
    2578           0 :                 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    2579           0 :                 return CMD_SUCCESS;
    2580             :         }
    2581             : 
    2582             :         /* Update Extended Prefix LSA */
    2583           0 :         if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
    2584           0 :                 vty_out(vty, "No corresponding loopback interface. Abort!\n");
    2585           0 :                 return CMD_WARNING;
    2586             :         }
    2587             : 
    2588             :         /* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
    2589           0 :         if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
    2590             :             && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
    2591           0 :                 ospf_zebra_delete_prefix_sid(srp);
    2592             : 
    2593             :         /* OK, all is clean, remove SRP from SRDB */
    2594           0 :         listnode_delete(OspfSR.self->ext_prefix, srp);
    2595           0 :         XFREE(MTYPE_OSPF_SR_PARAMS, srp);
    2596             : 
    2597           0 :         return CMD_SUCCESS;
    2598             : }
    2599             : 
    2600             : 
    2601           0 : static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
    2602             :                        mpls_label_t label_out)
    2603             : {
    2604           0 :         if (size < 24)
    2605             :                 return NULL;
    2606             : 
    2607           0 :         switch (label_out) {
    2608           0 :         case MPLS_LABEL_IMPLICIT_NULL:
    2609           0 :                 snprintf(buf, size, "Pop(%u)", label_in);
    2610           0 :                 break;
    2611           0 :         case MPLS_LABEL_IPV4_EXPLICIT_NULL:
    2612           0 :                 if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
    2613           0 :                         snprintf(buf, size, "no-op.");
    2614             :                 else
    2615           0 :                         snprintf(buf, size, "Swap(%u, null)", label_in);
    2616             :                 break;
    2617           0 :         case MPLS_INVALID_LABEL:
    2618           0 :                 snprintf(buf, size, "no-op.");
    2619           0 :                 break;
    2620           0 :         default:
    2621           0 :                 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
    2622           0 :                 break;
    2623             :         }
    2624             :         return buf;
    2625             : }
    2626             : 
    2627           0 : static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json,
    2628             :                            struct sr_prefix *srp)
    2629             : {
    2630             : 
    2631           0 :         struct listnode *node;
    2632           0 :         struct ospf_path *path;
    2633           0 :         struct interface *itf;
    2634           0 :         json_object *json_route = NULL, *json_obj;
    2635           0 :         char pref[19];
    2636           0 :         char sid[22];
    2637           0 :         char op[32];
    2638           0 :         char buf[PREFIX_STRLEN];
    2639           0 :         int indent = 0;
    2640             : 
    2641           0 :         snprintfrr(pref, 19, "%pFX", (struct prefix *)&srp->prefv4);
    2642           0 :         snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
    2643           0 :         if (json) {
    2644           0 :                 json_object_string_add(json, "prefix", pref);
    2645           0 :                 json_object_int_add(json, "sid", srp->sid);
    2646           0 :                 json_object_int_add(json, "inputLabel", srp->label_in);
    2647             :         } else {
    2648           0 :                 sbuf_push(sbuf, 0, "%18s  %21s  ", pref, sid);
    2649             :         }
    2650             : 
    2651             :         /* Check if it is a Local Node SID */
    2652           0 :         if (srp->type == LOCAL_SID) {
    2653           0 :                 itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
    2654           0 :                 if (json) {
    2655           0 :                         if (!json_route) {
    2656           0 :                                 json_route = json_object_new_array();
    2657           0 :                                 json_object_object_add(json, "prefixRoute",
    2658             :                                                        json_route);
    2659             :                         }
    2660           0 :                         json_obj = json_object_new_object();
    2661           0 :                         json_object_int_add(json_obj, "outputLabel",
    2662           0 :                                             srp->nhlfe.label_out);
    2663           0 :                         json_object_string_add(json_obj, "interface",
    2664             :                                                itf ? itf->name : "-");
    2665           0 :                         json_object_string_addf(json_obj, "nexthop", "%pI4",
    2666             :                                                 &srp->nhlfe.nexthop);
    2667           0 :                         json_object_array_add(json_route, json_obj);
    2668             :                 } else {
    2669           0 :                         sbuf_push(sbuf, 0, "%20s  %9s  %15s\n",
    2670             :                                   sr_op2str(op, 32, srp->label_in,
    2671             :                                             srp->nhlfe.label_out),
    2672             :                                   itf ? itf->name : "-",
    2673           0 :                                   inet_ntop(AF_INET, &srp->nhlfe.nexthop,
    2674             :                                             buf, sizeof(buf)));
    2675             :                 }
    2676           0 :                 return;
    2677             :         }
    2678             : 
    2679             :         /* Check if we have a valid path for this prefix */
    2680           0 :         if (srp->route == NULL) {
    2681           0 :                 if (!json) {
    2682           0 :                         sbuf_push(sbuf, 0, "\n");
    2683             :                 }
    2684           0 :                 return;
    2685             :         }
    2686             : 
    2687             :         /* Process list of OSPF paths */
    2688           0 :         for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
    2689           0 :                 itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT);
    2690           0 :                 if (json) {
    2691           0 :                         if (!json_route) {
    2692           0 :                                 json_route = json_object_new_array();
    2693           0 :                                 json_object_object_add(json, "prefixRoute",
    2694             :                                                        json_route);
    2695             :                         }
    2696           0 :                         json_obj = json_object_new_object();
    2697           0 :                         json_object_int_add(json_obj, "outputLabel",
    2698           0 :                                             path->srni.label_out);
    2699           0 :                         json_object_string_add(json_obj, "interface",
    2700             :                                                itf ? itf->name : "-");
    2701           0 :                         json_object_string_addf(json_obj, "nexthop", "%pI4",
    2702             :                                                 &path->nexthop);
    2703           0 :                         json_object_array_add(json_route, json_obj);
    2704             :                 } else {
    2705           0 :                         sbuf_push(sbuf, indent, "%20s  %9s  %15s\n",
    2706             :                                   sr_op2str(op, 32, srp->label_in,
    2707             :                                             path->srni.label_out),
    2708             :                                   itf ? itf->name : "-",
    2709           0 :                                   inet_ntop(AF_INET, &path->nexthop, buf,
    2710             :                                             sizeof(buf)));
    2711             :                         /* Offset to align information for ECMP */
    2712           0 :                         indent = 43;
    2713             :                 }
    2714             :         }
    2715             : }
    2716             : 
    2717           0 : static void show_sr_node(struct vty *vty, struct json_object *json,
    2718             :                          struct sr_node *srn)
    2719             : {
    2720             : 
    2721           0 :         struct listnode *node;
    2722           0 :         struct sr_link *srl;
    2723           0 :         struct sr_prefix *srp;
    2724           0 :         struct interface *itf;
    2725           0 :         struct sbuf sbuf;
    2726           0 :         char pref[19];
    2727           0 :         char sid[22];
    2728           0 :         char op[32];
    2729           0 :         char buf[PREFIX_STRLEN];
    2730           0 :         uint32_t upper;
    2731           0 :         json_object *json_node = NULL, *json_algo, *json_obj;
    2732           0 :         json_object *json_prefix = NULL, *json_link = NULL;
    2733             : 
    2734             :         /* Sanity Check */
    2735           0 :         if (srn == NULL)
    2736           0 :                 return;
    2737             : 
    2738           0 :         sbuf_init(&sbuf, NULL, 0);
    2739             : 
    2740           0 :         if (json) {
    2741           0 :                 json_node = json_object_new_object();
    2742           0 :                 json_object_string_addf(json_node, "routerID", "%pI4",
    2743             :                                         &srn->adv_router);
    2744           0 :                 json_object_int_add(json_node, "srgbSize",
    2745           0 :                                     srn->srgb.range_size);
    2746           0 :                 json_object_int_add(json_node, "srgbLabel",
    2747           0 :                                     srn->srgb.lower_bound);
    2748           0 :                 json_object_int_add(json_node, "srlbSize",
    2749           0 :                                     srn->srlb.range_size);
    2750           0 :                 json_object_int_add(json_node, "srlbLabel",
    2751           0 :                                     srn->srlb.lower_bound);
    2752           0 :                 json_algo = json_object_new_array();
    2753           0 :                 json_object_object_add(json_node, "algorithms", json_algo);
    2754           0 :                 for (int i = 0; i < ALGORITHM_COUNT; i++) {
    2755           0 :                         if (srn->algo[i] == SR_ALGORITHM_UNSET)
    2756           0 :                                 continue;
    2757           0 :                         json_obj = json_object_new_object();
    2758           0 :                         char tmp[2];
    2759             : 
    2760           0 :                         snprintf(tmp, sizeof(tmp), "%u", i);
    2761           0 :                         json_object_string_add(json_obj, tmp,
    2762           0 :                                                srn->algo[i] == SR_ALGORITHM_SPF
    2763             :                                                        ? "SPF"
    2764             :                                                        : "S-SPF");
    2765           0 :                         json_object_array_add(json_algo, json_obj);
    2766             :                 }
    2767           0 :                 if (srn->msd != 0)
    2768           0 :                         json_object_int_add(json_node, "nodeMsd", srn->msd);
    2769             :         } else {
    2770           0 :                 sbuf_push(&sbuf, 0, "SR-Node: %pI4", &srn->adv_router);
    2771           0 :                 upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
    2772           0 :                 sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
    2773             :                           srn->srgb.lower_bound, upper);
    2774           0 :                 upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
    2775           0 :                 sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
    2776             :                           srn->srlb.lower_bound, upper);
    2777           0 :                 sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
    2778           0 :                           srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
    2779           0 :                 for (int i = 1; i < ALGORITHM_COUNT; i++) {
    2780           0 :                         if (srn->algo[i] == SR_ALGORITHM_UNSET)
    2781           0 :                                 continue;
    2782           0 :                         sbuf_push(&sbuf, 0, "/%s",
    2783             :                                   srn->algo[i] == SR_ALGORITHM_SPF ? "SPF"
    2784             :                                                                    : "S-SPF");
    2785             :                 }
    2786           0 :                 if (srn->msd != 0)
    2787           0 :                         sbuf_push(&sbuf, 0, "\tMSD: %u", srn->msd);
    2788             :         }
    2789             : 
    2790           0 :         if (!json) {
    2791           0 :                 sbuf_push(&sbuf, 0,
    2792             :                           "\n\n    Prefix or Link       Node or Adj. SID       Label Operation  Interface          Nexthop\n");
    2793           0 :                 sbuf_push(&sbuf, 0,
    2794             :                           "------------------  ---------------------  --------------------  ---------  ---------------\n");
    2795             :         }
    2796           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
    2797           0 :                 if (json) {
    2798           0 :                         if (!json_prefix) {
    2799           0 :                                 json_prefix = json_object_new_array();
    2800           0 :                                 json_object_object_add(json_node,
    2801             :                                                        "extendedPrefix",
    2802             :                                                        json_prefix);
    2803             :                         }
    2804           0 :                         json_obj = json_object_new_object();
    2805           0 :                         show_sr_prefix(NULL, json_obj, srp);
    2806           0 :                         json_object_array_add(json_prefix, json_obj);
    2807             :                 } else {
    2808           0 :                         show_sr_prefix(&sbuf, NULL, srp);
    2809             :                 }
    2810             :         }
    2811             : 
    2812           0 :         for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
    2813           0 :                 snprintfrr(pref, 19, "%pI4/32", &srl->itf_addr);
    2814           0 :                 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
    2815           0 :                 itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
    2816           0 :                 if (json) {
    2817           0 :                         if (!json_link) {
    2818           0 :                                 json_link = json_object_new_array();
    2819           0 :                                 json_object_object_add(
    2820             :                                         json_node, "extendedLink", json_link);
    2821             :                         }
    2822             :                         /* Primary Link */
    2823           0 :                         json_obj = json_object_new_object();
    2824           0 :                         json_object_string_add(json_obj, "prefix", pref);
    2825           0 :                         json_object_int_add(json_obj, "sid", srl->sid[0]);
    2826           0 :                         json_object_int_add(json_obj, "inputLabel",
    2827           0 :                                             srl->nhlfe[0].label_in);
    2828           0 :                         json_object_int_add(json_obj, "outputLabel",
    2829           0 :                                             srl->nhlfe[0].label_out);
    2830           0 :                         json_object_string_add(json_obj, "interface",
    2831             :                                                itf ? itf->name : "-");
    2832           0 :                         json_object_string_addf(json_obj, "nexthop", "%pI4",
    2833             :                                                 &srl->nhlfe[0].nexthop);
    2834           0 :                         json_object_array_add(json_link, json_obj);
    2835             :                         /* Backup Link */
    2836           0 :                         json_obj = json_object_new_object();
    2837           0 :                         snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
    2838           0 :                         json_object_string_add(json_obj, "prefix", pref);
    2839           0 :                         json_object_int_add(json_obj, "sid", srl->sid[1]);
    2840           0 :                         json_object_int_add(json_obj, "inputLabel",
    2841           0 :                                             srl->nhlfe[1].label_in);
    2842           0 :                         json_object_int_add(json_obj, "outputLabel",
    2843           0 :                                             srl->nhlfe[1].label_out);
    2844           0 :                         json_object_string_add(json_obj, "interface",
    2845             :                                                itf ? itf->name : "-");
    2846           0 :                         json_object_string_addf(json_obj, "nexthop", "%pI4",
    2847             :                                                 &srl->nhlfe[1].nexthop);
    2848           0 :                         json_object_array_add(json_link, json_obj);
    2849             :                 } else {
    2850           0 :                         sbuf_push(&sbuf, 0, "%18s  %21s  %20s  %9s  %15s\n",
    2851             :                                   pref, sid,
    2852             :                                   sr_op2str(op, 32, srl->nhlfe[0].label_in,
    2853             :                                             srl->nhlfe[0].label_out),
    2854             :                                   itf ? itf->name : "-",
    2855           0 :                                   inet_ntop(AF_INET, &srl->nhlfe[0].nexthop,
    2856             :                                             buf, sizeof(buf)));
    2857           0 :                         snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
    2858           0 :                         sbuf_push(&sbuf, 0, "%18s  %21s  %20s  %9s  %15s\n",
    2859             :                                   pref, sid,
    2860             :                                   sr_op2str(op, 32, srl->nhlfe[1].label_in,
    2861             :                                             srl->nhlfe[1].label_out),
    2862             :                                   itf ? itf->name : "-",
    2863           0 :                                   inet_ntop(AF_INET, &srl->nhlfe[1].nexthop,
    2864             :                                           buf, sizeof(buf)));
    2865             :                 }
    2866             :         }
    2867           0 :         if (json)
    2868           0 :                 json_object_array_add(json, json_node);
    2869             :         else
    2870           0 :                 vty_out(vty, "%s\n", sbuf_buf(&sbuf));
    2871             : 
    2872           0 :         sbuf_free(&sbuf);
    2873             : }
    2874             : 
    2875           0 : static void show_vty_srdb(struct hash_bucket *bucket, void *args)
    2876             : {
    2877           0 :         struct vty *vty = (struct vty *)args;
    2878           0 :         struct sr_node *srn = (struct sr_node *)bucket->data;
    2879             : 
    2880           0 :         show_sr_node(vty, NULL, srn);
    2881           0 : }
    2882             : 
    2883           0 : static void show_json_srdb(struct hash_bucket *bucket, void *args)
    2884             : {
    2885           0 :         struct json_object *json = (struct json_object *)args;
    2886           0 :         struct sr_node *srn = (struct sr_node *)bucket->data;
    2887             : 
    2888           0 :         show_sr_node(NULL, json, srn);
    2889           0 : }
    2890             : 
    2891           0 : DEFUN (show_ip_opsf_srdb,
    2892             :        show_ip_ospf_srdb_cmd,
    2893             :        "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
    2894             :        SHOW_STR
    2895             :        IP_STR
    2896             :        OSPF_STR
    2897             :        "Database summary\n"
    2898             :        "Show Segment Routing Data Base\n"
    2899             :        "Advertising SR node\n"
    2900             :        "Advertising SR node ID (as an IP address)\n"
    2901             :        "Self-originated SR node\n"
    2902             :        JSON_STR)
    2903             : {
    2904           0 :         int idx = 0;
    2905           0 :         struct in_addr rid;
    2906           0 :         struct sr_node *srn;
    2907           0 :         bool uj = use_json(argc, argv);
    2908           0 :         json_object *json = NULL, *json_node_array = NULL;
    2909             : 
    2910           0 :         if (OspfSR.status == SR_OFF) {
    2911           0 :                 vty_out(vty, "Segment Routing is disabled on this router\n");
    2912           0 :                 return CMD_WARNING;
    2913             :         }
    2914             : 
    2915           0 :         if (uj) {
    2916           0 :                 json = json_object_new_object();
    2917           0 :                 json_node_array = json_object_new_array();
    2918           0 :                 json_object_string_addf(json, "srdbID", "%pI4",
    2919           0 :                                         &OspfSR.self->adv_router);
    2920           0 :                 json_object_object_add(json, "srNodes", json_node_array);
    2921             :         } else {
    2922           0 :                 vty_out(vty,
    2923             :                         "\n\t\tOSPF Segment Routing database for ID %pI4\n\n",
    2924           0 :                         &OspfSR.self->adv_router);
    2925             :         }
    2926             : 
    2927           0 :         if (argv_find(argv, argc, "self-originate", &idx)) {
    2928           0 :                 srn = OspfSR.self;
    2929           0 :                 show_sr_node(vty, json_node_array, srn);
    2930           0 :                 if (uj)
    2931           0 :                         vty_json(vty, json);
    2932           0 :                 return CMD_SUCCESS;
    2933             :         }
    2934             : 
    2935           0 :         if (argv_find(argv, argc, "A.B.C.D", &idx)) {
    2936           0 :                 if (!inet_aton(argv[idx]->arg, &rid)) {
    2937           0 :                         vty_out(vty, "Specified Router ID %s is invalid\n",
    2938           0 :                                 argv[idx]->arg);
    2939           0 :                         return CMD_WARNING_CONFIG_FAILED;
    2940             :                 }
    2941             :                 /* Get the SR Node from the SRDB */
    2942           0 :                 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
    2943             :                                                     (void *)&rid);
    2944           0 :                 show_sr_node(vty, json_node_array, srn);
    2945           0 :                 if (uj)
    2946           0 :                         vty_json(vty, json);
    2947           0 :                 return CMD_SUCCESS;
    2948             :         }
    2949             : 
    2950             :         /* No parameters have been provided, Iterate through all the SRDB */
    2951           0 :         if (uj) {
    2952           0 :                 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
    2953             :                                                          void *))show_json_srdb,
    2954             :                              (void *)json_node_array);
    2955           0 :                 vty_json(vty, json);
    2956             :         } else {
    2957           0 :                 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
    2958             :                                                          void *))show_vty_srdb,
    2959             :                              (void *)vty);
    2960             :         }
    2961             :         return CMD_SUCCESS;
    2962             : }
    2963             : 
    2964             : /* Install new CLI commands */
    2965           4 : void ospf_sr_register_vty(void)
    2966             : {
    2967           4 :         install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
    2968             : 
    2969           4 :         install_element(OSPF_NODE, &ospf_sr_enable_cmd);
    2970           4 :         install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
    2971           4 :         install_element(OSPF_NODE, &sr_global_label_range_cmd);
    2972           4 :         install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
    2973           4 :         install_element(OSPF_NODE, &sr_node_msd_cmd);
    2974           4 :         install_element(OSPF_NODE, &no_sr_node_msd_cmd);
    2975           4 :         install_element(OSPF_NODE, &sr_prefix_sid_cmd);
    2976           4 :         install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
    2977           4 : }

Generated by: LCOV version v1.16-topotato