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