]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_sr.c
Merge pull request #11328 from opensourcerouting/fix/drop_label_pton_ntop
[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 DEFUN (sr_node_msd,
2306 sr_node_msd_cmd,
2307 "segment-routing node-msd (1-16)",
2308 SR_STR
2309 "Maximum Stack Depth for this router\n"
2310 "Maximum number of label that could be stack (1-16)\n")
2311 {
2312 uint32_t msd;
2313 int idx = 1;
2314
2315 if (!ospf_sr_enabled(vty))
2316 return CMD_WARNING_CONFIG_FAILED;
2317
2318 /* Get MSD */
2319 argv_find(argv, argc, "(1-16)", &idx);
2320 msd = strtoul(argv[idx]->arg, NULL, 10);
2321 if (msd < 1 || msd > MPLS_MAX_LABELS) {
2322 vty_out(vty, "MSD must be comprise between 1 and %u\n",
2323 MPLS_MAX_LABELS);
2324 return CMD_WARNING_CONFIG_FAILED;
2325 }
2326
2327 /* Check if value has changed */
2328 if (OspfSR.msd == msd)
2329 return CMD_SUCCESS;
2330
2331 /* Set this router MSD */
2332 OspfSR.msd = msd;
2333 if (OspfSR.self != NULL) {
2334 OspfSR.self->msd = msd;
2335
2336 /* Set Router Information parameters if SR is UP */
2337 if (OspfSR.status == SR_UP)
2338 ospf_router_info_update_sr(true, OspfSR.self);
2339 }
2340
2341 return CMD_SUCCESS;
2342 }
2343
2344 DEFUN (no_sr_node_msd,
2345 no_sr_node_msd_cmd,
2346 "no segment-routing node-msd [(1-16)]",
2347 NO_STR
2348 SR_STR
2349 "Maximum Stack Depth for this router\n"
2350 "Maximum number of label that could be stack (1-16)\n")
2351 {
2352
2353 if (!ospf_sr_enabled(vty))
2354 return CMD_WARNING_CONFIG_FAILED;
2355
2356 /* unset this router MSD */
2357 OspfSR.msd = 0;
2358 if (OspfSR.self != NULL) {
2359 OspfSR.self->msd = 0;
2360
2361 /* Set Router Information parameters if SR is UP */
2362 if (OspfSR.status == SR_UP)
2363 ospf_router_info_update_sr(true, OspfSR.self);
2364 }
2365
2366 return CMD_SUCCESS;
2367 }
2368
2369 DEFUN (sr_prefix_sid,
2370 sr_prefix_sid_cmd,
2371 "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
2372 SR_STR
2373 "Prefix SID\n"
2374 "IPv4 Prefix as A.B.C.D/M\n"
2375 "SID index for this prefix in decimal (0-65535)\n"
2376 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2377 "Don't request Penultimate Hop Popping (PHP)\n"
2378 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2379 {
2380 int idx = 0;
2381 struct prefix p, pexist;
2382 uint32_t index;
2383 struct listnode *node;
2384 struct sr_prefix *srp, *exist = NULL;
2385 struct interface *ifp;
2386 bool no_php_flag = false;
2387 bool exp_null = false;
2388 bool index_in_use = false;
2389 uint8_t desired_flags = 0;
2390
2391 if (!ospf_sr_enabled(vty))
2392 return CMD_WARNING_CONFIG_FAILED;
2393
2394 /* Get network prefix */
2395 argv_find(argv, argc, "A.B.C.D/M", &idx);
2396 if (!str2prefix(argv[idx]->arg, &p)) {
2397 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2398 return CMD_WARNING_CONFIG_FAILED;
2399 }
2400
2401 /* Get & verify index value */
2402 argv_find(argv, argc, "(0-65535)", &idx);
2403 index = strtoul(argv[idx]->arg, NULL, 10);
2404 if (index > OspfSR.srgb.size - 1) {
2405 vty_out(vty, "Index %u must be lower than range size %u\n",
2406 index, OspfSR.srgb.size);
2407 return CMD_WARNING_CONFIG_FAILED;
2408 }
2409
2410 /* Get options */
2411 no_php_flag = argv_find(argv, argc, "no-php-flag", &idx);
2412 exp_null = argv_find(argv, argc, "explicit-null", &idx);
2413
2414 desired_flags |= no_php_flag ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2415 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0;
2416 desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_EFLG : 0;
2417
2418 /* Search for an existing Prefix-SID */
2419 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2420 if (prefix_same((struct prefix *)&srp->prefv4, &p))
2421 exist = srp;
2422 if (srp->sid == index) {
2423 index_in_use = true;
2424 pexist = p;
2425 }
2426 }
2427
2428 /* done if prefix segment already there with same index and flags */
2429 if (exist && exist->sid == index && exist->flags == desired_flags)
2430 return CMD_SUCCESS;
2431
2432 /* deny if index is already in use by a distinct prefix */
2433 if (!exist && index_in_use) {
2434 vty_out(vty, "Index %u is already used by %pFX\n", index,
2435 &pexist);
2436 return CMD_WARNING_CONFIG_FAILED;
2437 }
2438
2439 /* First, remove old NHLFE if installed */
2440 if (exist && CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2441 && !CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2442 ospf_zebra_delete_prefix_sid(exist);
2443
2444 /* Create new Extended Prefix to SRDB if not found */
2445 if (exist == NULL) {
2446 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
2447 IPV4_ADDR_COPY(&srp->prefv4.prefix, &p.u.prefix4);
2448 srp->prefv4.prefixlen = p.prefixlen;
2449 srp->prefv4.family = p.family;
2450 srp->sid = index;
2451 srp->type = LOCAL_SID;
2452 } else {
2453 /* we work on the existing SR prefix */
2454 srp = exist;
2455 }
2456
2457 /* Reset labels to handle flag update */
2458 srp->label_in = 0;
2459 srp->nhlfe.label_out = 0;
2460 srp->sid = index;
2461 srp->flags = desired_flags;
2462
2463 /* If NO PHP flag is present, compute NHLFE and set label */
2464 if (no_php_flag) {
2465 srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
2466 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
2467 }
2468
2469 osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
2470 (struct prefix *)&srp->prefv4);
2471
2472 /* Get Interface and check if it is a Loopback */
2473 ifp = if_lookup_prefix(&p, VRF_DEFAULT);
2474 if (ifp == NULL) {
2475 /*
2476 * Interface could be not yet available i.e. when this
2477 * command is in the configuration file, OSPF is not yet
2478 * ready. In this case, store the prefix SID for latter
2479 * update of this Extended Prefix
2480 */
2481 if (exist == NULL)
2482 listnode_add(OspfSR.self->ext_prefix, srp);
2483 zlog_info(
2484 "Interface for prefix %pFX not found. Deferred LSA flooding",
2485 &p);
2486 return CMD_SUCCESS;
2487 }
2488
2489 if (!if_is_loopback(ifp)) {
2490 vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
2491 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2492 return CMD_WARNING_CONFIG_FAILED;
2493 }
2494 srp->nhlfe.ifindex = ifp->ifindex;
2495
2496 /* Add SR Prefix if new */
2497 if (!exist)
2498 listnode_add(OspfSR.self->ext_prefix, srp);
2499
2500 /* Update Prefix SID if SR is UP */
2501 if (OspfSR.status == SR_UP) {
2502 if (no_php_flag && !exp_null)
2503 ospf_zebra_update_prefix_sid(srp);
2504 } else
2505 return CMD_SUCCESS;
2506
2507 /* Finally, update Extended Prefix LSA id SR is UP */
2508 srp->instance = ospf_ext_schedule_prefix_index(
2509 ifp, srp->sid, &srp->prefv4, srp->flags);
2510 if (srp->instance == 0) {
2511 vty_out(vty, "Unable to set index %u for prefix %pFX\n",
2512 index, &p);
2513 return CMD_WARNING;
2514 }
2515
2516 return CMD_SUCCESS;
2517 }
2518
2519 DEFUN (no_sr_prefix_sid,
2520 no_sr_prefix_sid_cmd,
2521 "no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
2522 NO_STR
2523 SR_STR
2524 "Prefix SID\n"
2525 "IPv4 Prefix as A.B.C.D/M\n"
2526 "SID index for this prefix in decimal (0-65535)\n"
2527 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2528 "Don't request Penultimate Hop Popping (PHP)\n"
2529 "Upstream neighbor must replace prefix-sid with explicit null label\n")
2530 {
2531 int idx = 0;
2532 struct prefix p;
2533 struct listnode *node;
2534 struct sr_prefix *srp;
2535 struct interface *ifp;
2536 bool found = false;
2537 int rc;
2538
2539 if (!ospf_sr_enabled(vty))
2540 return CMD_WARNING_CONFIG_FAILED;
2541
2542 if (OspfSR.status != SR_UP)
2543 return CMD_SUCCESS;
2544
2545 /* Get network prefix */
2546 argv_find(argv, argc, "A.B.C.D/M", &idx);
2547 rc = str2prefix(argv[idx]->arg, &p);
2548 if (!rc) {
2549 vty_out(vty, "Invalid prefix format %s\n", argv[idx]->arg);
2550 return CMD_WARNING_CONFIG_FAILED;
2551 }
2552
2553 /* check that the prefix is already set */
2554 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
2555 if (IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
2556 && (srp->prefv4.prefixlen == p.prefixlen)) {
2557 found = true;
2558 break;
2559 }
2560
2561 if (!found) {
2562 vty_out(vty, "Prefix %s is not found. Abort!\n",
2563 argv[idx]->arg);
2564 return CMD_WARNING_CONFIG_FAILED;
2565 }
2566
2567 osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
2568 (struct prefix *)&srp->prefv4, srp->sid);
2569
2570 /* Get Interface */
2571 ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2572 if (ifp == NULL) {
2573 vty_out(vty, "interface for prefix %s not found.\n",
2574 argv[idx]->arg);
2575 /* silently remove from list */
2576 listnode_delete(OspfSR.self->ext_prefix, srp);
2577 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2578 return CMD_SUCCESS;
2579 }
2580
2581 /* Update Extended Prefix LSA */
2582 if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
2583 vty_out(vty, "No corresponding loopback interface. Abort!\n");
2584 return CMD_WARNING;
2585 }
2586
2587 /* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
2588 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
2589 && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
2590 ospf_zebra_delete_prefix_sid(srp);
2591
2592 /* OK, all is clean, remove SRP from SRDB */
2593 listnode_delete(OspfSR.self->ext_prefix, srp);
2594 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2595
2596 return CMD_SUCCESS;
2597 }
2598
2599
2600 static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
2601 mpls_label_t label_out)
2602 {
2603 if (size < 24)
2604 return NULL;
2605
2606 switch (label_out) {
2607 case MPLS_LABEL_IMPLICIT_NULL:
2608 snprintf(buf, size, "Pop(%u)", label_in);
2609 break;
2610 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
2611 if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
2612 snprintf(buf, size, "no-op.");
2613 else
2614 snprintf(buf, size, "Swap(%u, null)", label_in);
2615 break;
2616 case MPLS_INVALID_LABEL:
2617 snprintf(buf, size, "no-op.");
2618 break;
2619 default:
2620 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
2621 break;
2622 }
2623 return buf;
2624 }
2625
2626 static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json,
2627 struct sr_prefix *srp)
2628 {
2629
2630 struct listnode *node;
2631 struct ospf_path *path;
2632 struct interface *itf;
2633 json_object *json_route = NULL, *json_obj;
2634 char pref[19];
2635 char sid[22];
2636 char op[32];
2637 char buf[PREFIX_STRLEN];
2638 int indent = 0;
2639
2640 snprintfrr(pref, 19, "%pFX", (struct prefix *)&srp->prefv4);
2641 snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
2642 if (json) {
2643 json_object_string_add(json, "prefix", pref);
2644 json_object_int_add(json, "sid", srp->sid);
2645 json_object_int_add(json, "inputLabel", srp->label_in);
2646 } else {
2647 sbuf_push(sbuf, 0, "%18s %21s ", pref, sid);
2648 }
2649
2650 /* Check if it is a Local Node SID */
2651 if (srp->type == LOCAL_SID) {
2652 itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
2653 if (json) {
2654 if (!json_route) {
2655 json_route = json_object_new_array();
2656 json_object_object_add(json, "prefixRoute",
2657 json_route);
2658 }
2659 json_obj = json_object_new_object();
2660 json_object_int_add(json_obj, "outputLabel",
2661 srp->nhlfe.label_out);
2662 json_object_string_add(json_obj, "interface",
2663 itf ? itf->name : "-");
2664 json_object_string_addf(json_obj, "nexthop", "%pI4",
2665 &srp->nhlfe.nexthop);
2666 json_object_array_add(json_route, json_obj);
2667 } else {
2668 sbuf_push(sbuf, 0, "%20s %9s %15s\n",
2669 sr_op2str(op, 32, srp->label_in,
2670 srp->nhlfe.label_out),
2671 itf ? itf->name : "-",
2672 inet_ntop(AF_INET, &srp->nhlfe.nexthop,
2673 buf, sizeof(buf)));
2674 }
2675 return;
2676 }
2677
2678 /* Check if we have a valid path for this prefix */
2679 if (srp->route == NULL) {
2680 if (!json) {
2681 sbuf_push(sbuf, 0, "\n");
2682 }
2683 return;
2684 }
2685
2686 /* Process list of OSPF paths */
2687 for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
2688 itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT);
2689 if (json) {
2690 if (!json_route) {
2691 json_route = json_object_new_array();
2692 json_object_object_add(json, "prefixRoute",
2693 json_route);
2694 }
2695 json_obj = json_object_new_object();
2696 json_object_int_add(json_obj, "outputLabel",
2697 path->srni.label_out);
2698 json_object_string_add(json_obj, "interface",
2699 itf ? itf->name : "-");
2700 json_object_string_addf(json_obj, "nexthop", "%pI4",
2701 &path->nexthop);
2702 json_object_array_add(json_route, json_obj);
2703 } else {
2704 sbuf_push(sbuf, indent, "%20s %9s %15s\n",
2705 sr_op2str(op, 32, srp->label_in,
2706 path->srni.label_out),
2707 itf ? itf->name : "-",
2708 inet_ntop(AF_INET, &path->nexthop, buf,
2709 sizeof(buf)));
2710 /* Offset to align information for ECMP */
2711 indent = 43;
2712 }
2713 }
2714 }
2715
2716 static void show_sr_node(struct vty *vty, struct json_object *json,
2717 struct sr_node *srn)
2718 {
2719
2720 struct listnode *node;
2721 struct sr_link *srl;
2722 struct sr_prefix *srp;
2723 struct interface *itf;
2724 struct sbuf sbuf;
2725 char pref[19];
2726 char sid[22];
2727 char op[32];
2728 char buf[PREFIX_STRLEN];
2729 uint32_t upper;
2730 json_object *json_node = NULL, *json_algo, *json_obj;
2731 json_object *json_prefix = NULL, *json_link = NULL;
2732
2733 /* Sanity Check */
2734 if (srn == NULL)
2735 return;
2736
2737 sbuf_init(&sbuf, NULL, 0);
2738
2739 if (json) {
2740 json_node = json_object_new_object();
2741 json_object_string_addf(json_node, "routerID", "%pI4",
2742 &srn->adv_router);
2743 json_object_int_add(json_node, "srgbSize",
2744 srn->srgb.range_size);
2745 json_object_int_add(json_node, "srgbLabel",
2746 srn->srgb.lower_bound);
2747 json_object_int_add(json_node, "srlbSize",
2748 srn->srlb.range_size);
2749 json_object_int_add(json_node, "srlbLabel",
2750 srn->srlb.lower_bound);
2751 json_algo = json_object_new_array();
2752 json_object_object_add(json_node, "algorithms", json_algo);
2753 for (int i = 0; i < ALGORITHM_COUNT; i++) {
2754 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2755 continue;
2756 json_obj = json_object_new_object();
2757 char tmp[2];
2758
2759 snprintf(tmp, sizeof(tmp), "%u", i);
2760 json_object_string_add(json_obj, tmp,
2761 srn->algo[i] == SR_ALGORITHM_SPF
2762 ? "SPF"
2763 : "S-SPF");
2764 json_object_array_add(json_algo, json_obj);
2765 }
2766 if (srn->msd != 0)
2767 json_object_int_add(json_node, "nodeMsd", srn->msd);
2768 } else {
2769 sbuf_push(&sbuf, 0, "SR-Node: %pI4", &srn->adv_router);
2770 upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
2771 sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
2772 srn->srgb.lower_bound, upper);
2773 upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
2774 sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
2775 srn->srlb.lower_bound, upper);
2776 sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
2777 srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
2778 for (int i = 1; i < ALGORITHM_COUNT; i++) {
2779 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2780 continue;
2781 sbuf_push(&sbuf, 0, "/%s",
2782 srn->algo[i] == SR_ALGORITHM_SPF ? "SPF"
2783 : "S-SPF");
2784 }
2785 if (srn->msd != 0)
2786 sbuf_push(&sbuf, 0, "\tMSD: %u", srn->msd);
2787 }
2788
2789 if (!json) {
2790 sbuf_push(&sbuf, 0,
2791 "\n\n Prefix or Link Node or Adj. SID Label Operation Interface Nexthop\n");
2792 sbuf_push(&sbuf, 0,
2793 "------------------ --------------------- -------------------- --------- ---------------\n");
2794 }
2795 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
2796 if (json) {
2797 if (!json_prefix) {
2798 json_prefix = json_object_new_array();
2799 json_object_object_add(json_node,
2800 "extendedPrefix",
2801 json_prefix);
2802 }
2803 json_obj = json_object_new_object();
2804 show_sr_prefix(NULL, json_obj, srp);
2805 json_object_array_add(json_prefix, json_obj);
2806 } else {
2807 show_sr_prefix(&sbuf, NULL, srp);
2808 }
2809 }
2810
2811 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
2812 snprintfrr(pref, 19, "%pI4/32", &srl->itf_addr);
2813 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
2814 itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
2815 if (json) {
2816 if (!json_link) {
2817 json_link = json_object_new_array();
2818 json_object_object_add(
2819 json_node, "extendedLink", json_link);
2820 }
2821 /* Primary Link */
2822 json_obj = json_object_new_object();
2823 json_object_string_add(json_obj, "prefix", pref);
2824 json_object_int_add(json_obj, "sid", srl->sid[0]);
2825 json_object_int_add(json_obj, "inputLabel",
2826 srl->nhlfe[0].label_in);
2827 json_object_int_add(json_obj, "outputLabel",
2828 srl->nhlfe[0].label_out);
2829 json_object_string_add(json_obj, "interface",
2830 itf ? itf->name : "-");
2831 json_object_string_addf(json_obj, "nexthop", "%pI4",
2832 &srl->nhlfe[0].nexthop);
2833 json_object_array_add(json_link, json_obj);
2834 /* Backup Link */
2835 json_obj = json_object_new_object();
2836 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2837 json_object_string_add(json_obj, "prefix", pref);
2838 json_object_int_add(json_obj, "sid", srl->sid[1]);
2839 json_object_int_add(json_obj, "inputLabel",
2840 srl->nhlfe[1].label_in);
2841 json_object_int_add(json_obj, "outputLabel",
2842 srl->nhlfe[1].label_out);
2843 json_object_string_add(json_obj, "interface",
2844 itf ? itf->name : "-");
2845 json_object_string_addf(json_obj, "nexthop", "%pI4",
2846 &srl->nhlfe[1].nexthop);
2847 json_object_array_add(json_link, json_obj);
2848 } else {
2849 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2850 pref, sid,
2851 sr_op2str(op, 32, srl->nhlfe[0].label_in,
2852 srl->nhlfe[0].label_out),
2853 itf ? itf->name : "-",
2854 inet_ntop(AF_INET, &srl->nhlfe[0].nexthop,
2855 buf, sizeof(buf)));
2856 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
2857 sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n",
2858 pref, sid,
2859 sr_op2str(op, 32, srl->nhlfe[1].label_in,
2860 srl->nhlfe[1].label_out),
2861 itf ? itf->name : "-",
2862 inet_ntop(AF_INET, &srl->nhlfe[1].nexthop,
2863 buf, sizeof(buf)));
2864 }
2865 }
2866 if (json)
2867 json_object_array_add(json, json_node);
2868 else
2869 vty_out(vty, "%s\n", sbuf_buf(&sbuf));
2870
2871 sbuf_free(&sbuf);
2872 }
2873
2874 static void show_vty_srdb(struct hash_bucket *bucket, void *args)
2875 {
2876 struct vty *vty = (struct vty *)args;
2877 struct sr_node *srn = (struct sr_node *)bucket->data;
2878
2879 show_sr_node(vty, NULL, srn);
2880 }
2881
2882 static void show_json_srdb(struct hash_bucket *bucket, void *args)
2883 {
2884 struct json_object *json = (struct json_object *)args;
2885 struct sr_node *srn = (struct sr_node *)bucket->data;
2886
2887 show_sr_node(NULL, json, srn);
2888 }
2889
2890 DEFUN (show_ip_opsf_srdb,
2891 show_ip_ospf_srdb_cmd,
2892 "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
2893 SHOW_STR
2894 IP_STR
2895 OSPF_STR
2896 "Database summary\n"
2897 "Show Segment Routing Data Base\n"
2898 "Advertising SR node\n"
2899 "Advertising SR node ID (as an IP address)\n"
2900 "Self-originated SR node\n"
2901 JSON_STR)
2902 {
2903 int idx = 0;
2904 struct in_addr rid;
2905 struct sr_node *srn;
2906 bool uj = use_json(argc, argv);
2907 json_object *json = NULL, *json_node_array = NULL;
2908
2909 if (OspfSR.status == SR_OFF) {
2910 vty_out(vty, "Segment Routing is disabled on this router\n");
2911 return CMD_WARNING;
2912 }
2913
2914 if (uj) {
2915 json = json_object_new_object();
2916 json_node_array = json_object_new_array();
2917 json_object_string_addf(json, "srdbID", "%pI4",
2918 &OspfSR.self->adv_router);
2919 json_object_object_add(json, "srNodes", json_node_array);
2920 } else {
2921 vty_out(vty,
2922 "\n\t\tOSPF Segment Routing database for ID %pI4\n\n",
2923 &OspfSR.self->adv_router);
2924 }
2925
2926 if (argv_find(argv, argc, "self-originate", &idx)) {
2927 srn = OspfSR.self;
2928 show_sr_node(vty, json_node_array, srn);
2929 if (uj)
2930 vty_json(vty, json);
2931 return CMD_SUCCESS;
2932 }
2933
2934 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
2935 if (!inet_aton(argv[idx]->arg, &rid)) {
2936 vty_out(vty, "Specified Router ID %s is invalid\n",
2937 argv[idx]->arg);
2938 return CMD_WARNING_CONFIG_FAILED;
2939 }
2940 /* Get the SR Node from the SRDB */
2941 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
2942 (void *)&rid);
2943 show_sr_node(vty, json_node_array, srn);
2944 if (uj)
2945 vty_json(vty, json);
2946 return CMD_SUCCESS;
2947 }
2948
2949 /* No parameters have been provided, Iterate through all the SRDB */
2950 if (uj) {
2951 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
2952 void *))show_json_srdb,
2953 (void *)json_node_array);
2954 vty_json(vty, json);
2955 } else {
2956 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *,
2957 void *))show_vty_srdb,
2958 (void *)vty);
2959 }
2960 return CMD_SUCCESS;
2961 }
2962
2963 /* Install new CLI commands */
2964 void ospf_sr_register_vty(void)
2965 {
2966 install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
2967
2968 install_element(OSPF_NODE, &ospf_sr_enable_cmd);
2969 install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
2970 install_element(OSPF_NODE, &sr_global_label_range_cmd);
2971 install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
2972 install_element(OSPF_NODE, &sr_node_msd_cmd);
2973 install_element(OSPF_NODE, &no_sr_node_msd_cmd);
2974 install_element(OSPF_NODE, &sr_prefix_sid_cmd);
2975 install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
2976 }