]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_sr.c
3a71e55710823d87079ec374b1066617976a8572
[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 continue;
761
762 if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &addr) ||
763 IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
764 route_unlock_node(rn);
765 return nbr;
766 }
767 }
768 return NULL;
769 }
770
771 /* Get OSPF Path from address */
772 static struct ospf_route *get_nexthop_by_addr(struct ospf *top,
773 struct prefix_ipv4 p)
774 {
775 struct route_node *rn;
776
777 /* Sanity Check */
778 if (top == NULL)
779 return NULL;
780
781 osr_debug(" |- Search Nexthop for prefix %pFX",
782 (struct prefix *)&p);
783
784 rn = route_node_lookup(top->new_table, (struct prefix *)&p);
785
786 /*
787 * Check if we found an OSPF route. May be NULL if SPF has not
788 * yet populate routing table for this prefix.
789 */
790 if (rn == NULL)
791 return NULL;
792
793 route_unlock_node(rn);
794 return rn->info;
795 }
796
797 /* Compute NHLFE entry for Extended Link */
798 static int compute_link_nhlfe(struct sr_link *srl)
799 {
800 struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
801 struct ospf_neighbor *nh;
802 int rc = 0;
803
804 osr_debug(" |- Compute NHLFE for link %pI4", &srl->itf_addr);
805
806 /* First determine the OSPF Neighbor */
807 nh = get_neighbor_by_addr(top, srl->nhlfe[0].nexthop);
808
809 /* Neighbor could be not found when OSPF Adjacency just fire up
810 * because SPF don't yet populate routing table. This NHLFE will
811 * be fixed later when SR SPF schedule will be called.
812 */
813 if (nh == NULL)
814 return rc;
815
816 osr_debug(" |- Found nexthop %pI4", &nh->router_id);
817
818 /* Set ifindex for this neighbor */
819 srl->nhlfe[0].ifindex = nh->oi->ifp->ifindex;
820 srl->nhlfe[1].ifindex = nh->oi->ifp->ifindex;
821
822 /* Update neighbor address for LAN_ADJ_SID */
823 if (srl->type == LAN_ADJ_SID) {
824 IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &nh->src);
825 IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &nh->src);
826 }
827
828 /* Set Input & Output Label */
829 if (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
830 srl->nhlfe[0].label_in = srl->sid[0];
831 else
832 srl->nhlfe[0].label_in =
833 index2label(srl->sid[0], srl->srn->srgb);
834 if (CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
835 srl->nhlfe[1].label_in = srl->sid[1];
836 else
837 srl->nhlfe[1].label_in =
838 index2label(srl->sid[1], srl->srn->srgb);
839
840 srl->nhlfe[0].label_out = MPLS_LABEL_IMPLICIT_NULL;
841 srl->nhlfe[1].label_out = MPLS_LABEL_IMPLICIT_NULL;
842
843 rc = 1;
844 return rc;
845 }
846
847 /**
848 * Compute output label for the given Prefix-SID.
849 *
850 * @param srp Segment Routing Prefix
851 * @param srnext Segment Routing nexthop node
852 *
853 * @return MPLS label or MPLS_INVALID_LABEL in case of error
854 */
855 static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
856 const struct sr_node *srnext)
857 {
858 /* Check if the nexthop SR Node is the last hop? */
859 if (srnext == srp->srn) {
860 /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
861 if (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
862 return MPLS_LABEL_IMPLICIT_NULL;
863
864 /* SR-Node requests Explicit NULL Label */
865 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
866 return MPLS_LABEL_IPV4_EXPLICIT_NULL;
867 /* Fallthrough */
868 }
869
870 /* Return SID value as MPLS label if it is an Absolute SID */
871 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG
872 | EXT_SUBTLV_PREFIX_SID_LFLG)) {
873 /*
874 * V/L SIDs have local significance, so only adjacent routers
875 * can use them (RFC8665 section #5)
876 */
877 if (srp->srn != srnext)
878 return MPLS_INVALID_LABEL;
879 return srp->sid;
880 }
881
882 /* Return MPLS label as SRGB lower bound + SID index as per RFC 8665 */
883 return (index2label(srp->sid, srnext->srgb));
884 }
885
886 /*
887 * Compute NHLFE entry for Extended Prefix
888 *
889 * @param srp - Segment Routing Prefix
890 *
891 * @return -1 if no route is found, 0 if there is no SR route ready
892 * and 1 if success or update
893 */
894 static int compute_prefix_nhlfe(struct sr_prefix *srp)
895 {
896 struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
897 struct ospf_path *path;
898 struct listnode *node;
899 struct sr_node *srnext;
900 int rc = -1;
901
902 osr_debug(" |- Compute NHLFE for prefix %pFX",
903 (struct prefix *)&srp->prefv4);
904
905
906 /* First determine the nexthop */
907 srp->route = get_nexthop_by_addr(top, srp->prefv4);
908
909 /* Nexthop could be not found when OSPF Adjacency just fire up
910 * because SPF don't yet populate routing table. This NHLFE will
911 * be fixed later when SR SPF schedule will be called.
912 */
913 if (srp->route == NULL)
914 return rc;
915
916 /* Compute Input Label with self SRGB */
917 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
918
919 rc = 0;
920 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
921
922 osr_debug(" |- Process new route via %pI4 for this prefix",
923 &path->nexthop);
924
925 /*
926 * Get SR-Node for this nexthop. Could be not yet available
927 * as Extended Link / Prefix and Router Information are flooded
928 * after LSA Type 1 & 2 which populate the OSPF Route Table
929 */
930 srnext = get_sr_node_by_nexthop(top, path->nexthop);
931 if (srnext == NULL)
932 continue;
933
934 /* And store this information for later update */
935 srnext->neighbor = OspfSR.self;
936 path->srni.nexthop = srnext;
937
938 /*
939 * SR Node could be known, but SRGB could be not initialize
940 * This is due to the fact that Extended Link / Prefix could
941 * be received before corresponding Router Information LSA
942 */
943 if (srnext == NULL || srnext->srgb.lower_bound == 0
944 || srnext->srgb.range_size == 0) {
945 osr_debug(
946 " |- SR-Node %pI4 not ready. Stop process",
947 &srnext->adv_router);
948 path->srni.label_out = MPLS_INVALID_LABEL;
949 continue;
950 }
951
952 osr_debug(" |- Found SRGB %u/%u for next hop SR-Node %pI4",
953 srnext->srgb.range_size, srnext->srgb.lower_bound,
954 &srnext->adv_router);
955
956 /* Compute Output Label with Nexthop SR Node SRGB */
957 path->srni.label_out = sr_prefix_out_label(srp, srnext);
958
959 osr_debug(" |- Computed new labels in: %u out: %u",
960 srp->label_in, path->srni.label_out);
961 rc = 1;
962 }
963 return rc;
964 }
965
966 /* Add new NHLFE entry for Adjacency SID */
967 static inline void add_adj_sid(struct sr_nhlfe nhlfe)
968 {
969 if (nhlfe.label_in != 0)
970 ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, nhlfe);
971 }
972
973 /* Remove NHLFE entry for Adjacency SID */
974 static inline void del_adj_sid(struct sr_nhlfe nhlfe)
975 {
976 if (nhlfe.label_in != 0)
977 ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
978 }
979
980 /* Update NHLFE entry for Adjacency SID */
981 static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2)
982 {
983 del_adj_sid(n1);
984 add_adj_sid(n2);
985 }
986
987 /*
988 * Functions to parse and get Extended Link / Prefix
989 * TLVs and SubTLVs
990 */
991
992 /* Extended Link SubTLVs Getter */
993 static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size)
994 {
995
996 struct sr_link *srl;
997 struct ext_tlv_link *link = (struct ext_tlv_link *)tlvh;
998 struct ext_subtlv_adj_sid *adj_sid;
999 struct ext_subtlv_lan_adj_sid *lan_sid;
1000 struct ext_subtlv_rmt_itf_addr *rmt_itf;
1001
1002 struct tlv_header *sub_tlvh;
1003 uint16_t length = 0, sum = 0, i = 0;
1004
1005 /* Check TLV size */
1006 if ((ntohs(tlvh->length) > size)
1007 || ntohs(tlvh->length) < EXT_TLV_LINK_SIZE) {
1008 zlog_warn("Wrong Extended Link TLV size. Abort!");
1009 return NULL;
1010 }
1011
1012 srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
1013
1014 /* Initialize TLV browsing */
1015 length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
1016 sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
1017 + EXT_TLV_LINK_SIZE);
1018 for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
1019 switch (ntohs(sub_tlvh->type)) {
1020 case EXT_SUBTLV_ADJ_SID:
1021 adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh;
1022 srl->type = ADJ_SID;
1023 i = CHECK_FLAG(adj_sid->flags,
1024 EXT_SUBTLV_LINK_ADJ_SID_BFLG)
1025 ? 1
1026 : 0;
1027 srl->flags[i] = adj_sid->flags;
1028 if (CHECK_FLAG(adj_sid->flags,
1029 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1030 srl->sid[i] = GET_LABEL(ntohl(adj_sid->value));
1031 else
1032 srl->sid[i] = ntohl(adj_sid->value);
1033 IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop, &link->link_id);
1034 break;
1035 case EXT_SUBTLV_LAN_ADJ_SID:
1036 lan_sid = (struct ext_subtlv_lan_adj_sid *)sub_tlvh;
1037 srl->type = LAN_ADJ_SID;
1038 i = CHECK_FLAG(lan_sid->flags,
1039 EXT_SUBTLV_LINK_ADJ_SID_BFLG)
1040 ? 1
1041 : 0;
1042 srl->flags[i] = lan_sid->flags;
1043 if (CHECK_FLAG(lan_sid->flags,
1044 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1045 srl->sid[i] = GET_LABEL(ntohl(lan_sid->value));
1046 else
1047 srl->sid[i] = ntohl(lan_sid->value);
1048 IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop,
1049 &lan_sid->neighbor_id);
1050 break;
1051 case EXT_SUBTLV_RMT_ITF_ADDR:
1052 rmt_itf = (struct ext_subtlv_rmt_itf_addr *)sub_tlvh;
1053 IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &rmt_itf->value);
1054 IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &rmt_itf->value);
1055 break;
1056 default:
1057 break;
1058 }
1059 sum += TLV_SIZE(sub_tlvh);
1060 }
1061
1062 IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data);
1063
1064 osr_debug(" |- Found primary %u and backup %u Adj/Lan Sid for %pI4",
1065 srl->sid[0], srl->sid[1], &srl->itf_addr);
1066
1067 return srl;
1068 }
1069
1070 /* Extended Prefix SubTLVs Getter */
1071 static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh,
1072 size_t size)
1073 {
1074
1075 struct sr_prefix *srp;
1076 struct ext_tlv_prefix *pref = (struct ext_tlv_prefix *)tlvh;
1077 struct ext_subtlv_prefix_sid *psid;
1078
1079 struct tlv_header *sub_tlvh;
1080 uint16_t length = 0, sum = 0;
1081
1082 /* Check TLV size */
1083 if ((ntohs(tlvh->length) > size)
1084 || ntohs(tlvh->length) < EXT_TLV_PREFIX_SIZE) {
1085 zlog_warn("Wrong Extended Link TLV size. Abort!");
1086 return NULL;
1087 }
1088
1089 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
1090
1091 /* Initialize TLV browsing */
1092 length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
1093 sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
1094 + EXT_TLV_PREFIX_SIZE);
1095 for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
1096 switch (ntohs(sub_tlvh->type)) {
1097 case EXT_SUBTLV_PREFIX_SID:
1098 psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
1099 if (psid->algorithm != SR_ALGORITHM_SPF) {
1100 flog_err(EC_OSPF_INVALID_ALGORITHM,
1101 "SR (%s): Unsupported Algorithm",
1102 __func__);
1103 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1104 return NULL;
1105 }
1106 srp->type = PREF_SID;
1107 srp->flags = psid->flags;
1108 if (CHECK_FLAG(psid->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
1109 srp->sid = GET_LABEL(ntohl(psid->value));
1110 else
1111 srp->sid = ntohl(psid->value);
1112 IPV4_ADDR_COPY(&srp->prefv4.prefix, &pref->address);
1113 srp->prefv4.prefixlen = pref->pref_length;
1114 srp->prefv4.family = AF_INET;
1115 apply_mask_ipv4(&srp->prefv4);
1116 break;
1117 default:
1118 break;
1119 }
1120 sum += TLV_SIZE(sub_tlvh);
1121 }
1122
1123 osr_debug(" |- Found SID %u for prefix %pFX", srp->sid,
1124 (struct prefix *)&srp->prefv4);
1125
1126 return srp;
1127 }
1128
1129 /*
1130 * Functions to manipulate Segment Routing Link & Prefix structures
1131 */
1132
1133 /* Compare two Segment Link: return 0 if equal, 1 otherwise */
1134 static inline int sr_link_cmp(struct sr_link *srl1, struct sr_link *srl2)
1135 {
1136 if ((srl1->sid[0] == srl2->sid[0]) && (srl1->sid[1] == srl2->sid[1])
1137 && (srl1->type == srl2->type) && (srl1->flags[0] == srl2->flags[0])
1138 && (srl1->flags[1] == srl2->flags[1]))
1139 return 0;
1140 else
1141 return 1;
1142 }
1143
1144 /* Compare two Segment Prefix: return 0 if equal, 1 otherwise */
1145 static inline int sr_prefix_cmp(struct sr_prefix *srp1, struct sr_prefix *srp2)
1146 {
1147 if ((srp1->sid == srp2->sid) && (srp1->flags == srp2->flags))
1148 return 0;
1149 else
1150 return 1;
1151 }
1152
1153 /* Update Segment Link of given Segment Routing Node */
1154 static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl,
1155 uint8_t lsa_flags)
1156 {
1157 struct listnode *node;
1158 struct sr_link *lk;
1159 bool found = false;
1160 bool config = true;
1161
1162 /* Sanity check */
1163 if ((srn == NULL) || (srl == NULL))
1164 return;
1165
1166 osr_debug(" |- Process Extended Link Adj/Lan-SID");
1167
1168 /* Detect if Adj/Lan_Adj SID must be configured */
1169 if (!CHECK_FLAG(lsa_flags, OSPF_LSA_SELF)
1170 && (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
1171 || CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG)))
1172 config = false;
1173
1174 /* Search for existing Segment Link */
1175 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, lk))
1176 if (lk->instance == srl->instance) {
1177 found = true;
1178 break;
1179 }
1180
1181 osr_debug(" |- %s SR Link 8.0.0.%u for SR node %pI4",
1182 found ? "Update" : "Add", GET_OPAQUE_ID(srl->instance),
1183 &srn->adv_router);
1184
1185 /* if not found, add new Segment Link and install NHLFE */
1186 if (!found) {
1187 /* Complete SR-Link and add it to SR-Node list */
1188 srl->srn = srn;
1189 IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
1190 listnode_add(srn->ext_link, srl);
1191 /* Try to set MPLS table */
1192 if (config && compute_link_nhlfe(srl)) {
1193 add_adj_sid(srl->nhlfe[0]);
1194 add_adj_sid(srl->nhlfe[1]);
1195 }
1196 } else {
1197 /* Update SR-Link if they are different */
1198 if (sr_link_cmp(lk, srl)) {
1199 /* Try to set MPLS table */
1200 if (config) {
1201 if (compute_link_nhlfe(srl)) {
1202 update_adj_sid(lk->nhlfe[0],
1203 srl->nhlfe[0]);
1204 update_adj_sid(lk->nhlfe[1],
1205 srl->nhlfe[1]);
1206 } else {
1207 del_adj_sid(lk->nhlfe[0]);
1208 del_adj_sid(lk->nhlfe[1]);
1209 }
1210 }
1211 /* Replace SR-Link in SR-Node Adjacency List */
1212 listnode_delete(srn->ext_link, lk);
1213 XFREE(MTYPE_OSPF_SR_PARAMS, lk);
1214 srl->srn = srn;
1215 IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
1216 listnode_add(srn->ext_link, srl);
1217 } else {
1218 /*
1219 * This is just an LSA refresh.
1220 * Stop processing and free SR Link
1221 */
1222 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1223 }
1224 }
1225 }
1226
1227 /* Update Segment Prefix of given Segment Routing Node */
1228 static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp)
1229 {
1230
1231 struct listnode *node;
1232 struct sr_prefix *pref;
1233 bool found = false;
1234
1235 /* Sanity check */
1236 if (srn == NULL || srp == NULL)
1237 return;
1238
1239 osr_debug(" |- Process Extended Prefix SID %u", srp->sid);
1240
1241 /* Process only Global Prefix SID */
1242 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_LFLG))
1243 return;
1244
1245 /* Search for existing Segment Prefix */
1246 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, pref))
1247 if (pref->instance == srp->instance
1248 && prefix_same((struct prefix *)&srp->prefv4,
1249 &pref->prefv4)) {
1250 found = true;
1251 break;
1252 }
1253
1254 osr_debug(" |- %s SR LSA ID 7.0.0.%u for SR node %pI4",
1255 found ? "Update" : "Add", GET_OPAQUE_ID(srp->instance),
1256 &srn->adv_router);
1257
1258 /* Complete SR-Prefix */
1259 srp->srn = srn;
1260 IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router);
1261
1262 /* if not found, add new Segment Prefix and install NHLFE */
1263 if (!found) {
1264 /* Add it to SR-Node list ... */
1265 listnode_add(srn->ext_prefix, srp);
1266 /* ... and try to set MPLS table */
1267 if (compute_prefix_nhlfe(srp) == 1)
1268 ospf_zebra_update_prefix_sid(srp);
1269 } else {
1270 /*
1271 * An old SR prefix exist. Check if something changes or if it
1272 * is just a refresh.
1273 */
1274 if (sr_prefix_cmp(pref, srp)) {
1275 if (compute_prefix_nhlfe(srp) == 1) {
1276 ospf_zebra_delete_prefix_sid(pref);
1277 /* Replace Segment Prefix */
1278 listnode_delete(srn->ext_prefix, pref);
1279 XFREE(MTYPE_OSPF_SR_PARAMS, pref);
1280 listnode_add(srn->ext_prefix, srp);
1281 ospf_zebra_update_prefix_sid(srp);
1282 } else {
1283 /* New NHLFE was not found.
1284 * Just free the SR Prefix
1285 */
1286 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1287 }
1288 } else {
1289 /* This is just an LSA refresh.
1290 * Stop processing and free SR Prefix
1291 */
1292 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1293 }
1294 }
1295 }
1296
1297 /*
1298 * When change the FRR Self SRGB, update the NHLFE Input Label
1299 * for all Extended Prefix with SID index through hash_iterate()
1300 */
1301 static void update_in_nhlfe(struct hash_bucket *bucket, void *args)
1302 {
1303 struct listnode *node;
1304 struct sr_node *srn = (struct sr_node *)bucket->data;
1305 struct sr_prefix *srp;
1306
1307 /* Process Every Extended Prefix for this SR-Node */
1308 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1309 /* Process Self SRN only if NO-PHP is requested */
1310 if ((srn == OspfSR.self)
1311 && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
1312 continue;
1313
1314 /* Process only SID Index */
1315 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
1316 continue;
1317
1318 /* First, remove old MPLS table entries ... */
1319 ospf_zebra_delete_prefix_sid(srp);
1320 /* ... then compute new input label ... */
1321 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
1322 /* ... and install new MPLS LFIB */
1323 ospf_zebra_update_prefix_sid(srp);
1324 }
1325 }
1326
1327 /*
1328 * When SRGB has changed, update NHLFE Output Label for all Extended Prefix
1329 * with SID index which use the given SR-Node as nexthop through hash_iterate()
1330 */
1331 static void update_out_nhlfe(struct hash_bucket *bucket, void *args)
1332 {
1333 struct listnode *node, *pnode;
1334 struct sr_node *srn = (struct sr_node *)bucket->data;
1335 struct sr_node *srnext = (struct sr_node *)args;
1336 struct sr_prefix *srp;
1337 struct ospf_path *path;
1338
1339 /* Skip Self SR-Node */
1340 if (srn == OspfSR.self)
1341 return;
1342
1343 osr_debug("SR (%s): Update Out NHLFE for neighbor SR-Node %pI4",
1344 __func__, &srn->adv_router);
1345
1346 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1347 /* Skip Prefix that has not yet a valid route */
1348 if (srp->route == NULL)
1349 continue;
1350
1351 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, pnode, path)) {
1352 /* Skip path that has not next SR-Node as nexthop */
1353 if (path->srni.nexthop != srnext)
1354 continue;
1355
1356 /* Compute new Output Label */
1357 path->srni.label_out = sr_prefix_out_label(srp, srnext);
1358 }
1359
1360 /* Finally update MPLS table */
1361 ospf_zebra_update_prefix_sid(srp);
1362 }
1363 }
1364
1365 /*
1366 * Following functions are call when new Segment Routing LSA are received
1367 * - Router Information: ospf_sr_ri_lsa_update() & ospf_sr_ri_lsa_delete()
1368 * - Extended Link: ospf_sr_ext_link_update() & ospf_sr_ext_link_delete()
1369 * - Extended Prefix: ospf_ext_prefix_update() & ospf_sr_ext_prefix_delete()
1370 */
1371
1372 /* Update Segment Routing from Router Information LSA */
1373 void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
1374 {
1375 struct sr_node *srn;
1376 struct tlv_header *tlvh;
1377 struct lsa_header *lsah = lsa->data;
1378 struct ri_sr_tlv_sid_label_range *ri_srgb = NULL;
1379 struct ri_sr_tlv_sid_label_range *ri_srlb = NULL;
1380 struct ri_sr_tlv_sr_algorithm *algo = NULL;
1381 struct sr_block srgb;
1382 uint16_t length = 0, sum = 0;
1383 uint8_t msd = 0;
1384
1385 osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4",
1386 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1387 &lsah->adv_router);
1388
1389 /* Sanity check */
1390 if (IS_LSA_SELF(lsa))
1391 return;
1392
1393 if (OspfSR.neighbors == NULL) {
1394 flog_err(EC_OSPF_SR_INVALID_DB,
1395 "SR (%s): Abort! no valid SR DataBase", __func__);
1396 return;
1397 }
1398
1399 /* Search SR Node in hash table from Router ID */
1400 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1401 &lsah->adv_router);
1402
1403
1404 /* Collect Router Information Sub TLVs */
1405 /* Initialize TLV browsing */
1406 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1407 srgb.range_size = 0;
1408 srgb.lower_bound = 0;
1409
1410 for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
1411 tlvh = TLV_HDR_NEXT(tlvh)) {
1412 switch (ntohs(tlvh->type)) {
1413 case RI_SR_TLV_SR_ALGORITHM:
1414 algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
1415 break;
1416 case RI_SR_TLV_SRGB_LABEL_RANGE:
1417 ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
1418 break;
1419 case RI_SR_TLV_SRLB_LABEL_RANGE:
1420 ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh;
1421 break;
1422 case RI_SR_TLV_NODE_MSD:
1423 msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
1424 break;
1425 default:
1426 break;
1427 }
1428 sum += TLV_SIZE(tlvh);
1429 }
1430
1431 /* Check if Segment Routing Capabilities has been found */
1432 if (ri_srgb == NULL) {
1433 /* Skip Router Information without SR capabilities
1434 * advertise by a non SR Node */
1435 if (srn == NULL) {
1436 return;
1437 } else {
1438 /* Remove SR Node that advertise Router Information
1439 * without SR capabilities. This could correspond to a
1440 * Node stopping Segment Routing */
1441 hash_release(OspfSR.neighbors, &(srn->adv_router));
1442 sr_node_del(srn);
1443 return;
1444 }
1445 }
1446
1447 /* Check that RI LSA belongs to the correct SR Node */
1448 if ((srn != NULL) && (srn->instance != 0)
1449 && (srn->instance != ntohl(lsah->id.s_addr))) {
1450 flog_err(EC_OSPF_SR_INVALID_LSA_ID,
1451 "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4/%u",
1452 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1453 &lsah->adv_router, srn->instance);
1454 return;
1455 }
1456
1457 /* OK. All things look good. Get SRGB */
1458 srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size));
1459 srgb.lower_bound = GET_LABEL(ntohl(ri_srgb->lower.value));
1460
1461 /* Check if it is a new SR Node or not */
1462 if (srn == NULL) {
1463 /* Get a new SR Node in hash table from Router ID */
1464 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1465 &lsah->adv_router,
1466 (void *)sr_node_new);
1467 /* update LSA ID */
1468 srn->instance = ntohl(lsah->id.s_addr);
1469 /* Copy SRGB */
1470 srn->srgb.range_size = srgb.range_size;
1471 srn->srgb.lower_bound = srgb.lower_bound;
1472 }
1473
1474 /* Update Algorithm, SRLB and MSD if present */
1475 if (algo != NULL) {
1476 int i;
1477 for (i = 0; i < ntohs(algo->header.length); i++)
1478 srn->algo[i] = algo->value[0];
1479 for (; i < ALGORITHM_COUNT; i++)
1480 srn->algo[i] = SR_ALGORITHM_UNSET;
1481 } else {
1482 srn->algo[0] = SR_ALGORITHM_SPF;
1483 }
1484 srn->msd = msd;
1485 if (ri_srlb != NULL) {
1486 srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size));
1487 srn->srlb.lower_bound = GET_LABEL(ntohl(ri_srlb->lower.value));
1488 }
1489
1490 /* Check if SRGB has changed */
1491 if ((srn->srgb.range_size == srgb.range_size)
1492 && (srn->srgb.lower_bound == srgb.lower_bound))
1493 return;
1494
1495 /* Copy SRGB */
1496 srn->srgb.range_size = srgb.range_size;
1497 srn->srgb.lower_bound = srgb.lower_bound;
1498
1499 osr_debug(" |- Update SR-Node[%pI4], SRGB[%u/%u], SRLB[%u/%u], Algo[%u], MSD[%u]",
1500 &srn->adv_router, srn->srgb.lower_bound, srn->srgb.range_size,
1501 srn->srlb.lower_bound, srn->srlb.range_size, srn->algo[0],
1502 srn->msd);
1503
1504 /* ... and NHLFE if it is a neighbor SR node */
1505 if (srn->neighbor == OspfSR.self)
1506 hash_iterate(OspfSR.neighbors, update_out_nhlfe, srn);
1507 }
1508
1509 /*
1510 * Delete SR Node entry in hash table information corresponding to an expired
1511 * Router Information LSA
1512 */
1513 void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
1514 {
1515 struct sr_node *srn;
1516 struct lsa_header *lsah = lsa->data;
1517
1518 osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", __func__,
1519 &lsah->adv_router, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)));
1520
1521 /* Sanity check */
1522 if (OspfSR.neighbors == NULL) {
1523 flog_err(EC_OSPF_SR_INVALID_DB,
1524 "SR (%s): Abort! no valid SR Data Base", __func__);
1525 return;
1526 }
1527
1528 /* Release Router ID entry in SRDB hash table */
1529 srn = hash_release(OspfSR.neighbors, &(lsah->adv_router));
1530
1531 /* Sanity check */
1532 if (srn == NULL) {
1533 flog_err(EC_OSPF_SR_NODE_CREATE,
1534 "SR (%s): Abort! no entry in SRDB for SR Node %pI4",
1535 __func__, &lsah->adv_router);
1536 return;
1537 }
1538
1539 if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
1540 flog_err(
1541 EC_OSPF_SR_INVALID_LSA_ID,
1542 "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4",
1543 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1544 &lsah->adv_router);
1545 return;
1546 }
1547
1548 /* Remove SR node */
1549 sr_node_del(srn);
1550 }
1551
1552 /* Update Segment Routing from Extended Link LSA */
1553 void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
1554 {
1555 struct sr_node *srn;
1556 struct tlv_header *tlvh;
1557 struct lsa_header *lsah = lsa->data;
1558 struct sr_link *srl;
1559
1560 int length;
1561
1562 osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4",
1563 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1564 &lsah->adv_router);
1565
1566 /* Sanity check */
1567 if (OspfSR.neighbors == NULL) {
1568 flog_err(EC_OSPF_SR_INVALID_DB,
1569 "SR (%s): Abort! no valid SR DataBase", __func__);
1570 return;
1571 }
1572
1573 /* Get SR Node in hash table from Router ID */
1574 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1575 (void *)&(lsah->adv_router),
1576 (void *)sr_node_new);
1577
1578 /* Initialize TLV browsing */
1579 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1580 for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
1581 tlvh = TLV_HDR_NEXT(tlvh)) {
1582 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1583 /* Got Extended Link information */
1584 srl = get_ext_link_sid(tlvh, length);
1585 /* Update SID if not null */
1586 if (srl != NULL) {
1587 srl->instance = ntohl(lsah->id.s_addr);
1588 update_ext_link_sid(srn, srl, lsa->flags);
1589 }
1590 }
1591 length -= TLV_SIZE(tlvh);
1592 }
1593 }
1594
1595 /* Delete Segment Routing from Extended Link LSA */
1596 void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
1597 {
1598 struct listnode *node;
1599 struct sr_link *srl;
1600 struct sr_node *srn;
1601 struct lsa_header *lsah = lsa->data;
1602 uint32_t instance = ntohl(lsah->id.s_addr);
1603
1604 osr_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %pI4",
1605 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1606 &lsah->adv_router);
1607
1608 /* Sanity check */
1609 if (OspfSR.neighbors == NULL) {
1610 flog_err(EC_OSPF_SR_INVALID_DB,
1611 "SR (%s): Abort! no valid SR DataBase", __func__);
1612 return;
1613 }
1614
1615 /* Search SR Node in hash table from Router ID */
1616 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1617 (void *)&(lsah->adv_router));
1618
1619 /*
1620 * SR-Node may be NULL if it has been remove previously when
1621 * processing Router Information LSA deletion
1622 */
1623 if (srn == NULL) {
1624 flog_err(EC_OSPF_SR_INVALID_DB,
1625 "SR (%s): Stop! no entry in SRDB for SR Node %pI4",
1626 __func__, &lsah->adv_router);
1627 return;
1628 }
1629
1630 /* Search for corresponding Segment Link */
1631 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
1632 if (srl->instance == instance)
1633 break;
1634
1635 /* Remove Segment Link if found. Note that for Neighbors, only Global
1636 * Adj/Lan-Adj SID are stored in the SR-DB */
1637 if ((srl != NULL) && (srl->instance == instance)) {
1638 del_adj_sid(srl->nhlfe[0]);
1639 del_adj_sid(srl->nhlfe[1]);
1640 listnode_delete(srn->ext_link, srl);
1641 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1642 }
1643 }
1644
1645 /* Add (LAN)Adjacency-SID from Extended Link Information */
1646 void ospf_sr_ext_itf_add(struct ext_itf *exti)
1647 {
1648 struct sr_node *srn = OspfSR.self;
1649 struct sr_link *srl;
1650
1651 osr_debug("SR (%s): Add Extended Link LSA 8.0.0.%u from self", __func__,
1652 exti->instance);
1653
1654 /* Sanity check */
1655 if (srn == NULL)
1656 return;
1657
1658 /* Initialize new Segment Routing Link */
1659 srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
1660 srl->srn = srn;
1661 srl->adv_router = srn->adv_router;
1662 srl->itf_addr = exti->link.link_data;
1663 srl->instance =
1664 SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
1665 srl->remote_id = exti->link.link_id;
1666 switch (exti->stype) {
1667 case ADJ_SID:
1668 srl->type = ADJ_SID;
1669 /* Primary information */
1670 srl->flags[0] = exti->adj_sid[0].flags;
1671 if (CHECK_FLAG(exti->adj_sid[0].flags,
1672 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1673 srl->sid[0] = GET_LABEL(ntohl(exti->adj_sid[0].value));
1674 else
1675 srl->sid[0] = ntohl(exti->adj_sid[0].value);
1676 if (exti->rmt_itf_addr.header.type == 0)
1677 srl->nhlfe[0].nexthop = exti->link.link_id;
1678 else
1679 srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
1680 /* Backup Information if set */
1681 if (exti->adj_sid[1].header.type == 0)
1682 break;
1683 srl->flags[1] = exti->adj_sid[1].flags;
1684 if (CHECK_FLAG(exti->adj_sid[1].flags,
1685 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1686 srl->sid[1] = GET_LABEL(ntohl(exti->adj_sid[1].value));
1687 else
1688 srl->sid[1] = ntohl(exti->adj_sid[1].value);
1689 if (exti->rmt_itf_addr.header.type == 0)
1690 srl->nhlfe[1].nexthop = exti->link.link_id;
1691 else
1692 srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
1693 break;
1694 case LAN_ADJ_SID:
1695 srl->type = LAN_ADJ_SID;
1696 /* Primary information */
1697 srl->flags[0] = exti->lan_sid[0].flags;
1698 if (CHECK_FLAG(exti->lan_sid[0].flags,
1699 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1700 srl->sid[0] = GET_LABEL(ntohl(exti->lan_sid[0].value));
1701 else
1702 srl->sid[0] = ntohl(exti->lan_sid[0].value);
1703 if (exti->rmt_itf_addr.header.type == 0)
1704 srl->nhlfe[0].nexthop = exti->lan_sid[0].neighbor_id;
1705 else
1706 srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value;
1707 /* Backup Information if set */
1708 if (exti->lan_sid[1].header.type == 0)
1709 break;
1710 srl->flags[1] = exti->lan_sid[1].flags;
1711 if (CHECK_FLAG(exti->lan_sid[1].flags,
1712 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
1713 srl->sid[1] = GET_LABEL(ntohl(exti->lan_sid[1].value));
1714 else
1715 srl->sid[1] = ntohl(exti->lan_sid[1].value);
1716 if (exti->rmt_itf_addr.header.type == 0)
1717 srl->nhlfe[1].nexthop = exti->lan_sid[1].neighbor_id;
1718 else
1719 srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
1720 break;
1721 case PREF_SID:
1722 case LOCAL_SID:
1723 /* Wrong SID Type. Abort! */
1724 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1725 return;
1726 }
1727
1728 /* Segment Routing Link is ready, update it */
1729 update_ext_link_sid(srn, srl, OSPF_LSA_SELF);
1730 }
1731
1732 /* Delete Prefix or (LAN)Adjacency-SID from Extended Link Information */
1733 void ospf_sr_ext_itf_delete(struct ext_itf *exti)
1734 {
1735 struct listnode *node;
1736 struct sr_node *srn = OspfSR.self;
1737 struct sr_prefix *srp = NULL;
1738 struct sr_link *srl = NULL;
1739 uint32_t instance;
1740
1741 osr_debug("SR (%s): Remove Extended LSA %u.0.0.%u from self",
1742 __func__, exti->stype == PREF_SID ? 7 : 8, exti->instance);
1743
1744 /* Sanity check: SR-Node and Extended Prefix/Link list may have been
1745 * removed earlier when stopping OSPF or OSPF-SR */
1746 if (srn == NULL || srn->ext_prefix == NULL || srn->ext_link == NULL)
1747 return;
1748
1749 if (exti->stype == PREF_SID) {
1750 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
1751 exti->instance);
1752 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
1753 if (srp->instance == instance)
1754 break;
1755
1756 /* Uninstall Segment Prefix SID if found */
1757 if ((srp != NULL) && (srp->instance == instance))
1758 ospf_zebra_delete_prefix_sid(srp);
1759 } else {
1760 /* Search for corresponding Segment Link for self SR-Node */
1761 instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA,
1762 exti->instance);
1763 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
1764 if (srl->instance == instance)
1765 break;
1766
1767 /* Remove Segment Link if found */
1768 if ((srl != NULL) && (srl->instance == instance)) {
1769 del_adj_sid(srl->nhlfe[0]);
1770 del_adj_sid(srl->nhlfe[1]);
1771 listnode_delete(srn->ext_link, srl);
1772 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1773 }
1774 }
1775 }
1776
1777 /* Update Segment Routing from Extended Prefix LSA */
1778 void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
1779 {
1780 struct sr_node *srn;
1781 struct tlv_header *tlvh;
1782 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1783 struct sr_prefix *srp;
1784
1785 int length;
1786
1787 osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4",
1788 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1789 &lsah->adv_router);
1790
1791 /* Sanity check */
1792 if (OspfSR.neighbors == NULL) {
1793 flog_err(EC_OSPF_SR_INVALID_DB,
1794 "SR (%s): Abort! no valid SR DataBase", __func__);
1795 return;
1796 }
1797
1798 /* Get SR Node in hash table from Router ID */
1799 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1800 (void *)&(lsah->adv_router),
1801 (void *)sr_node_new);
1802 /* Initialize TLV browsing */
1803 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1804 for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh;
1805 tlvh = TLV_HDR_NEXT(tlvh)) {
1806 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1807 /* Got Extended Link information */
1808 srp = get_ext_prefix_sid(tlvh, length);
1809 /* Update SID if not null */
1810 if (srp != NULL) {
1811 srp->instance = ntohl(lsah->id.s_addr);
1812 update_ext_prefix_sid(srn, srp);
1813 }
1814 }
1815 length -= TLV_SIZE(tlvh);
1816 }
1817 }
1818
1819 /* Delete Segment Routing from Extended Prefix LSA */
1820 void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
1821 {
1822 struct listnode *node;
1823 struct sr_prefix *srp;
1824 struct sr_node *srn;
1825 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1826 uint32_t instance = ntohl(lsah->id.s_addr);
1827
1828 osr_debug("SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %pI4",
1829 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1830 &lsah->adv_router);
1831
1832 /* Sanity check */
1833 if (OspfSR.neighbors == NULL) {
1834 flog_err(EC_OSPF_SR_INVALID_DB,
1835 "SR (%s): Abort! no valid SR DataBase", __func__);
1836 return;
1837 }
1838
1839 /* Search SR Node in hash table from Router ID */
1840 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1841 (void *)&(lsah->adv_router));
1842
1843 /*
1844 * SR-Node may be NULL if it has been remove previously when
1845 * processing Router Information LSA deletion
1846 */
1847 if (srn == NULL) {
1848 flog_err(EC_OSPF_SR_INVALID_DB,
1849 "SR (%s): Stop! no entry in SRDB for SR Node %pI4",
1850 __func__, &lsah->adv_router);
1851 return;
1852 }
1853
1854 /* Search for corresponding Segment Prefix */
1855 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
1856 if (srp->instance == instance)
1857 break;
1858
1859 /* Remove Prefix if found */
1860 if ((srp != NULL) && (srp->instance == instance)) {
1861 ospf_zebra_delete_prefix_sid(srp);
1862 listnode_delete(srn->ext_prefix, srp);
1863 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1864 } else {
1865 flog_err(
1866 EC_OSPF_SR_INVALID_DB,
1867 "SR (%s): Didn't found corresponding SR Prefix 7.0.0.%u for SR Node %pI4",
1868 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1869 &lsah->adv_router);
1870 }
1871 }
1872
1873 /*
1874 * Update Prefix SID. Call by ospf_ext_pref_ism_change to
1875 * complete initial CLI command at startup.
1876 *
1877 * @param ifp - Loopback interface
1878 * @param pref - Prefix address of this interface
1879 *
1880 * @return - void
1881 */
1882 void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p)
1883 {
1884 struct listnode *node;
1885 struct sr_prefix *srp;
1886
1887 /* Sanity Check */
1888 if ((ifp == NULL) || (p == NULL))
1889 return;
1890
1891 /*
1892 * Search if there is a Segment Prefix that correspond to this
1893 * interface or prefix, and update it if found
1894 */
1895 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
1896 if ((srp->nhlfe.ifindex == ifp->ifindex)
1897 || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p->u.prefix4))
1898 && (srp->prefv4.prefixlen == p->prefixlen))) {
1899
1900 /* Update Interface & Prefix info */
1901 srp->nhlfe.ifindex = ifp->ifindex;
1902 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p->u.prefix4);
1903 srp->prefv4.prefixlen = p->prefixlen;
1904 srp->prefv4.family = p->family;
1905 IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4);
1906
1907 /* OK. Let's Schedule Extended Prefix LSA */
1908 srp->instance = ospf_ext_schedule_prefix_index(
1909 ifp, srp->sid, &srp->prefv4, srp->flags);
1910
1911 osr_debug(
1912 " |- Update Node SID %pFX - %u for self SR Node",
1913 (struct prefix *)&srp->prefv4, srp->sid);
1914
1915 /* Install SID if NO-PHP is set and not EXPLICIT-NULL */
1916 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
1917 && !CHECK_FLAG(srp->flags,
1918 EXT_SUBTLV_PREFIX_SID_EFLG)) {
1919 srp->label_in = index2label(srp->sid,
1920 OspfSR.self->srgb);
1921 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
1922 ospf_zebra_update_prefix_sid(srp);
1923 }
1924 }
1925 }
1926 }
1927
1928 /*
1929 * Following functions are used to update MPLS LFIB after a SPF run
1930 */
1931
1932 static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args)
1933 {
1934
1935 struct sr_node *srn = (struct sr_node *)bucket->data;
1936 struct listnode *node;
1937 struct sr_prefix *srp;
1938 bool old;
1939 int rc;
1940
1941 osr_debug(" |- Update Prefix for SR Node %pI4", &srn->adv_router);
1942
1943 /* Skip Self SR Node */
1944 if (srn == OspfSR.self)
1945 return;
1946
1947 /* Update Extended Prefix */
1948 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1949
1950 /* Keep track of valid route */
1951 old = srp->route != NULL;
1952
1953 /* Compute the new NHLFE */
1954 rc = compute_prefix_nhlfe(srp);
1955
1956 /* Check computation result */
1957 switch (rc) {
1958 /* Routes are not know, remove old NHLFE if any to avoid loop */
1959 case -1:
1960 if (old)
1961 ospf_zebra_delete_prefix_sid(srp);
1962 break;
1963 /* Routes exist but are not ready, skip it */
1964 case 0:
1965 break;
1966 /* There is at least one route, update NHLFE */
1967 case 1:
1968 ospf_zebra_update_prefix_sid(srp);
1969 break;
1970 default:
1971 break;
1972 }
1973 }
1974 }
1975
1976 void ospf_sr_update_task(struct ospf *ospf)
1977 {
1978
1979 struct timeval start_time, stop_time;
1980
1981 /* Check ospf and SR status */
1982 if ((ospf == NULL) || (OspfSR.status != SR_UP))
1983 return;
1984
1985 monotime(&start_time);
1986
1987 osr_debug("SR (%s): Start SPF update", __func__);
1988
1989 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
1990 void *))ospf_sr_nhlfe_update,
1991 NULL);
1992
1993 monotime(&stop_time);
1994
1995 osr_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__,
1996 (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
1997 + (stop_time.tv_usec - start_time.tv_usec));
1998 }
1999
2000 /*
2001 * --------------------------------------
2002 * Following are vty command functions.
2003 * --------------------------------------
2004 */
2005
2006 /*
2007 * Segment Routing Router configuration
2008 *
2009 * Must be centralize as it concerns both Extended Link/Prefix LSA
2010 * and Router Information LSA. Choose to call it from Extended Prefix
2011 * write_config() call back.
2012 *
2013 * @param vty VTY output
2014 *
2015 * @return none
2016 */
2017 void ospf_sr_config_write_router(struct vty *vty)
2018 {
2019 struct listnode *node;
2020 struct sr_prefix *srp;
2021 uint32_t upper;
2022
2023 if (OspfSR.status == SR_UP)
2024 vty_out(vty, " segment-routing on\n");
2025
2026 upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
2027 if ((OspfSR.srgb.start != DEFAULT_SRGB_LABEL)
2028 || (OspfSR.srgb.size != DEFAULT_SRGB_SIZE))
2029 vty_out(vty, " segment-routing global-block %u %u",
2030 OspfSR.srgb.start, upper);
2031
2032 if ((OspfSR.srlb.start != DEFAULT_SRLB_LABEL) ||
2033 (OspfSR.srlb.end != DEFAULT_SRLB_END)) {
2034 if ((OspfSR.srgb.start == DEFAULT_SRGB_LABEL) &&
2035 (OspfSR.srgb.size == DEFAULT_SRGB_SIZE))
2036 vty_out(vty, " segment-routing global-block %u %u",
2037 OspfSR.srgb.start, upper);
2038 vty_out(vty, " local-block %u %u\n", OspfSR.srlb.start,
2039 OspfSR.srlb.end);
2040 } else
2041 vty_out(vty, "\n");
2042
2043 if (OspfSR.msd != 0)
2044 vty_out(vty, " segment-routing node-msd %u\n", OspfSR.msd);
2045
2046 if (OspfSR.self != NULL) {
2047 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2048 vty_out(vty, " segment-routing prefix %pFX index %u",
2049 &srp->prefv4, srp->sid);
2050 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2051 vty_out(vty, " explicit-null\n");
2052 else if (CHECK_FLAG(srp->flags,
2053 EXT_SUBTLV_PREFIX_SID_NPFLG))
2054 vty_out(vty, " no-php-flag\n");
2055 else
2056 vty_out(vty, "\n");
2057 }
2058 }
2059 }
2060
2061 DEFUN(ospf_sr_enable,
2062 ospf_sr_enable_cmd,
2063 "segment-routing on",
2064 SR_STR
2065 "Enable Segment Routing\n")
2066 {
2067
2068 VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
2069
2070 if (OspfSR.status != SR_OFF)
2071 return CMD_SUCCESS;
2072
2073 if (ospf->vrf_id != VRF_DEFAULT) {
2074 vty_out(vty,
2075 "Segment Routing is only supported in default VRF\n");
2076 return CMD_WARNING_CONFIG_FAILED;
2077 }
2078
2079 osr_debug("SR: Segment Routing: OFF -> ON");
2080
2081 /* Start Segment Routing */
2082 OspfSR.status = SR_ON;
2083 ospf_sr_start(ospf);
2084
2085 return CMD_SUCCESS;
2086 }
2087
2088 DEFUN (no_ospf_sr_enable,
2089 no_ospf_sr_enable_cmd,
2090 "no segment-routing [on]",
2091 NO_STR
2092 SR_STR
2093 "Disable Segment Routing\n")
2094 {
2095
2096 if (OspfSR.status == SR_OFF)
2097 return CMD_SUCCESS;
2098
2099 osr_debug("SR: Segment Routing: ON -> OFF");
2100
2101 /* Start by Disabling Extended Link & Prefix LSA */
2102 ospf_ext_update_sr(false);
2103
2104 /* then, disable Router Information SR parameters */
2105 ospf_router_info_update_sr(false, OspfSR.self);
2106
2107 /* Finally, stop Segment Routing */
2108 ospf_sr_stop();
2109
2110 return CMD_SUCCESS;
2111 }
2112
2113 static int ospf_sr_enabled(struct vty *vty)
2114 {
2115 if (OspfSR.status != SR_OFF)
2116 return 1;
2117
2118 if (vty)
2119 vty_out(vty, "%% OSPF SR is not turned on\n");
2120
2121 return 0;
2122 }
2123
2124 /* tell if two ranges [r1_lower, r1_upper] and [r2_lower,r2_upper] overlap */
2125 static bool ranges_overlap(uint32_t r1_lower, uint32_t r1_upper,
2126 uint32_t r2_lower, uint32_t r2_upper)
2127 {
2128 return !((r1_upper < r2_lower) || (r1_lower > r2_upper));
2129 }
2130
2131
2132 /* tell if a range is valid */
2133 static bool sr_range_is_valid(uint32_t lower, uint32_t upper, uint32_t min_size)
2134 {
2135 return (upper >= lower + min_size);
2136 }
2137
2138 /**
2139 * Update SRGB and/or SRLB using new CLI values.
2140 *
2141 * @param gb_lower Lower bound of the SRGB
2142 * @param gb_upper Upper bound of the SRGB
2143 * @param lb_lower Lower bound of the SRLB
2144 * @param lb_upper Upper bound of the SRLB
2145 *
2146 * @return 0 on success, -1 otherwise
2147 */
2148 static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper,
2149 uint32_t lb_lower, uint32_t lb_upper)
2150 {
2151
2152 /* Check if values have changed */
2153 bool gb_changed, lb_changed;
2154 uint32_t gb_size = gb_upper - gb_lower + 1;
2155 uint32_t lb_size = lb_upper - lb_lower + 1;
2156
2157 gb_changed =
2158 (OspfSR.srgb.size != gb_size || OspfSR.srgb.start != gb_lower);
2159 lb_changed =
2160 (OspfSR.srlb.end != lb_upper || OspfSR.srlb.start != lb_lower);
2161 if (!gb_changed && !lb_changed)
2162 return 0;
2163
2164 /* Check if SR is correctly started i.e. Label Manager connected */
2165 if (OspfSR.status != SR_UP) {
2166 OspfSR.srgb.size = gb_size;
2167 OspfSR.srgb.start = gb_lower;
2168 OspfSR.srlb.end = lb_upper;
2169 OspfSR.srlb.start = lb_lower;
2170 return 0;
2171 }
2172
2173 /* Release old SRGB if it has changed and is active. */
2174 if (gb_changed) {
2175
2176 sr_global_block_delete();
2177
2178 /* Set new SRGB values - but do not reserve yet (we need to
2179 * release the SRLB too) */
2180 OspfSR.srgb.size = gb_size;
2181 OspfSR.srgb.start = gb_lower;
2182 if (OspfSR.self != NULL) {
2183 OspfSR.self->srgb.range_size = gb_size;
2184 OspfSR.self->srgb.lower_bound = gb_lower;
2185 }
2186 }
2187 /* Release old SRLB if it has changed and reserve new block as needed.
2188 */
2189 if (lb_changed) {
2190
2191 sr_local_block_delete();
2192
2193 /* Set new SRLB values */
2194 if (sr_local_block_init(lb_lower, lb_upper) < 0) {
2195 ospf_sr_stop();
2196 return -1;
2197 }
2198 if (OspfSR.self != NULL) {
2199 OspfSR.self->srlb.lower_bound = lb_lower;
2200 OspfSR.self->srlb.range_size = lb_size;
2201 }
2202 }
2203
2204 /*
2205 * Try to reserve the new SRGB from the Label Manger. If the
2206 * allocation fails, disable SR until new blocks are successfully
2207 * allocated.
2208 */
2209 if (gb_changed) {
2210 if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size)
2211 < 0) {
2212 ospf_sr_stop();
2213 return -1;
2214 }
2215 }
2216
2217 /* Update Self SR-Node */
2218 if (OspfSR.self != NULL) {
2219 /* SRGB is reserved, set Router Information parameters */
2220 ospf_router_info_update_sr(true, OspfSR.self);
2221
2222 /* and update NHLFE entries */
2223 if (gb_changed)
2224 hash_iterate(OspfSR.neighbors,
2225 (void (*)(struct hash_bucket *,
2226 void *))update_in_nhlfe,
2227 NULL);
2228
2229 /* and update (LAN)-Adjacency SID */
2230 if (lb_changed)
2231 ospf_ext_link_srlb_update();
2232 }
2233
2234 return 0;
2235 }
2236
2237 DEFUN(sr_global_label_range, sr_global_label_range_cmd,
2238 "segment-routing global-block (16-1048575) (16-1048575) [local-block (16-1048575) (16-1048575)]",
2239 SR_STR
2240 "Segment Routing Global Block label range\n"
2241 "Lower-bound range in decimal (16-1048575)\n"
2242 "Upper-bound range in decimal (16-1048575)\n"
2243 "Segment Routing Local Block label range\n"
2244 "Lower-bound range in decimal (16-1048575)\n"
2245 "Upper-bound range in decimal (16-1048575)\n")
2246 {
2247 uint32_t lb_upper, lb_lower;
2248 uint32_t gb_upper, gb_lower;
2249 int idx_gb_low = 2, idx_gb_up = 3;
2250 int idx_lb_low = 5, idx_lb_up = 6;
2251
2252 /* Get lower and upper bound for mandatory global-block */
2253 gb_lower = strtoul(argv[idx_gb_low]->arg, NULL, 10);
2254 gb_upper = strtoul(argv[idx_gb_up]->arg, NULL, 10);
2255
2256 /* SRLB values are taken from vtysh if there, else use the known ones */
2257 lb_upper = argc > idx_lb_up ? strtoul(argv[idx_lb_up]->arg, NULL, 10)
2258 : OspfSR.srlb.end;
2259 lb_lower = argc > idx_lb_low ? strtoul(argv[idx_lb_low]->arg, NULL, 10)
2260 : OspfSR.srlb.start;
2261
2262 /* check correctness of input SRGB */
2263 if (!sr_range_is_valid(gb_lower, gb_upper, MIN_SRGB_SIZE)) {
2264 vty_out(vty, "Invalid SRGB range\n");
2265 return CMD_WARNING_CONFIG_FAILED;
2266 }
2267
2268 /* check correctness of SRLB */
2269 if (!sr_range_is_valid(lb_lower, lb_upper, MIN_SRLB_SIZE)) {
2270 vty_out(vty, "Invalid SRLB range\n");
2271 return CMD_WARNING_CONFIG_FAILED;
2272 }
2273
2274 /* Validate SRGB against SRLB */
2275 if (ranges_overlap(gb_lower, gb_upper, lb_lower, lb_upper)) {
2276 vty_out(vty,
2277 "New SR Global Block (%u/%u) conflicts with Local Block (%u/%u)\n",
2278 gb_lower, gb_upper, lb_lower, lb_upper);
2279 return CMD_WARNING_CONFIG_FAILED;
2280 }
2281
2282 if (update_sr_blocks(gb_lower, gb_upper, lb_lower, lb_upper) < 0)
2283 return CMD_WARNING_CONFIG_FAILED;
2284 else
2285 return CMD_SUCCESS;
2286 }
2287
2288 DEFUN(no_sr_global_label_range, no_sr_global_label_range_cmd,
2289 "no segment-routing global-block [(16-1048575) (16-1048575) local-block (16-1048575) (16-1048575)]",
2290 NO_STR SR_STR
2291 "Segment Routing Global Block label range\n"
2292 "Lower-bound range in decimal (16-1048575)\n"
2293 "Upper-bound range in decimal (16-1048575)\n"
2294 "Segment Routing Local Block label range\n"
2295 "Lower-bound range in decimal (16-1048575)\n"
2296 "Upper-bound range in decimal (16-1048575)\n")
2297 {
2298 if (update_sr_blocks(DEFAULT_SRGB_LABEL, DEFAULT_SRGB_END,
2299 DEFAULT_SRLB_LABEL, DEFAULT_SRLB_END)
2300 < 0)
2301 return CMD_WARNING_CONFIG_FAILED;
2302 else
2303 return CMD_SUCCESS;
2304 }
2305
2306 DEFUN (sr_node_msd,
2307 sr_node_msd_cmd,
2308 "segment-routing node-msd (1-16)",
2309 SR_STR
2310 "Maximum Stack Depth for this router\n"
2311 "Maximum number of label that could be stack (1-16)\n")
2312 {
2313 uint32_t msd;
2314 int idx = 1;
2315
2316 if (!ospf_sr_enabled(vty))
2317 return CMD_WARNING_CONFIG_FAILED;
2318
2319 /* Get MSD */
2320 argv_find(argv, argc, "(1-16)", &idx);
2321 msd = strtoul(argv[idx]->arg, NULL, 10);
2322 if (msd < 1 || msd > MPLS_MAX_LABELS) {
2323 vty_out(vty, "MSD must be comprise between 1 and %u\n",
2324 MPLS_MAX_LABELS);
2325 return CMD_WARNING_CONFIG_FAILED;
2326 }
2327
2328 /* Check if value has changed */
2329 if (OspfSR.msd == msd)
2330 return CMD_SUCCESS;
2331
2332 /* Set this router MSD */
2333 OspfSR.msd = msd;
2334 if (OspfSR.self != NULL) {
2335 OspfSR.self->msd = msd;
2336
2337 /* Set Router Information parameters if SR is UP */
2338 if (OspfSR.status == SR_UP)
2339 ospf_router_info_update_sr(true, OspfSR.self);
2340 }
2341
2342 return CMD_SUCCESS;
2343 }
2344
2345 DEFUN (no_sr_node_msd,
2346 no_sr_node_msd_cmd,
2347 "no segment-routing node-msd [(1-16)]",
2348 NO_STR
2349 SR_STR
2350 "Maximum Stack Depth for this router\n"
2351 "Maximum number of label that could be stack (1-16)\n")
2352 {
2353
2354 if (!ospf_sr_enabled(vty))
2355 return CMD_WARNING_CONFIG_FAILED;
2356
2357 /* unset this router MSD */
2358 OspfSR.msd = 0;
2359 if (OspfSR.self != NULL) {
2360 OspfSR.self->msd = 0;
2361
2362 /* Set Router Information parameters if SR is UP */
2363 if (OspfSR.status == SR_UP)
2364 ospf_router_info_update_sr(true, OspfSR.self);
2365 }
2366
2367 return CMD_SUCCESS;
2368 }
2369
2370 DEFUN (sr_prefix_sid,
2371 sr_prefix_sid_cmd,
2372 "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
2373 SR_STR
2374 "Prefix SID\n"
2375 "IPv4 Prefix as A.B.C.D/M\n"
2376 "SID index for this prefix in decimal (0-65535)\n"
2377 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2378 "Don't request Penultimate Hop Popping (PHP)\n"
2379 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2380 {
2381 int idx = 0;
2382 struct prefix p, pexist;
2383 uint32_t index;
2384 struct listnode *node;
2385 struct sr_prefix *srp, *exist = NULL;
2386 struct interface *ifp;
2387 bool no_php_flag = false;
2388 bool exp_null = false;
2389 bool index_in_use = false;
2390 uint8_t desired_flags = 0;
2391
2392 if (!ospf_sr_enabled(vty))
2393 return CMD_WARNING_CONFIG_FAILED;
2394
2395 /* Get network prefix */
2396 argv_find(argv, argc, "A.B.C.D/M", &idx);
2397 if (!str2prefix(argv[idx]->arg, &p)) {
2398 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2399 return CMD_WARNING_CONFIG_FAILED;
2400 }
2401
2402 /* Get & verify index value */
2403 argv_find(argv, argc, "(0-65535)", &idx);
2404 index = strtoul(argv[idx]->arg, NULL, 10);
2405 if (index > OspfSR.srgb.size - 1) {
2406 vty_out(vty, "Index %u must be lower than range size %u\n",
2407 index, OspfSR.srgb.size);
2408 return CMD_WARNING_CONFIG_FAILED;
2409 }
2410
2411 /* Get options */
2412 no_php_flag = argv_find(argv, argc, "no-php-flag", &idx);
2413 exp_null = argv_find(argv, argc, "explicit-null", &idx);
2414
2415 desired_flags |= no_php_flag ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2416 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2417 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_EFLG : 0;
2418
2419 /* Search for an existing Prefix-SID */
2420 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2421 if (prefix_same((struct prefix *)&srp->prefv4, &p))
2422 exist = srp;
2423 if (srp->sid == index) {
2424 index_in_use = true;
2425 pexist = p;
2426 }
2427 }
2428
2429 /* done if prefix segment already there with same index and flags */
2430 if (exist && exist->sid == index && exist->flags == desired_flags)
2431 return CMD_SUCCESS;
2432
2433 /* deny if index is already in use by a distinct prefix */
2434 if (!exist && index_in_use) {
2435 vty_out(vty, "Index %u is already used by %pFX\n", index,
2436 &pexist);
2437 return CMD_WARNING_CONFIG_FAILED;
2438 }
2439
2440 /* First, remove old NHLFE if installed */
2441 if (exist && CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2442 && !CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2443 ospf_zebra_delete_prefix_sid(exist);
2444
2445 /* Create new Extended Prefix to SRDB if not found */
2446 if (exist == NULL) {
2447 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
2448 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p.u.prefix4);
2449 srp->prefv4.prefixlen = p.prefixlen;
2450 srp->prefv4.family = p.family;
2451 srp->sid = index;
2452 srp->type = LOCAL_SID;
2453 } else {
2454 /* we work on the existing SR prefix */
2455 srp = exist;
2456 }
2457
2458 /* Reset labels to handle flag update */
2459 srp->label_in = 0;
2460 srp->nhlfe.label_out = 0;
2461 srp->sid = index;
2462 srp->flags = desired_flags;
2463
2464 /* If NO PHP flag is present, compute NHLFE and set label */
2465 if (no_php_flag) {
2466 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
2467 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
2468 }
2469
2470 osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
2471 (struct prefix *)&srp->prefv4);
2472
2473 /* Get Interface and check if it is a Loopback */
2474 ifp = if_lookup_prefix(&p, VRF_DEFAULT);
2475 if (ifp == NULL) {
2476 /*
2477 * Interface could be not yet available i.e. when this
2478 * command is in the configuration file, OSPF is not yet
2479 * ready. In this case, store the prefix SID for latter
2480 * update of this Extended Prefix
2481 */
2482 if (exist == NULL)
2483 listnode_add(OspfSR.self->ext_prefix, srp);
2484 zlog_info(
2485 "Interface for prefix %pFX not found. Deferred LSA flooding",
2486 &p);
2487 return CMD_SUCCESS;
2488 }
2489
2490 if (!if_is_loopback(ifp)) {
2491 vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
2492 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2493 return CMD_WARNING_CONFIG_FAILED;
2494 }
2495 srp->nhlfe.ifindex = ifp->ifindex;
2496
2497 /* Add SR Prefix if new */
2498 if (!exist)
2499 listnode_add(OspfSR.self->ext_prefix, srp);
2500
2501 /* Update Prefix SID if SR is UP */
2502 if (OspfSR.status == SR_UP) {
2503 if (no_php_flag && !exp_null)
2504 ospf_zebra_update_prefix_sid(srp);
2505 } else
2506 return CMD_SUCCESS;
2507
2508 /* Finally, update Extended Prefix LSA id SR is UP */
2509 srp->instance = ospf_ext_schedule_prefix_index(
2510 ifp, srp->sid, &srp->prefv4, srp->flags);
2511 if (srp->instance == 0) {
2512 vty_out(vty, "Unable to set index %u for prefix %pFX\n",
2513 index, &p);
2514 return CMD_WARNING;
2515 }
2516
2517 return CMD_SUCCESS;
2518 }
2519
2520 DEFUN (no_sr_prefix_sid,
2521 no_sr_prefix_sid_cmd,
2522 "no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
2523 NO_STR
2524 SR_STR
2525 "Prefix SID\n"
2526 "IPv4 Prefix as A.B.C.D/M\n"
2527 "SID index for this prefix in decimal (0-65535)\n"
2528 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2529 "Don't request Penultimate Hop Popping (PHP)\n"
2530 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2531 {
2532 int idx = 0;
2533 struct prefix p;
2534 struct listnode *node;
2535 struct sr_prefix *srp;
2536 struct interface *ifp;
2537 bool found = false;
2538 int rc;
2539
2540 if (!ospf_sr_enabled(vty))
2541 return CMD_WARNING_CONFIG_FAILED;
2542
2543 if (OspfSR.status != SR_UP)
2544 return CMD_SUCCESS;
2545
2546 /* Get network prefix */
2547 argv_find(argv, argc, "A.B.C.D/M", &idx);
2548 rc = str2prefix(argv[idx]->arg, &p);
2549 if (!rc) {
2550 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2551 return CMD_WARNING_CONFIG_FAILED;
2552 }
2553
2554 /* check that the prefix is already set */
2555 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
2556 if (IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
2557 && (srp->prefv4.prefixlen == p.prefixlen)) {
2558 found = true;
2559 break;
2560 }
2561
2562 if (!found) {
2563 vty_out(vty, "Prefix %s is not found. Abort!\n",
2564 argv[idx]->arg);
2565 return CMD_WARNING_CONFIG_FAILED;
2566 }
2567
2568 osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
2569 (struct prefix *)&srp->prefv4, srp->sid);
2570
2571 /* Get Interface */
2572 ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2573 if (ifp == NULL) {
2574 vty_out(vty, "interface for prefix %s not found.\n",
2575 argv[idx]->arg);
2576 /* silently remove from list */
2577 listnode_delete(OspfSR.self->ext_prefix, srp);
2578 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2579 return CMD_SUCCESS;
2580 }
2581
2582 /* Update Extended Prefix LSA */
2583 if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
2584 vty_out(vty, "No corresponding loopback interface. Abort!\n");
2585 return CMD_WARNING;
2586 }
2587
2588 /* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
2589 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2590 && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2591 ospf_zebra_delete_prefix_sid(srp);
2592
2593 /* OK, all is clean, remove SRP from SRDB */
2594 listnode_delete(OspfSR.self->ext_prefix, srp);
2595 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2596
2597 return CMD_SUCCESS;
2598 }
2599
2600
2601 static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
2602 mpls_label_t label_out)
2603 {
2604 if (size < 24)
2605 return NULL;
2606
2607 switch (label_out) {
2608 case MPLS_LABEL_IMPLICIT_NULL:
2609 snprintf(buf, size, "Pop(%u)", label_in);
2610 break;
2611 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2612 if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
2613 snprintf(buf, size, "no-op.");
2614 else
2615 snprintf(buf, size, "Swap(%u, null)", label_in);
2616 break;
2617 case MPLS_INVALID_LABEL:
2618 snprintf(buf, size, "no-op.");
2619 break;
2620 default:
2621 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
2622 break;
2623 }
2624 return buf;
2625 }
2626
2627 static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json,
2628 struct sr_prefix *srp)
2629 {
2630
2631 struct listnode *node;
2632 struct ospf_path *path;
2633 struct interface *itf;
2634 json_object *json_route = NULL, *json_obj;
2635 char pref[19];
2636 char sid[22];
2637 char op[32];
2638 char buf[PREFIX_STRLEN];
2639 int indent = 0;
2640
2641 snprintfrr(pref, 19, "%pFX", (struct prefix *)&srp->prefv4);
2642 snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
2643 if (json) {
2644 json_object_string_add(json, "prefix", pref);
2645 json_object_int_add(json, "sid", srp->sid);
2646 json_object_int_add(json, "inputLabel", srp->label_in);
2647 } else {
2648 sbuf_push(sbuf, 0, "%18s %21s ", pref, sid);
2649 }
2650
2651 /* Check if it is a Local Node SID */
2652 if (srp->type == LOCAL_SID) {
2653 itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2654 if (json) {
2655 if (!json_route) {
2656 json_route = json_object_new_array();
2657 json_object_object_add(json, "prefixRoute",
2658 json_route);
2659 }
2660 json_obj = json_object_new_object();
2661 json_object_int_add(json_obj, "outputLabel",
2662 srp->nhlfe.label_out);
2663 json_object_string_add(json_obj, "interface",
2664 itf ? itf->name : "-");
2665 json_object_string_addf(json_obj, "nexthop", "%pI4",
2666 &srp->nhlfe.nexthop);
2667 json_object_array_add(json_route, json_obj);
2668 } else {
2669 sbuf_push(sbuf, 0, "%20s %9s %15s\n",
2670 sr_op2str(op, 32, srp->label_in,
2671 srp->nhlfe.label_out),
2672 itf ? itf->name : "-",
2673 inet_ntop(AF_INET, &srp->nhlfe.nexthop,
2674 buf, sizeof(buf)));
2675 }
2676 return;
2677 }
2678
2679 /* Check if we have a valid path for this prefix */
2680 if (srp->route == NULL) {
2681 if (!json) {
2682 sbuf_push(sbuf, 0, "\n");
2683 }
2684 return;
2685 }
2686
2687 /* Process list of OSPF paths */
2688 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
2689 itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT);
2690 if (json) {
2691 if (!json_route) {
2692 json_route = json_object_new_array();
2693 json_object_object_add(json, "prefixRoute",
2694 json_route);
2695 }
2696 json_obj = json_object_new_object();
2697 json_object_int_add(json_obj, "outputLabel",
2698 path->srni.label_out);
2699 json_object_string_add(json_obj, "interface",
2700 itf ? itf->name : "-");
2701 json_object_string_addf(json_obj, "nexthop", "%pI4",
2702 &path->nexthop);
2703 json_object_array_add(json_route, json_obj);
2704 } else {
2705 sbuf_push(sbuf, indent, "%20s %9s %15s\n",
2706 sr_op2str(op, 32, srp->label_in,
2707 path->srni.label_out),
2708 itf ? itf->name : "-",
2709 inet_ntop(AF_INET, &path->nexthop, buf,
2710 sizeof(buf)));
2711 /* Offset to align information for ECMP */
2712 indent = 43;
2713 }
2714 }
2715 }
2716
2717 static void show_sr_node(struct vty *vty, struct json_object *json,
2718 struct sr_node *srn)
2719 {
2720
2721 struct listnode *node;
2722 struct sr_link *srl;
2723 struct sr_prefix *srp;
2724 struct interface *itf;
2725 struct sbuf sbuf;
2726 char pref[19];
2727 char sid[22];
2728 char op[32];
2729 char buf[PREFIX_STRLEN];
2730 uint32_t upper;
2731 json_object *json_node = NULL, *json_algo, *json_obj;
2732 json_object *json_prefix = NULL, *json_link = NULL;
2733
2734 /* Sanity Check */
2735 if (srn == NULL)
2736 return;
2737
2738 sbuf_init(&sbuf, NULL, 0);
2739
2740 if (json) {
2741 json_node = json_object_new_object();
2742 json_object_string_addf(json_node, "routerID", "%pI4",
2743 &srn->adv_router);
2744 json_object_int_add(json_node, "srgbSize",
2745 srn->srgb.range_size);
2746 json_object_int_add(json_node, "srgbLabel",
2747 srn->srgb.lower_bound);
2748 json_object_int_add(json_node, "srlbSize",
2749 srn->srlb.range_size);
2750 json_object_int_add(json_node, "srlbLabel",
2751 srn->srlb.lower_bound);
2752 json_algo = json_object_new_array();
2753 json_object_object_add(json_node, "algorithms", json_algo);
2754 for (int i = 0; i < ALGORITHM_COUNT; i++) {
2755 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2756 continue;
2757 json_obj = json_object_new_object();
2758 char tmp[2];
2759
2760 snprintf(tmp, sizeof(tmp), "%u", i);
2761 json_object_string_add(json_obj, tmp,
2762 srn->algo[i] == SR_ALGORITHM_SPF
2763 ? "SPF"
2764 : "S-SPF");
2765 json_object_array_add(json_algo, json_obj);
2766 }
2767 if (srn->msd != 0)
2768 json_object_int_add(json_node, "nodeMsd", srn->msd);
2769 } else {
2770 sbuf_push(&sbuf, 0, "SR-Node: %pI4", &srn->adv_router);
2771 upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
2772 sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
2773 srn->srgb.lower_bound, upper);
2774 upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
2775 sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
2776 srn->srlb.lower_bound, upper);
2777 sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
2778 srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
2779 for (int i = 1; i < ALGORITHM_COUNT; i++) {
2780 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2781 continue;
2782 sbuf_push(&sbuf, 0, "/%s",
2783 srn->algo[i] == SR_ALGORITHM_SPF ? "SPF"
2784 : "S-SPF");
2785 }
2786 if (srn->msd != 0)
2787 sbuf_push(&sbuf, 0, "\tMSD: %u", srn->msd);
2788 }
2789
2790 if (!json) {
2791 sbuf_push(&sbuf, 0,
2792 "\n\n Prefix or Link Node or Adj. SID Label Operation Interface Nexthop\n");
2793 sbuf_push(&sbuf, 0,
2794 "------------------ --------------------- -------------------- --------- ---------------\n");
2795 }
2796 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
2797 if (json) {
2798 if (!json_prefix) {
2799 json_prefix = json_object_new_array();
2800 json_object_object_add(json_node,
2801 "extendedPrefix",
2802 json_prefix);
2803 }
2804 json_obj = json_object_new_object();
2805 show_sr_prefix(NULL, json_obj, srp);
2806 json_object_array_add(json_prefix, json_obj);
2807 } else {
2808 show_sr_prefix(&sbuf, NULL, srp);
2809 }
2810 }
2811
2812 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
2813 snprintfrr(pref, 19, "%pI4/32", &srl->itf_addr);
2814 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
2815 itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
2816 if (json) {
2817 if (!json_link) {
2818 json_link = json_object_new_array();
2819 json_object_object_add(
2820 json_node, "extendedLink", json_link);
2821 }
2822 /* Primary Link */
2823 json_obj = json_object_new_object();
2824 json_object_string_add(json_obj, "prefix", pref);
2825 json_object_int_add(json_obj, "sid", srl->sid[0]);
2826 json_object_int_add(json_obj, "inputLabel",
2827 srl->nhlfe[0].label_in);
2828 json_object_int_add(json_obj, "outputLabel",
2829 srl->nhlfe[0].label_out);
2830 json_object_string_add(json_obj, "interface",
2831 itf ? itf->name : "-");
2832 json_object_string_addf(json_obj, "nexthop", "%pI4",
2833 &srl->nhlfe[0].nexthop);
2834 json_object_array_add(json_link, json_obj);
2835 /* Backup Link */
2836 json_obj = json_object_new_object();
2837 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2838 json_object_string_add(json_obj, "prefix", pref);
2839 json_object_int_add(json_obj, "sid", srl->sid[1]);
2840 json_object_int_add(json_obj, "inputLabel",
2841 srl->nhlfe[1].label_in);
2842 json_object_int_add(json_obj, "outputLabel",
2843 srl->nhlfe[1].label_out);
2844 json_object_string_add(json_obj, "interface",
2845 itf ? itf->name : "-");
2846 json_object_string_addf(json_obj, "nexthop", "%pI4",
2847 &srl->nhlfe[1].nexthop);
2848 json_object_array_add(json_link, json_obj);
2849 } else {
2850 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2851 pref, sid,
2852 sr_op2str(op, 32, srl->nhlfe[0].label_in,
2853 srl->nhlfe[0].label_out),
2854 itf ? itf->name : "-",
2855 inet_ntop(AF_INET, &srl->nhlfe[0].nexthop,
2856 buf, sizeof(buf)));
2857 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2858 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2859 pref, sid,
2860 sr_op2str(op, 32, srl->nhlfe[1].label_in,
2861 srl->nhlfe[1].label_out),
2862 itf ? itf->name : "-",
2863 inet_ntop(AF_INET, &srl->nhlfe[1].nexthop,
2864 buf, sizeof(buf)));
2865 }
2866 }
2867 if (json)
2868 json_object_array_add(json, json_node);
2869 else
2870 vty_out(vty, "%s\n", sbuf_buf(&sbuf));
2871
2872 sbuf_free(&sbuf);
2873 }
2874
2875 static void show_vty_srdb(struct hash_bucket *bucket, void *args)
2876 {
2877 struct vty *vty = (struct vty *)args;
2878 struct sr_node *srn = (struct sr_node *)bucket->data;
2879
2880 show_sr_node(vty, NULL, srn);
2881 }
2882
2883 static void show_json_srdb(struct hash_bucket *bucket, void *args)
2884 {
2885 struct json_object *json = (struct json_object *)args;
2886 struct sr_node *srn = (struct sr_node *)bucket->data;
2887
2888 show_sr_node(NULL, json, srn);
2889 }
2890
2891 DEFUN (show_ip_opsf_srdb,
2892 show_ip_ospf_srdb_cmd,
2893 "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
2894 SHOW_STR
2895 IP_STR
2896 OSPF_STR
2897 "Database summary\n"
2898 "Show Segment Routing Data Base\n"
2899 "Advertising SR node\n"
2900 "Advertising SR node ID (as an IP address)\n"
2901 "Self-originated SR node\n"
2902 JSON_STR)
2903 {
2904 int idx = 0;
2905 struct in_addr rid;
2906 struct sr_node *srn;
2907 bool uj = use_json(argc, argv);
2908 json_object *json = NULL, *json_node_array = NULL;
2909
2910 if (OspfSR.status == SR_OFF) {
2911 vty_out(vty, "Segment Routing is disabled on this router\n");
2912 return CMD_WARNING;
2913 }
2914
2915 if (uj) {
2916 json = json_object_new_object();
2917 json_node_array = json_object_new_array();
2918 json_object_string_addf(json, "srdbID", "%pI4",
2919 &OspfSR.self->adv_router);
2920 json_object_object_add(json, "srNodes", json_node_array);
2921 } else {
2922 vty_out(vty,
2923 "\n\t\tOSPF Segment Routing database for ID %pI4\n\n",
2924 &OspfSR.self->adv_router);
2925 }
2926
2927 if (argv_find(argv, argc, "self-originate", &idx)) {
2928 srn = OspfSR.self;
2929 show_sr_node(vty, json_node_array, srn);
2930 if (uj)
2931 vty_json(vty, json);
2932 return CMD_SUCCESS;
2933 }
2934
2935 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
2936 if (!inet_aton(argv[idx]->arg, &rid)) {
2937 vty_out(vty, "Specified Router ID %s is invalid\n",
2938 argv[idx]->arg);
2939 return CMD_WARNING_CONFIG_FAILED;
2940 }
2941 /* Get the SR Node from the SRDB */
2942 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
2943 (void *)&rid);
2944 show_sr_node(vty, json_node_array, srn);
2945 if (uj)
2946 vty_json(vty, json);
2947 return CMD_SUCCESS;
2948 }
2949
2950 /* No parameters have been provided, Iterate through all the SRDB */
2951 if (uj) {
2952 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
2953 void *))show_json_srdb,
2954 (void *)json_node_array);
2955 vty_json(vty, json);
2956 } else {
2957 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
2958 void *))show_vty_srdb,
2959 (void *)vty);
2960 }
2961 return CMD_SUCCESS;
2962 }
2963
2964 /* Install new CLI commands */
2965 void ospf_sr_register_vty(void)
2966 {
2967 install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
2968
2969 install_element(OSPF_NODE, &ospf_sr_enable_cmd);
2970 install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
2971 install_element(OSPF_NODE, &sr_global_label_range_cmd);
2972 install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
2973 install_element(OSPF_NODE, &sr_node_msd_cmd);
2974 install_element(OSPF_NODE, &no_sr_node_msd_cmd);
2975 install_element(OSPF_NODE, &sr_prefix_sid_cmd);
2976 install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
2977 }