]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_sr.c
Merge pull request #11158 from cyberstormdotmu/master
[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(OspfSR));
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 /* update LSA ID */
1467 srn->instance = ntohl(lsah->id.s_addr);
1468 /* Copy SRGB */
1469 srn->srgb.range_size = srgb.range_size;
1470 srn->srgb.lower_bound = srgb.lower_bound;
1471 }
1472
1473 /* Update Algorithm, SRLB and MSD if present */
1474 if (algo != NULL) {
1475 int i;
1476 for (i = 0; i < ntohs(algo->header.length); i++)
1477 srn->algo[i] = algo->value[0];
1478 for (; i < ALGORITHM_COUNT; i++)
1479 srn->algo[i] = SR_ALGORITHM_UNSET;
1480 } else {
1481 srn->algo[0] = SR_ALGORITHM_SPF;
1482 }
1483 srn->msd = msd;
1484 if (ri_srlb != NULL) {
1485 srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size));
1486 srn->srlb.lower_bound = GET_LABEL(ntohl(ri_srlb->lower.value));
1487 }
1488
1489 /* Check if SRGB has changed */
1490 if ((srn->srgb.range_size == srgb.range_size)
1491 && (srn->srgb.lower_bound == srgb.lower_bound))
1492 return;
1493
1494 /* Copy SRGB */
1495 srn->srgb.range_size = srgb.range_size;
1496 srn->srgb.lower_bound = srgb.lower_bound;
1497
1498 osr_debug(" |- Update SR-Node[%pI4], SRGB[%u/%u], SRLB[%u/%u], Algo[%u], MSD[%u]",
1499 &srn->adv_router, srn->srgb.lower_bound, srn->srgb.range_size,
1500 srn->srlb.lower_bound, srn->srlb.range_size, srn->algo[0],
1501 srn->msd);
1502
1503 /* ... and NHLFE if it is a neighbor SR node */
1504 if (srn->neighbor == OspfSR.self)
1505 hash_iterate(OspfSR.neighbors, update_out_nhlfe, srn);
1506 }
1507
1508 /*
1509 * Delete SR Node entry in hash table information corresponding to an expired
1510 * Router Information LSA
1511 */
1512 void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
1513 {
1514 struct sr_node *srn;
1515 struct lsa_header *lsah = lsa->data;
1516
1517 osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", __func__,
1518 &lsah->adv_router, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)));
1519
1520 /* Sanity check */
1521 if (OspfSR.neighbors == NULL) {
1522 flog_err(EC_OSPF_SR_INVALID_DB,
1523 "SR (%s): Abort! no valid SR Data Base", __func__);
1524 return;
1525 }
1526
1527 /* Release Router ID entry in SRDB hash table */
1528 srn = hash_release(OspfSR.neighbors, &(lsah->adv_router));
1529
1530 /* Sanity check */
1531 if (srn == NULL) {
1532 flog_err(EC_OSPF_SR_NODE_CREATE,
1533 "SR (%s): Abort! no entry in SRDB for SR Node %pI4",
1534 __func__, &lsah->adv_router);
1535 return;
1536 }
1537
1538 if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
1539 flog_err(
1540 EC_OSPF_SR_INVALID_LSA_ID,
1541 "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4",
1542 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1543 &lsah->adv_router);
1544 return;
1545 }
1546
1547 /* Remove SR node */
1548 sr_node_del(srn);
1549 }
1550
1551 /* Update Segment Routing from Extended Link LSA */
1552 void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
1553 {
1554 struct sr_node *srn;
1555 struct tlv_header *tlvh;
1556 struct lsa_header *lsah = lsa->data;
1557 struct sr_link *srl;
1558
1559 int length;
1560
1561 osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4",
1562 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1563 &lsah->adv_router);
1564
1565 /* Sanity check */
1566 if (OspfSR.neighbors == NULL) {
1567 flog_err(EC_OSPF_SR_INVALID_DB,
1568 "SR (%s): Abort! no valid SR DataBase", __func__);
1569 return;
1570 }
1571
1572 /* Get SR Node in hash table from Router ID */
1573 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1574 (void *)&(lsah->adv_router),
1575 (void *)sr_node_new);
1576
1577 /* Initialize TLV browsing */
1578 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1579 for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
1580 tlvh = TLV_HDR_NEXT(tlvh)) {
1581 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1582 /* Got Extended Link information */
1583 srl = get_ext_link_sid(tlvh, length);
1584 /* Update SID if not null */
1585 if (srl != NULL) {
1586 srl->instance = ntohl(lsah->id.s_addr);
1587 update_ext_link_sid(srn, srl, lsa->flags);
1588 }
1589 }
1590 length -= TLV_SIZE(tlvh);
1591 }
1592 }
1593
1594 /* Delete Segment Routing from Extended Link LSA */
1595 void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
1596 {
1597 struct listnode *node;
1598 struct sr_link *srl;
1599 struct sr_node *srn;
1600 struct lsa_header *lsah = lsa->data;
1601 uint32_t instance = ntohl(lsah->id.s_addr);
1602
1603 osr_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %pI4",
1604 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1605 &lsah->adv_router);
1606
1607 /* Sanity check */
1608 if (OspfSR.neighbors == NULL) {
1609 flog_err(EC_OSPF_SR_INVALID_DB,
1610 "SR (%s): Abort! no valid SR DataBase", __func__);
1611 return;
1612 }
1613
1614 /* Search SR Node in hash table from Router ID */
1615 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1616 (void *)&(lsah->adv_router));
1617
1618 /*
1619 * SR-Node may be NULL if it has been remove previously when
1620 * processing Router Information LSA deletion
1621 */
1622 if (srn == NULL) {
1623 flog_err(EC_OSPF_SR_INVALID_DB,
1624 "SR (%s): Stop! no entry in SRDB for SR Node %pI4",
1625 __func__, &lsah->adv_router);
1626 return;
1627 }
1628
1629 /* Search for corresponding Segment Link */
1630 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
1631 if (srl->instance == instance)
1632 break;
1633
1634 /* Remove Segment Link if found. Note that for Neighbors, only Global
1635 * Adj/Lan-Adj SID are stored in the SR-DB */
1636 if ((srl != NULL) && (srl->instance == instance)) {
1637 del_adj_sid(srl->nhlfe[0]);
1638 del_adj_sid(srl->nhlfe[1]);
1639 listnode_delete(srn->ext_link, srl);
1640 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1641 }
1642 }
1643
1644 /* Add (LAN)Adjacency-SID from Extended Link Information */
1645 void ospf_sr_ext_itf_add(struct ext_itf *exti)
1646 {
1647 struct sr_node *srn = OspfSR.self;
1648 struct sr_link *srl;
1649
1650 osr_debug("SR (%s): Add Extended Link LSA 8.0.0.%u from self", __func__,
1651 exti->instance);
1652
1653 /* Sanity check */
1654 if (srn == NULL)
1655 return;
1656
1657 /* Initialize new Segment Routing Link */
1658 srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
1659 srl->srn = srn;
1660 srl->adv_router = srn->adv_router;
1661 srl->itf_addr = exti->link.link_data;
1662 srl->instance =
1663 SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
1664 srl->remote_id = exti->link.link_id;
1665 switch (exti->stype) {
1666 case ADJ_SID:
1667 srl->type = ADJ_SID;
1668 /* Primary information */
1669 srl->flags[0] = exti->adj_sid[0].flags;
1670 if (CHECK_FLAG(exti->adj_sid[0].flags,
1671 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1672 srl->sid[0] = GET_LABEL(ntohl(exti->adj_sid[0].value));
1673 else
1674 srl->sid[0] = ntohl(exti->adj_sid[0].value);
1675 if (exti->rmt_itf_addr.header.type == 0)
1676 srl->nhlfe[0].nexthop = exti->link.link_id;
1677 else
1678 srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
1679 /* Backup Information if set */
1680 if (exti->adj_sid[1].header.type == 0)
1681 break;
1682 srl->flags[1] = exti->adj_sid[1].flags;
1683 if (CHECK_FLAG(exti->adj_sid[1].flags,
1684 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1685 srl->sid[1] = GET_LABEL(ntohl(exti->adj_sid[1].value));
1686 else
1687 srl->sid[1] = ntohl(exti->adj_sid[1].value);
1688 if (exti->rmt_itf_addr.header.type == 0)
1689 srl->nhlfe[1].nexthop = exti->link.link_id;
1690 else
1691 srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
1692 break;
1693 case LAN_ADJ_SID:
1694 srl->type = LAN_ADJ_SID;
1695 /* Primary information */
1696 srl->flags[0] = exti->lan_sid[0].flags;
1697 if (CHECK_FLAG(exti->lan_sid[0].flags,
1698 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1699 srl->sid[0] = GET_LABEL(ntohl(exti->lan_sid[0].value));
1700 else
1701 srl->sid[0] = ntohl(exti->lan_sid[0].value);
1702 if (exti->rmt_itf_addr.header.type == 0)
1703 srl->nhlfe[0].nexthop = exti->lan_sid[0].neighbor_id;
1704 else
1705 srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
1706 /* Backup Information if set */
1707 if (exti->lan_sid[1].header.type == 0)
1708 break;
1709 srl->flags[1] = exti->lan_sid[1].flags;
1710 if (CHECK_FLAG(exti->lan_sid[1].flags,
1711 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1712 srl->sid[1] = GET_LABEL(ntohl(exti->lan_sid[1].value));
1713 else
1714 srl->sid[1] = ntohl(exti->lan_sid[1].value);
1715 if (exti->rmt_itf_addr.header.type == 0)
1716 srl->nhlfe[1].nexthop = exti->lan_sid[1].neighbor_id;
1717 else
1718 srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
1719 break;
1720 case PREF_SID:
1721 case LOCAL_SID:
1722 /* Wrong SID Type. Abort! */
1723 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1724 return;
1725 }
1726
1727 /* Segment Routing Link is ready, update it */
1728 update_ext_link_sid(srn, srl, OSPF_LSA_SELF);
1729 }
1730
1731 /* Delete Prefix or (LAN)Adjacency-SID from Extended Link Information */
1732 void ospf_sr_ext_itf_delete(struct ext_itf *exti)
1733 {
1734 struct listnode *node;
1735 struct sr_node *srn = OspfSR.self;
1736 struct sr_prefix *srp = NULL;
1737 struct sr_link *srl = NULL;
1738 uint32_t instance;
1739
1740 osr_debug("SR (%s): Remove Extended LSA %u.0.0.%u from self",
1741 __func__, exti->stype == PREF_SID ? 7 : 8, exti->instance);
1742
1743 /* Sanity check: SR-Node and Extended Prefix/Link list may have been
1744 * removed earlier when stopping OSPF or OSPF-SR */
1745 if (srn == NULL || srn->ext_prefix == NULL || srn->ext_link == NULL)
1746 return;
1747
1748 if (exti->stype == PREF_SID) {
1749 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
1750 exti->instance);
1751 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
1752 if (srp->instance == instance)
1753 break;
1754
1755 /* Uninstall Segment Prefix SID if found */
1756 if ((srp != NULL) && (srp->instance == instance))
1757 ospf_zebra_delete_prefix_sid(srp);
1758 } else {
1759 /* Search for corresponding Segment Link for self SR-Node */
1760 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA,
1761 exti->instance);
1762 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
1763 if (srl->instance == instance)
1764 break;
1765
1766 /* Remove Segment Link if found */
1767 if ((srl != NULL) && (srl->instance == instance)) {
1768 del_adj_sid(srl->nhlfe[0]);
1769 del_adj_sid(srl->nhlfe[1]);
1770 listnode_delete(srn->ext_link, srl);
1771 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1772 }
1773 }
1774 }
1775
1776 /* Update Segment Routing from Extended Prefix LSA */
1777 void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
1778 {
1779 struct sr_node *srn;
1780 struct tlv_header *tlvh;
1781 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1782 struct sr_prefix *srp;
1783
1784 int length;
1785
1786 osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4",
1787 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1788 &lsah->adv_router);
1789
1790 /* Sanity check */
1791 if (OspfSR.neighbors == NULL) {
1792 flog_err(EC_OSPF_SR_INVALID_DB,
1793 "SR (%s): Abort! no valid SR DataBase", __func__);
1794 return;
1795 }
1796
1797 /* Get SR Node in hash table from Router ID */
1798 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1799 (void *)&(lsah->adv_router),
1800 (void *)sr_node_new);
1801 /* Initialize TLV browsing */
1802 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1803 for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
1804 tlvh = TLV_HDR_NEXT(tlvh)) {
1805 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1806 /* Got Extended Link information */
1807 srp = get_ext_prefix_sid(tlvh, length);
1808 /* Update SID if not null */
1809 if (srp != NULL) {
1810 srp->instance = ntohl(lsah->id.s_addr);
1811 update_ext_prefix_sid(srn, srp);
1812 }
1813 }
1814 length -= TLV_SIZE(tlvh);
1815 }
1816 }
1817
1818 /* Delete Segment Routing from Extended Prefix LSA */
1819 void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
1820 {
1821 struct listnode *node;
1822 struct sr_prefix *srp;
1823 struct sr_node *srn;
1824 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1825 uint32_t instance = ntohl(lsah->id.s_addr);
1826
1827 osr_debug("SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %pI4",
1828 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1829 &lsah->adv_router);
1830
1831 /* Sanity check */
1832 if (OspfSR.neighbors == NULL) {
1833 flog_err(EC_OSPF_SR_INVALID_DB,
1834 "SR (%s): Abort! no valid SR DataBase", __func__);
1835 return;
1836 }
1837
1838 /* Search SR Node in hash table from Router ID */
1839 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1840 (void *)&(lsah->adv_router));
1841
1842 /*
1843 * SR-Node may be NULL if it has been remove previously when
1844 * processing Router Information LSA deletion
1845 */
1846 if (srn == NULL) {
1847 flog_err(EC_OSPF_SR_INVALID_DB,
1848 "SR (%s): Stop! no entry in SRDB for SR Node %pI4",
1849 __func__, &lsah->adv_router);
1850 return;
1851 }
1852
1853 /* Search for corresponding Segment Prefix */
1854 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
1855 if (srp->instance == instance)
1856 break;
1857
1858 /* Remove Prefix if found */
1859 if ((srp != NULL) && (srp->instance == instance)) {
1860 ospf_zebra_delete_prefix_sid(srp);
1861 listnode_delete(srn->ext_prefix, srp);
1862 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1863 } else {
1864 flog_err(
1865 EC_OSPF_SR_INVALID_DB,
1866 "SR (%s): Didn't found corresponding SR Prefix 7.0.0.%u for SR Node %pI4",
1867 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1868 &lsah->adv_router);
1869 }
1870 }
1871
1872 /*
1873 * Update Prefix SID. Call by ospf_ext_pref_ism_change to
1874 * complete initial CLI command at startup.
1875 *
1876 * @param ifp - Loopback interface
1877 * @param pref - Prefix address of this interface
1878 *
1879 * @return - void
1880 */
1881 void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p)
1882 {
1883 struct listnode *node;
1884 struct sr_prefix *srp;
1885
1886 /* Sanity Check */
1887 if ((ifp == NULL) || (p == NULL))
1888 return;
1889
1890 /*
1891 * Search if there is a Segment Prefix that correspond to this
1892 * interface or prefix, and update it if found
1893 */
1894 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
1895 if ((srp->nhlfe.ifindex == ifp->ifindex)
1896 || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p->u.prefix4))
1897 && (srp->prefv4.prefixlen == p->prefixlen))) {
1898
1899 /* Update Interface & Prefix info */
1900 srp->nhlfe.ifindex = ifp->ifindex;
1901 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p->u.prefix4);
1902 srp->prefv4.prefixlen = p->prefixlen;
1903 srp->prefv4.family = p->family;
1904 IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4);
1905
1906 /* OK. Let's Schedule Extended Prefix LSA */
1907 srp->instance = ospf_ext_schedule_prefix_index(
1908 ifp, srp->sid, &srp->prefv4, srp->flags);
1909
1910 osr_debug(
1911 " |- Update Node SID %pFX - %u for self SR Node",
1912 (struct prefix *)&srp->prefv4, srp->sid);
1913
1914 /* Install SID if NO-PHP is set and not EXPLICIT-NULL */
1915 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
1916 && !CHECK_FLAG(srp->flags,
1917 EXT_SUBTLV_PREFIX_SID_EFLG)) {
1918 srp->label_in = index2label(srp->sid,
1919 OspfSR.self->srgb);
1920 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
1921 ospf_zebra_update_prefix_sid(srp);
1922 }
1923 }
1924 }
1925 }
1926
1927 /*
1928 * Following functions are used to update MPLS LFIB after a SPF run
1929 */
1930
1931 static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args)
1932 {
1933
1934 struct sr_node *srn = (struct sr_node *)bucket->data;
1935 struct listnode *node;
1936 struct sr_prefix *srp;
1937 bool old;
1938 int rc;
1939
1940 osr_debug(" |- Update Prefix for SR Node %pI4", &srn->adv_router);
1941
1942 /* Skip Self SR Node */
1943 if (srn == OspfSR.self)
1944 return;
1945
1946 /* Update Extended Prefix */
1947 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1948
1949 /* Keep track of valid route */
1950 old = srp->route != NULL;
1951
1952 /* Compute the new NHLFE */
1953 rc = compute_prefix_nhlfe(srp);
1954
1955 /* Check computation result */
1956 switch (rc) {
1957 /* Routes are not know, remove old NHLFE if any to avoid loop */
1958 case -1:
1959 if (old)
1960 ospf_zebra_delete_prefix_sid(srp);
1961 break;
1962 /* Routes exist but are not ready, skip it */
1963 case 0:
1964 break;
1965 /* There is at least one route, update NHLFE */
1966 case 1:
1967 ospf_zebra_update_prefix_sid(srp);
1968 break;
1969 default:
1970 break;
1971 }
1972 }
1973 }
1974
1975 void ospf_sr_update_task(struct ospf *ospf)
1976 {
1977
1978 struct timeval start_time, stop_time;
1979
1980 /* Check ospf and SR status */
1981 if ((ospf == NULL) || (OspfSR.status != SR_UP))
1982 return;
1983
1984 monotime(&start_time);
1985
1986 osr_debug("SR (%s): Start SPF update", __func__);
1987
1988 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
1989 void *))ospf_sr_nhlfe_update,
1990 NULL);
1991
1992 monotime(&stop_time);
1993
1994 osr_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__,
1995 (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
1996 + (stop_time.tv_usec - start_time.tv_usec));
1997 }
1998
1999 /*
2000 * --------------------------------------
2001 * Following are vty command functions.
2002 * --------------------------------------
2003 */
2004
2005 /*
2006 * Segment Routing Router configuration
2007 *
2008 * Must be centralize as it concerns both Extended Link/Prefix LSA
2009 * and Router Information LSA. Choose to call it from Extended Prefix
2010 * write_config() call back.
2011 *
2012 * @param vty VTY output
2013 *
2014 * @return none
2015 */
2016 void ospf_sr_config_write_router(struct vty *vty)
2017 {
2018 struct listnode *node;
2019 struct sr_prefix *srp;
2020 uint32_t upper;
2021
2022 if (OspfSR.status == SR_UP)
2023 vty_out(vty, " segment-routing on\n");
2024
2025 upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
2026 if ((OspfSR.srgb.start != DEFAULT_SRGB_LABEL)
2027 || (OspfSR.srgb.size != DEFAULT_SRGB_SIZE))
2028 vty_out(vty, " segment-routing global-block %u %u",
2029 OspfSR.srgb.start, upper);
2030
2031 if ((OspfSR.srlb.start != DEFAULT_SRLB_LABEL) ||
2032 (OspfSR.srlb.end != DEFAULT_SRLB_END)) {
2033 if ((OspfSR.srgb.start == DEFAULT_SRGB_LABEL) &&
2034 (OspfSR.srgb.size == DEFAULT_SRGB_SIZE))
2035 vty_out(vty, " segment-routing global-block %u %u",
2036 OspfSR.srgb.start, upper);
2037 vty_out(vty, " local-block %u %u\n", OspfSR.srlb.start,
2038 OspfSR.srlb.end);
2039 } else
2040 vty_out(vty, "\n");
2041
2042 if (OspfSR.msd != 0)
2043 vty_out(vty, " segment-routing node-msd %u\n", OspfSR.msd);
2044
2045 if (OspfSR.self != NULL) {
2046 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2047 vty_out(vty, " segment-routing prefix %pFX index %u",
2048 &srp->prefv4, srp->sid);
2049 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2050 vty_out(vty, " explicit-null\n");
2051 else if (CHECK_FLAG(srp->flags,
2052 EXT_SUBTLV_PREFIX_SID_NPFLG))
2053 vty_out(vty, " no-php-flag\n");
2054 else
2055 vty_out(vty, "\n");
2056 }
2057 }
2058 }
2059
2060 DEFUN(ospf_sr_enable,
2061 ospf_sr_enable_cmd,
2062 "segment-routing on",
2063 SR_STR
2064 "Enable Segment Routing\n")
2065 {
2066
2067 VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
2068
2069 if (OspfSR.status != SR_OFF)
2070 return CMD_SUCCESS;
2071
2072 if (ospf->vrf_id != VRF_DEFAULT) {
2073 vty_out(vty,
2074 "Segment Routing is only supported in default VRF\n");
2075 return CMD_WARNING_CONFIG_FAILED;
2076 }
2077
2078 osr_debug("SR: Segment Routing: OFF -> ON");
2079
2080 /* Start Segment Routing */
2081 OspfSR.status = SR_ON;
2082 ospf_sr_start(ospf);
2083
2084 return CMD_SUCCESS;
2085 }
2086
2087 DEFUN (no_ospf_sr_enable,
2088 no_ospf_sr_enable_cmd,
2089 "no segment-routing [on]",
2090 NO_STR
2091 SR_STR
2092 "Disable Segment Routing\n")
2093 {
2094
2095 if (OspfSR.status == SR_OFF)
2096 return CMD_SUCCESS;
2097
2098 osr_debug("SR: Segment Routing: ON -> OFF");
2099
2100 /* Start by Disabling Extended Link & Prefix LSA */
2101 ospf_ext_update_sr(false);
2102
2103 /* then, disable Router Information SR parameters */
2104 ospf_router_info_update_sr(false, OspfSR.self);
2105
2106 /* Finally, stop Segment Routing */
2107 ospf_sr_stop();
2108
2109 return CMD_SUCCESS;
2110 }
2111
2112 static int ospf_sr_enabled(struct vty *vty)
2113 {
2114 if (OspfSR.status != SR_OFF)
2115 return 1;
2116
2117 if (vty)
2118 vty_out(vty, "%% OSPF SR is not turned on\n");
2119
2120 return 0;
2121 }
2122
2123 /* tell if two ranges [r1_lower, r1_upper] and [r2_lower,r2_upper] overlap */
2124 static bool ranges_overlap(uint32_t r1_lower, uint32_t r1_upper,
2125 uint32_t r2_lower, uint32_t r2_upper)
2126 {
2127 return !((r1_upper < r2_lower) || (r1_lower > r2_upper));
2128 }
2129
2130
2131 /* tell if a range is valid */
2132 static bool sr_range_is_valid(uint32_t lower, uint32_t upper, uint32_t min_size)
2133 {
2134 return (upper >= lower + min_size);
2135 }
2136
2137 /**
2138 * Update SRGB and/or SRLB using new CLI values.
2139 *
2140 * @param gb_lower Lower bound of the SRGB
2141 * @param gb_upper Upper bound of the SRGB
2142 * @param lb_lower Lower bound of the SRLB
2143 * @param lb_upper Upper bound of the SRLB
2144 *
2145 * @return 0 on success, -1 otherwise
2146 */
2147 static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper,
2148 uint32_t lb_lower, uint32_t lb_upper)
2149 {
2150
2151 /* Check if values have changed */
2152 bool gb_changed, lb_changed;
2153 uint32_t gb_size = gb_upper - gb_lower + 1;
2154 uint32_t lb_size = lb_upper - lb_lower + 1;
2155
2156 gb_changed =
2157 (OspfSR.srgb.size != gb_size || OspfSR.srgb.start != gb_lower);
2158 lb_changed =
2159 (OspfSR.srlb.end != lb_upper || OspfSR.srlb.start != lb_lower);
2160 if (!gb_changed && !lb_changed)
2161 return 0;
2162
2163 /* Check if SR is correctly started i.e. Label Manager connected */
2164 if (OspfSR.status != SR_UP) {
2165 OspfSR.srgb.size = gb_size;
2166 OspfSR.srgb.start = gb_lower;
2167 OspfSR.srlb.end = lb_upper;
2168 OspfSR.srlb.start = lb_lower;
2169 return 0;
2170 }
2171
2172 /* Release old SRGB if it has changed and is active. */
2173 if (gb_changed) {
2174
2175 sr_global_block_delete();
2176
2177 /* Set new SRGB values - but do not reserve yet (we need to
2178 * release the SRLB too) */
2179 OspfSR.srgb.size = gb_size;
2180 OspfSR.srgb.start = gb_lower;
2181 if (OspfSR.self != NULL) {
2182 OspfSR.self->srgb.range_size = gb_size;
2183 OspfSR.self->srgb.lower_bound = gb_lower;
2184 }
2185 }
2186 /* Release old SRLB if it has changed and reserve new block as needed.
2187 */
2188 if (lb_changed) {
2189
2190 sr_local_block_delete();
2191
2192 /* Set new SRLB values */
2193 if (sr_local_block_init(lb_lower, lb_upper) < 0) {
2194 ospf_sr_stop();
2195 return -1;
2196 }
2197 if (OspfSR.self != NULL) {
2198 OspfSR.self->srlb.lower_bound = lb_lower;
2199 OspfSR.self->srlb.range_size = lb_size;
2200 }
2201 }
2202
2203 /*
2204 * Try to reserve the new SRGB from the Label Manger. If the
2205 * allocation fails, disable SR until new blocks are successfully
2206 * allocated.
2207 */
2208 if (gb_changed) {
2209 if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size)
2210 < 0) {
2211 ospf_sr_stop();
2212 return -1;
2213 }
2214 }
2215
2216 /* Update Self SR-Node */
2217 if (OspfSR.self != NULL) {
2218 /* SRGB is reserved, set Router Information parameters */
2219 ospf_router_info_update_sr(true, OspfSR.self);
2220
2221 /* and update NHLFE entries */
2222 if (gb_changed)
2223 hash_iterate(OspfSR.neighbors,
2224 (void (*)(struct hash_bucket *,
2225 void *))update_in_nhlfe,
2226 NULL);
2227
2228 /* and update (LAN)-Adjacency SID */
2229 if (lb_changed)
2230 ospf_ext_link_srlb_update();
2231 }
2232
2233 return 0;
2234 }
2235
2236 DEFUN(sr_global_label_range, sr_global_label_range_cmd,
2237 "segment-routing global-block (16-1048575) (16-1048575) [local-block (16-1048575) (16-1048575)]",
2238 SR_STR
2239 "Segment Routing Global Block label range\n"
2240 "Lower-bound range in decimal (16-1048575)\n"
2241 "Upper-bound range in decimal (16-1048575)\n"
2242 "Segment Routing Local Block label range\n"
2243 "Lower-bound range in decimal (16-1048575)\n"
2244 "Upper-bound range in decimal (16-1048575)\n")
2245 {
2246 uint32_t lb_upper, lb_lower;
2247 uint32_t gb_upper, gb_lower;
2248 int idx_gb_low = 2, idx_gb_up = 3;
2249 int idx_lb_low = 5, idx_lb_up = 6;
2250
2251 /* Get lower and upper bound for mandatory global-block */
2252 gb_lower = strtoul(argv[idx_gb_low]->arg, NULL, 10);
2253 gb_upper = strtoul(argv[idx_gb_up]->arg, NULL, 10);
2254
2255 /* SRLB values are taken from vtysh if there, else use the known ones */
2256 lb_upper = argc > idx_lb_up ? strtoul(argv[idx_lb_up]->arg, NULL, 10)
2257 : OspfSR.srlb.end;
2258 lb_lower = argc > idx_lb_low ? strtoul(argv[idx_lb_low]->arg, NULL, 10)
2259 : OspfSR.srlb.start;
2260
2261 /* check correctness of input SRGB */
2262 if (!sr_range_is_valid(gb_lower, gb_upper, MIN_SRGB_SIZE)) {
2263 vty_out(vty, "Invalid SRGB range\n");
2264 return CMD_WARNING_CONFIG_FAILED;
2265 }
2266
2267 /* check correctness of SRLB */
2268 if (!sr_range_is_valid(lb_lower, lb_upper, MIN_SRLB_SIZE)) {
2269 vty_out(vty, "Invalid SRLB range\n");
2270 return CMD_WARNING_CONFIG_FAILED;
2271 }
2272
2273 /* Validate SRGB against SRLB */
2274 if (ranges_overlap(gb_lower, gb_upper, lb_lower, lb_upper)) {
2275 vty_out(vty,
2276 "New SR Global Block (%u/%u) conflicts with Local Block (%u/%u)\n",
2277 gb_lower, gb_upper, lb_lower, lb_upper);
2278 return CMD_WARNING_CONFIG_FAILED;
2279 }
2280
2281 if (update_sr_blocks(gb_lower, gb_upper, lb_lower, lb_upper) < 0)
2282 return CMD_WARNING_CONFIG_FAILED;
2283 else
2284 return CMD_SUCCESS;
2285 }
2286
2287 DEFUN(no_sr_global_label_range, no_sr_global_label_range_cmd,
2288 "no segment-routing global-block [(16-1048575) (16-1048575) local-block (16-1048575) (16-1048575)]",
2289 NO_STR SR_STR
2290 "Segment Routing Global Block label range\n"
2291 "Lower-bound range in decimal (16-1048575)\n"
2292 "Upper-bound range in decimal (16-1048575)\n"
2293 "Segment Routing Local Block label range\n"
2294 "Lower-bound range in decimal (16-1048575)\n"
2295 "Upper-bound range in decimal (16-1048575)\n")
2296 {
2297 if (update_sr_blocks(DEFAULT_SRGB_LABEL, DEFAULT_SRGB_END,
2298 DEFAULT_SRLB_LABEL, DEFAULT_SRLB_END)
2299 < 0)
2300 return CMD_WARNING_CONFIG_FAILED;
2301 else
2302 return CMD_SUCCESS;
2303 }
2304
2305 #if CONFDATE > 20220528
2306 CPP_NOTICE(
2307 "Use of the segment-routing local-block command is deprecated, use the combined global-block command instead")
2308 #endif
2309
2310 DEFUN_HIDDEN(sr_local_label_range, sr_local_label_range_cmd,
2311 "segment-routing local-block (16-1048575) (16-1048575)",
2312 SR_STR
2313 "Segment Routing Local Block label range\n"
2314 "Lower-bound range in decimal (16-1048575)\n"
2315 "Upper-bound range in decimal (16-1048575)\n")
2316 {
2317 uint32_t upper;
2318 uint32_t lower;
2319 uint32_t srgb_upper;
2320 int idx_low = 2;
2321 int idx_up = 3;
2322
2323 /* Get lower and upper bound */
2324 lower = strtoul(argv[idx_low]->arg, NULL, 10);
2325 upper = strtoul(argv[idx_up]->arg, NULL, 10);
2326
2327 /* check correctness of SRLB */
2328 if (!sr_range_is_valid(lower, upper, MIN_SRLB_SIZE)) {
2329 vty_out(vty, "Invalid SRLB range\n");
2330 return CMD_WARNING_CONFIG_FAILED;
2331 }
2332
2333 /* Check if values have changed */
2334 if ((OspfSR.srlb.start == lower)
2335 && (OspfSR.srlb.end == upper))
2336 return CMD_SUCCESS;
2337
2338 /* Validate SRLB against SRGB */
2339 srgb_upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
2340
2341 if (ranges_overlap(OspfSR.srgb.start, srgb_upper, lower, upper)) {
2342 vty_out(vty,
2343 "New SR Local Block (%u/%u) conflicts with Global Block (%u/%u)\n",
2344 lower, upper, OspfSR.srgb.start, srgb_upper);
2345 return CMD_WARNING_CONFIG_FAILED;
2346 }
2347
2348 if (update_sr_blocks(OspfSR.srgb.start, srgb_upper, lower, upper) < 0)
2349 return CMD_WARNING_CONFIG_FAILED;
2350 else
2351 return CMD_SUCCESS;
2352 }
2353
2354 DEFUN_HIDDEN(no_sr_local_label_range, no_sr_local_label_range_cmd,
2355 "no segment-routing local-block [(16-1048575) (16-1048575)]",
2356 NO_STR SR_STR
2357 "Segment Routing Local Block label range\n"
2358 "Lower-bound range in decimal (16-1048575)\n"
2359 "Upper-bound range in decimal (16-1048575)\n")
2360 {
2361
2362 uint32_t srgb_end;
2363
2364 /* Validate SRLB against SRGB */
2365 srgb_end = OspfSR.srgb.start + OspfSR.srgb.size - 1;
2366 if (ranges_overlap(OspfSR.srgb.start, srgb_end, DEFAULT_SRLB_LABEL,
2367 DEFAULT_SRLB_END)) {
2368 vty_out(vty,
2369 "New SR Local Block (%u/%u) conflicts with Global Block (%u/%u)\n",
2370 DEFAULT_SRLB_LABEL, DEFAULT_SRLB_END, OspfSR.srgb.start,
2371 srgb_end);
2372 return CMD_WARNING_CONFIG_FAILED;
2373 }
2374
2375 if (update_sr_blocks(OspfSR.srgb.start, srgb_end, DEFAULT_SRLB_LABEL,
2376 DEFAULT_SRLB_END)
2377 < 0)
2378 return CMD_WARNING_CONFIG_FAILED;
2379 else
2380 return CMD_SUCCESS;
2381 }
2382
2383 DEFUN (sr_node_msd,
2384 sr_node_msd_cmd,
2385 "segment-routing node-msd (1-16)",
2386 SR_STR
2387 "Maximum Stack Depth for this router\n"
2388 "Maximum number of label that could be stack (1-16)\n")
2389 {
2390 uint32_t msd;
2391 int idx = 1;
2392
2393 if (!ospf_sr_enabled(vty))
2394 return CMD_WARNING_CONFIG_FAILED;
2395
2396 /* Get MSD */
2397 argv_find(argv, argc, "(1-16)", &idx);
2398 msd = strtoul(argv[idx]->arg, NULL, 10);
2399 if (msd < 1 || msd > MPLS_MAX_LABELS) {
2400 vty_out(vty, "MSD must be comprise between 1 and %u\n",
2401 MPLS_MAX_LABELS);
2402 return CMD_WARNING_CONFIG_FAILED;
2403 }
2404
2405 /* Check if value has changed */
2406 if (OspfSR.msd == msd)
2407 return CMD_SUCCESS;
2408
2409 /* Set this router MSD */
2410 OspfSR.msd = msd;
2411 if (OspfSR.self != NULL) {
2412 OspfSR.self->msd = msd;
2413
2414 /* Set Router Information parameters if SR is UP */
2415 if (OspfSR.status == SR_UP)
2416 ospf_router_info_update_sr(true, OspfSR.self);
2417 }
2418
2419 return CMD_SUCCESS;
2420 }
2421
2422 DEFUN (no_sr_node_msd,
2423 no_sr_node_msd_cmd,
2424 "no segment-routing node-msd [(1-16)]",
2425 NO_STR
2426 SR_STR
2427 "Maximum Stack Depth for this router\n"
2428 "Maximum number of label that could be stack (1-16)\n")
2429 {
2430
2431 if (!ospf_sr_enabled(vty))
2432 return CMD_WARNING_CONFIG_FAILED;
2433
2434 /* unset this router MSD */
2435 OspfSR.msd = 0;
2436 if (OspfSR.self != NULL) {
2437 OspfSR.self->msd = 0;
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 (sr_prefix_sid,
2448 sr_prefix_sid_cmd,
2449 "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
2450 SR_STR
2451 "Prefix SID\n"
2452 "IPv4 Prefix as A.B.C.D/M\n"
2453 "SID index for this prefix in decimal (0-65535)\n"
2454 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2455 "Don't request Penultimate Hop Popping (PHP)\n"
2456 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2457 {
2458 int idx = 0;
2459 struct prefix p, pexist;
2460 uint32_t index;
2461 struct listnode *node;
2462 struct sr_prefix *srp, *exist = NULL;
2463 struct interface *ifp;
2464 bool no_php_flag = false;
2465 bool exp_null = false;
2466 bool index_in_use = false;
2467 uint8_t desired_flags = 0;
2468
2469 if (!ospf_sr_enabled(vty))
2470 return CMD_WARNING_CONFIG_FAILED;
2471
2472 /* Get network prefix */
2473 argv_find(argv, argc, "A.B.C.D/M", &idx);
2474 if (!str2prefix(argv[idx]->arg, &p)) {
2475 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2476 return CMD_WARNING_CONFIG_FAILED;
2477 }
2478
2479 /* Get & verify index value */
2480 argv_find(argv, argc, "(0-65535)", &idx);
2481 index = strtoul(argv[idx]->arg, NULL, 10);
2482 if (index > OspfSR.srgb.size - 1) {
2483 vty_out(vty, "Index %u must be lower than range size %u\n",
2484 index, OspfSR.srgb.size);
2485 return CMD_WARNING_CONFIG_FAILED;
2486 }
2487
2488 /* Get options */
2489 no_php_flag = argv_find(argv, argc, "no-php-flag", &idx);
2490 exp_null = argv_find(argv, argc, "explicit-null", &idx);
2491
2492 desired_flags |= no_php_flag ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2493 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2494 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_EFLG : 0;
2495
2496 /* Search for an existing Prefix-SID */
2497 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2498 if (prefix_same((struct prefix *)&srp->prefv4, &p))
2499 exist = srp;
2500 if (srp->sid == index) {
2501 index_in_use = true;
2502 pexist = p;
2503 }
2504 }
2505
2506 /* done if prefix segment already there with same index and flags */
2507 if (exist && exist->sid == index && exist->flags == desired_flags)
2508 return CMD_SUCCESS;
2509
2510 /* deny if index is already in use by a distinct prefix */
2511 if (!exist && index_in_use) {
2512 vty_out(vty, "Index %u is already used by %pFX\n", index,
2513 &pexist);
2514 return CMD_WARNING_CONFIG_FAILED;
2515 }
2516
2517 /* First, remove old NHLFE if installed */
2518 if (exist && CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2519 && !CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2520 ospf_zebra_delete_prefix_sid(exist);
2521
2522 /* Create new Extended Prefix to SRDB if not found */
2523 if (exist == NULL) {
2524 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
2525 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p.u.prefix4);
2526 srp->prefv4.prefixlen = p.prefixlen;
2527 srp->prefv4.family = p.family;
2528 srp->sid = index;
2529 srp->type = LOCAL_SID;
2530 } else {
2531 /* we work on the existing SR prefix */
2532 srp = exist;
2533 }
2534
2535 /* Reset labels to handle flag update */
2536 srp->label_in = 0;
2537 srp->nhlfe.label_out = 0;
2538 srp->sid = index;
2539 srp->flags = desired_flags;
2540
2541 /* If NO PHP flag is present, compute NHLFE and set label */
2542 if (no_php_flag) {
2543 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
2544 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
2545 }
2546
2547 osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
2548 (struct prefix *)&srp->prefv4);
2549
2550 /* Get Interface and check if it is a Loopback */
2551 ifp = if_lookup_prefix(&p, VRF_DEFAULT);
2552 if (ifp == NULL) {
2553 /*
2554 * Interface could be not yet available i.e. when this
2555 * command is in the configuration file, OSPF is not yet
2556 * ready. In this case, store the prefix SID for latter
2557 * update of this Extended Prefix
2558 */
2559 if (exist == NULL)
2560 listnode_add(OspfSR.self->ext_prefix, srp);
2561 zlog_info(
2562 "Interface for prefix %pFX not found. Deferred LSA flooding",
2563 &p);
2564 return CMD_SUCCESS;
2565 }
2566
2567 if (!if_is_loopback(ifp)) {
2568 vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
2569 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2570 return CMD_WARNING_CONFIG_FAILED;
2571 }
2572 srp->nhlfe.ifindex = ifp->ifindex;
2573
2574 /* Add SR Prefix if new */
2575 if (!exist)
2576 listnode_add(OspfSR.self->ext_prefix, srp);
2577
2578 /* Update Prefix SID if SR is UP */
2579 if (OspfSR.status == SR_UP) {
2580 if (no_php_flag && !exp_null)
2581 ospf_zebra_update_prefix_sid(srp);
2582 } else
2583 return CMD_SUCCESS;
2584
2585 /* Finally, update Extended Prefix LSA id SR is UP */
2586 srp->instance = ospf_ext_schedule_prefix_index(
2587 ifp, srp->sid, &srp->prefv4, srp->flags);
2588 if (srp->instance == 0) {
2589 vty_out(vty, "Unable to set index %u for prefix %pFX\n",
2590 index, &p);
2591 return CMD_WARNING;
2592 }
2593
2594 return CMD_SUCCESS;
2595 }
2596
2597 DEFUN (no_sr_prefix_sid,
2598 no_sr_prefix_sid_cmd,
2599 "no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
2600 NO_STR
2601 SR_STR
2602 "Prefix SID\n"
2603 "IPv4 Prefix as A.B.C.D/M\n"
2604 "SID index for this prefix in decimal (0-65535)\n"
2605 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2606 "Don't request Penultimate Hop Popping (PHP)\n"
2607 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2608 {
2609 int idx = 0;
2610 struct prefix p;
2611 struct listnode *node;
2612 struct sr_prefix *srp;
2613 struct interface *ifp;
2614 bool found = false;
2615 int rc;
2616
2617 if (!ospf_sr_enabled(vty))
2618 return CMD_WARNING_CONFIG_FAILED;
2619
2620 if (OspfSR.status != SR_UP)
2621 return CMD_SUCCESS;
2622
2623 /* Get network prefix */
2624 argv_find(argv, argc, "A.B.C.D/M", &idx);
2625 rc = str2prefix(argv[idx]->arg, &p);
2626 if (!rc) {
2627 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2628 return CMD_WARNING_CONFIG_FAILED;
2629 }
2630
2631 /* check that the prefix is already set */
2632 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
2633 if (IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
2634 && (srp->prefv4.prefixlen == p.prefixlen)) {
2635 found = true;
2636 break;
2637 }
2638
2639 if (!found) {
2640 vty_out(vty, "Prefix %s is not found. Abort!\n",
2641 argv[idx]->arg);
2642 return CMD_WARNING_CONFIG_FAILED;
2643 }
2644
2645 osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
2646 (struct prefix *)&srp->prefv4, srp->sid);
2647
2648 /* Get Interface */
2649 ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2650 if (ifp == NULL) {
2651 vty_out(vty, "interface for prefix %s not found.\n",
2652 argv[idx]->arg);
2653 /* silently remove from list */
2654 listnode_delete(OspfSR.self->ext_prefix, srp);
2655 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2656 return CMD_SUCCESS;
2657 }
2658
2659 /* Update Extended Prefix LSA */
2660 if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
2661 vty_out(vty, "No corresponding loopback interface. Abort!\n");
2662 return CMD_WARNING;
2663 }
2664
2665 /* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
2666 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2667 && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2668 ospf_zebra_delete_prefix_sid(srp);
2669
2670 /* OK, all is clean, remove SRP from SRDB */
2671 listnode_delete(OspfSR.self->ext_prefix, srp);
2672 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2673
2674 return CMD_SUCCESS;
2675 }
2676
2677
2678 static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
2679 mpls_label_t label_out)
2680 {
2681 if (size < 24)
2682 return NULL;
2683
2684 switch (label_out) {
2685 case MPLS_LABEL_IMPLICIT_NULL:
2686 snprintf(buf, size, "Pop(%u)", label_in);
2687 break;
2688 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2689 if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
2690 snprintf(buf, size, "no-op.");
2691 else
2692 snprintf(buf, size, "Swap(%u, null)", label_in);
2693 break;
2694 case MPLS_INVALID_LABEL:
2695 snprintf(buf, size, "no-op.");
2696 break;
2697 default:
2698 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
2699 break;
2700 }
2701 return buf;
2702 }
2703
2704 static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json,
2705 struct sr_prefix *srp)
2706 {
2707
2708 struct listnode *node;
2709 struct ospf_path *path;
2710 struct interface *itf;
2711 json_object *json_route = NULL, *json_obj;
2712 char pref[19];
2713 char sid[22];
2714 char op[32];
2715 char buf[PREFIX_STRLEN];
2716 int indent = 0;
2717
2718 snprintfrr(pref, 19, "%pFX", (struct prefix *)&srp->prefv4);
2719 snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
2720 if (json) {
2721 json_object_string_add(json, "prefix", pref);
2722 json_object_int_add(json, "sid", srp->sid);
2723 json_object_int_add(json, "inputLabel", srp->label_in);
2724 } else {
2725 sbuf_push(sbuf, 0, "%18s %21s ", pref, sid);
2726 }
2727
2728 /* Check if it is a Local Node SID */
2729 if (srp->type == LOCAL_SID) {
2730 itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2731 if (json) {
2732 if (!json_route) {
2733 json_route = json_object_new_array();
2734 json_object_object_add(json, "prefixRoute",
2735 json_route);
2736 }
2737 json_obj = json_object_new_object();
2738 json_object_int_add(json_obj, "outputLabel",
2739 srp->nhlfe.label_out);
2740 json_object_string_add(json_obj, "interface",
2741 itf ? itf->name : "-");
2742 json_object_string_addf(json_obj, "nexthop", "%pI4",
2743 &srp->nhlfe.nexthop);
2744 json_object_array_add(json_route, json_obj);
2745 } else {
2746 sbuf_push(sbuf, 0, "%20s %9s %15s\n",
2747 sr_op2str(op, 32, srp->label_in,
2748 srp->nhlfe.label_out),
2749 itf ? itf->name : "-",
2750 inet_ntop(AF_INET, &srp->nhlfe.nexthop,
2751 buf, sizeof(buf)));
2752 }
2753 return;
2754 }
2755
2756 /* Check if we have a valid path for this prefix */
2757 if (srp->route == NULL) {
2758 if (!json) {
2759 sbuf_push(sbuf, 0, "\n");
2760 }
2761 return;
2762 }
2763
2764 /* Process list of OSPF paths */
2765 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
2766 itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT);
2767 if (json) {
2768 if (!json_route) {
2769 json_route = json_object_new_array();
2770 json_object_object_add(json, "prefixRoute",
2771 json_route);
2772 }
2773 json_obj = json_object_new_object();
2774 json_object_int_add(json_obj, "outputLabel",
2775 path->srni.label_out);
2776 json_object_string_add(json_obj, "interface",
2777 itf ? itf->name : "-");
2778 json_object_string_addf(json_obj, "nexthop", "%pI4",
2779 &path->nexthop);
2780 json_object_array_add(json_route, json_obj);
2781 } else {
2782 sbuf_push(sbuf, indent, "%20s %9s %15s\n",
2783 sr_op2str(op, 32, srp->label_in,
2784 path->srni.label_out),
2785 itf ? itf->name : "-",
2786 inet_ntop(AF_INET, &path->nexthop, buf,
2787 sizeof(buf)));
2788 /* Offset to align information for ECMP */
2789 indent = 43;
2790 }
2791 }
2792 }
2793
2794 static void show_sr_node(struct vty *vty, struct json_object *json,
2795 struct sr_node *srn)
2796 {
2797
2798 struct listnode *node;
2799 struct sr_link *srl;
2800 struct sr_prefix *srp;
2801 struct interface *itf;
2802 struct sbuf sbuf;
2803 char pref[19];
2804 char sid[22];
2805 char op[32];
2806 char buf[PREFIX_STRLEN];
2807 uint32_t upper;
2808 json_object *json_node = NULL, *json_algo, *json_obj;
2809 json_object *json_prefix = NULL, *json_link = NULL;
2810
2811 /* Sanity Check */
2812 if (srn == NULL)
2813 return;
2814
2815 sbuf_init(&sbuf, NULL, 0);
2816
2817 if (json) {
2818 json_node = json_object_new_object();
2819 json_object_string_addf(json_node, "routerID", "%pI4",
2820 &srn->adv_router);
2821 json_object_int_add(json_node, "srgbSize",
2822 srn->srgb.range_size);
2823 json_object_int_add(json_node, "srgbLabel",
2824 srn->srgb.lower_bound);
2825 json_object_int_add(json_node, "srlbSize",
2826 srn->srlb.range_size);
2827 json_object_int_add(json_node, "srlbLabel",
2828 srn->srlb.lower_bound);
2829 json_algo = json_object_new_array();
2830 json_object_object_add(json_node, "algorithms", json_algo);
2831 for (int i = 0; i < ALGORITHM_COUNT; i++) {
2832 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2833 continue;
2834 json_obj = json_object_new_object();
2835 char tmp[2];
2836
2837 snprintf(tmp, sizeof(tmp), "%u", i);
2838 json_object_string_add(json_obj, tmp,
2839 srn->algo[i] == SR_ALGORITHM_SPF
2840 ? "SPF"
2841 : "S-SPF");
2842 json_object_array_add(json_algo, json_obj);
2843 }
2844 if (srn->msd != 0)
2845 json_object_int_add(json_node, "nodeMsd", srn->msd);
2846 } else {
2847 sbuf_push(&sbuf, 0, "SR-Node: %pI4", &srn->adv_router);
2848 upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
2849 sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
2850 srn->srgb.lower_bound, upper);
2851 upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
2852 sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
2853 srn->srlb.lower_bound, upper);
2854 sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
2855 srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
2856 for (int i = 1; i < ALGORITHM_COUNT; i++) {
2857 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2858 continue;
2859 sbuf_push(&sbuf, 0, "/%s",
2860 srn->algo[i] == SR_ALGORITHM_SPF ? "SPF"
2861 : "S-SPF");
2862 }
2863 if (srn->msd != 0)
2864 sbuf_push(&sbuf, 0, "\tMSD: %u", srn->msd);
2865 }
2866
2867 if (!json) {
2868 sbuf_push(&sbuf, 0,
2869 "\n\n Prefix or Link Node or Adj. SID Label Operation Interface Nexthop\n");
2870 sbuf_push(&sbuf, 0,
2871 "------------------ --------------------- -------------------- --------- ---------------\n");
2872 }
2873 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
2874 if (json) {
2875 if (!json_prefix) {
2876 json_prefix = json_object_new_array();
2877 json_object_object_add(json_node,
2878 "extendedPrefix",
2879 json_prefix);
2880 }
2881 json_obj = json_object_new_object();
2882 show_sr_prefix(NULL, json_obj, srp);
2883 json_object_array_add(json_prefix, json_obj);
2884 } else {
2885 show_sr_prefix(&sbuf, NULL, srp);
2886 }
2887 }
2888
2889 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
2890 snprintfrr(pref, 19, "%pI4/32", &srl->itf_addr);
2891 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
2892 itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
2893 if (json) {
2894 if (!json_link) {
2895 json_link = json_object_new_array();
2896 json_object_object_add(
2897 json_node, "extendedLink", json_link);
2898 }
2899 /* Primary Link */
2900 json_obj = json_object_new_object();
2901 json_object_string_add(json_obj, "prefix", pref);
2902 json_object_int_add(json_obj, "sid", srl->sid[0]);
2903 json_object_int_add(json_obj, "inputLabel",
2904 srl->nhlfe[0].label_in);
2905 json_object_int_add(json_obj, "outputLabel",
2906 srl->nhlfe[0].label_out);
2907 json_object_string_add(json_obj, "interface",
2908 itf ? itf->name : "-");
2909 json_object_string_addf(json_obj, "nexthop", "%pI4",
2910 &srl->nhlfe[0].nexthop);
2911 json_object_array_add(json_link, json_obj);
2912 /* Backup Link */
2913 json_obj = json_object_new_object();
2914 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2915 json_object_string_add(json_obj, "prefix", pref);
2916 json_object_int_add(json_obj, "sid", srl->sid[1]);
2917 json_object_int_add(json_obj, "inputLabel",
2918 srl->nhlfe[1].label_in);
2919 json_object_int_add(json_obj, "outputLabel",
2920 srl->nhlfe[1].label_out);
2921 json_object_string_add(json_obj, "interface",
2922 itf ? itf->name : "-");
2923 json_object_string_addf(json_obj, "nexthop", "%pI4",
2924 &srl->nhlfe[1].nexthop);
2925 json_object_array_add(json_link, json_obj);
2926 } else {
2927 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2928 pref, sid,
2929 sr_op2str(op, 32, srl->nhlfe[0].label_in,
2930 srl->nhlfe[0].label_out),
2931 itf ? itf->name : "-",
2932 inet_ntop(AF_INET, &srl->nhlfe[0].nexthop,
2933 buf, sizeof(buf)));
2934 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2935 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2936 pref, sid,
2937 sr_op2str(op, 32, srl->nhlfe[1].label_in,
2938 srl->nhlfe[1].label_out),
2939 itf ? itf->name : "-",
2940 inet_ntop(AF_INET, &srl->nhlfe[1].nexthop,
2941 buf, sizeof(buf)));
2942 }
2943 }
2944 if (json)
2945 json_object_array_add(json, json_node);
2946 else
2947 vty_out(vty, "%s\n", sbuf_buf(&sbuf));
2948
2949 sbuf_free(&sbuf);
2950 }
2951
2952 static void show_vty_srdb(struct hash_bucket *bucket, void *args)
2953 {
2954 struct vty *vty = (struct vty *)args;
2955 struct sr_node *srn = (struct sr_node *)bucket->data;
2956
2957 show_sr_node(vty, NULL, srn);
2958 }
2959
2960 static void show_json_srdb(struct hash_bucket *bucket, void *args)
2961 {
2962 struct json_object *json = (struct json_object *)args;
2963 struct sr_node *srn = (struct sr_node *)bucket->data;
2964
2965 show_sr_node(NULL, json, srn);
2966 }
2967
2968 DEFUN (show_ip_opsf_srdb,
2969 show_ip_ospf_srdb_cmd,
2970 "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
2971 SHOW_STR
2972 IP_STR
2973 OSPF_STR
2974 "Database summary\n"
2975 "Show Segment Routing Data Base\n"
2976 "Advertising SR node\n"
2977 "Advertising SR node ID (as an IP address)\n"
2978 "Self-originated SR node\n"
2979 JSON_STR)
2980 {
2981 int idx = 0;
2982 struct in_addr rid;
2983 struct sr_node *srn;
2984 bool uj = use_json(argc, argv);
2985 json_object *json = NULL, *json_node_array = NULL;
2986
2987 if (OspfSR.status == SR_OFF) {
2988 vty_out(vty, "Segment Routing is disabled on this router\n");
2989 return CMD_WARNING;
2990 }
2991
2992 if (uj) {
2993 json = json_object_new_object();
2994 json_node_array = json_object_new_array();
2995 json_object_string_addf(json, "srdbID", "%pI4",
2996 &OspfSR.self->adv_router);
2997 json_object_object_add(json, "srNodes", json_node_array);
2998 } else {
2999 vty_out(vty,
3000 "\n\t\tOSPF Segment Routing database for ID %pI4\n\n",
3001 &OspfSR.self->adv_router);
3002 }
3003
3004 if (argv_find(argv, argc, "self-originate", &idx)) {
3005 srn = OspfSR.self;
3006 show_sr_node(vty, json_node_array, srn);
3007 if (uj)
3008 vty_json(vty, json);
3009 return CMD_SUCCESS;
3010 }
3011
3012 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
3013 if (!inet_aton(argv[idx]->arg, &rid)) {
3014 vty_out(vty, "Specified Router ID %s is invalid\n",
3015 argv[idx]->arg);
3016 return CMD_WARNING_CONFIG_FAILED;
3017 }
3018 /* Get the SR Node from the SRDB */
3019 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
3020 (void *)&rid);
3021 show_sr_node(vty, json_node_array, srn);
3022 if (uj)
3023 vty_json(vty, json);
3024 return CMD_SUCCESS;
3025 }
3026
3027 /* No parameters have been provided, Iterate through all the SRDB */
3028 if (uj) {
3029 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
3030 void *))show_json_srdb,
3031 (void *)json_node_array);
3032 vty_json(vty, json);
3033 } else {
3034 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
3035 void *))show_vty_srdb,
3036 (void *)vty);
3037 }
3038 return CMD_SUCCESS;
3039 }
3040
3041 /* Install new CLI commands */
3042 void ospf_sr_register_vty(void)
3043 {
3044 install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
3045
3046 install_element(OSPF_NODE, &ospf_sr_enable_cmd);
3047 install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
3048 install_element(OSPF_NODE, &sr_global_label_range_cmd);
3049 install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
3050 install_element(OSPF_NODE, &sr_local_label_range_cmd);
3051 install_element(OSPF_NODE, &no_sr_local_label_range_cmd);
3052 install_element(OSPF_NODE, &sr_node_msd_cmd);
3053 install_element(OSPF_NODE, &no_sr_node_msd_cmd);
3054 install_element(OSPF_NODE, &sr_prefix_sid_cmd);
3055 install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
3056 }