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