2 * This is an implementation of Segment Routing for IS-IS as per RFC 8667
4 * Copyright (C) 2019 Orange http://www.orange.com
6 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
7 * Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "termtable.h"
36 #include "lib/lib_errors.h"
38 #include "isisd/isisd.h"
39 #include "isisd/isis_spf.h"
40 #include "isisd/isis_spf_private.h"
41 #include "isisd/isis_adjacency.h"
42 #include "isisd/isis_route.h"
43 #include "isisd/isis_mt.h"
44 #include "isisd/isis_sr.h"
45 #include "isisd/isis_tlvs.h"
46 #include "isisd/isis_misc.h"
47 #include "isisd/isis_zebra.h"
48 #include "isisd/isis_errors.h"
50 /* Local variables and functions */
51 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SR_INFO
, "ISIS segment routing information")
53 static void sr_prefix_uninstall(struct sr_prefix
*srp
);
54 static void sr_prefix_reinstall(struct sr_prefix
*srp
, bool make_before_break
);
55 static void sr_local_block_delete(struct isis_area
*area
);
56 static int sr_local_block_init(struct isis_area
*area
);
57 static void sr_adj_sid_update(struct sr_adjacency
*sra
,
58 struct sr_local_block
*srlb
);
59 static void sr_adj_sid_del(struct sr_adjacency
*sra
);
61 /* --- RB-Tree Management functions ----------------------------------------- */
64 * SR Prefix comparison for RB-Tree.
66 * @param a First SR prefix
67 * @param b Second SR prefix
69 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
71 static inline int sr_prefix_sid_compare(const struct sr_prefix
*a
,
72 const struct sr_prefix
*b
)
74 return prefix_cmp(&a
->prefix
, &b
->prefix
);
76 DECLARE_RBTREE_UNIQ(srdb_node_prefix
, struct sr_prefix
, node_entry
,
77 sr_prefix_sid_compare
)
78 DECLARE_RBTREE_UNIQ(srdb_area_prefix
, struct sr_prefix
, area_entry
,
79 sr_prefix_sid_compare
)
82 * Configured SR Prefix comparison for RB-Tree.
84 * @param a First SR prefix
85 * @param b Second SR prefix
87 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
89 static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg
*a
,
90 const struct sr_prefix_cfg
*b
)
92 return prefix_cmp(&a
->prefix
, &b
->prefix
);
94 DECLARE_RBTREE_UNIQ(srdb_prefix_cfg
, struct sr_prefix_cfg
, entry
,
95 sr_prefix_sid_cfg_compare
)
98 * SR Node comparison for RB-Tree.
100 * @param a First SR node
101 * @param b Second SR node
103 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
105 static inline int sr_node_compare(const struct sr_node
*a
,
106 const struct sr_node
*b
)
108 return memcmp(a
->sysid
, b
->sysid
, ISIS_SYS_ID_LEN
);
110 DECLARE_RBTREE_UNIQ(srdb_node
, struct sr_node
, entry
, sr_node_compare
)
112 /* --- Functions used for Yang model and CLI to configure Segment Routing --- */
115 * Check if prefix correspond to a Node SID.
117 * @param ifp Interface
118 * @param prefix Prefix to be checked
120 * @return True if the interface/address pair corresponds to a Node-SID
122 static bool sr_prefix_is_node_sid(const struct interface
*ifp
,
123 const struct prefix
*prefix
)
125 return (if_is_loopback(ifp
) && is_host_route(prefix
));
129 * Update local SRGB configuration. SRGB is reserved though Label Manager.
130 * This function trigger the update of local Prefix-SID installation.
132 * @param area IS-IS area
133 * @param lower_bound Lower bound of SRGB
134 * @param upper_bound Upper bound of SRGB
136 * @return 0 on success, -1 otherwise
138 int isis_sr_cfg_srgb_update(struct isis_area
*area
, uint32_t lower_bound
,
139 uint32_t upper_bound
)
141 struct isis_sr_db
*srdb
= &area
->srdb
;
143 sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
144 area
->area_tag
, lower_bound
, upper_bound
);
146 /* Just store new SRGB values if Label Manager is not available.
147 * SRGB will be configured later when SR start */
148 if (!isis_zebra_label_manager_ready()) {
149 srdb
->config
.srgb_lower_bound
= lower_bound
;
150 srdb
->config
.srgb_upper_bound
= upper_bound
;
154 /* Label Manager is ready, start by releasing the old SRGB. */
155 if (srdb
->srgb_active
) {
156 isis_zebra_release_label_range(srdb
->config
.srgb_lower_bound
,
157 srdb
->config
.srgb_upper_bound
);
158 srdb
->srgb_active
= false;
161 srdb
->config
.srgb_lower_bound
= lower_bound
;
162 srdb
->config
.srgb_upper_bound
= upper_bound
;
165 struct sr_prefix
*srp
;
167 /* then request new SRGB if SR is enabled. */
168 if (isis_zebra_request_label_range(
169 srdb
->config
.srgb_lower_bound
,
170 srdb
->config
.srgb_upper_bound
171 - srdb
->config
.srgb_lower_bound
+ 1) < 0) {
172 srdb
->srgb_active
= false;
175 srdb
->srgb_active
= true;
178 sr_debug(" |- Got new SRGB [%u/%u]",
179 srdb
->config
.srgb_lower_bound
,
180 srdb
->config
.srgb_upper_bound
);
182 /* Reinstall local Prefix-SIDs to update their input labels. */
183 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
184 frr_each (srdb_area_prefix
,
185 &area
->srdb
.prefix_sids
[level
- 1], srp
) {
186 sr_prefix_reinstall(srp
, false);
190 lsp_regenerate_schedule(area
, area
->is_type
, 0);
191 } else if (srdb
->config
.enabled
) {
192 /* Try to enable SR again using the new SRGB. */
200 * Update Segment Routing Local Block range which is reserved though the
201 * Label Manager. This function trigger the update of local Adjacency-SID
204 * @param area IS-IS area
205 * @param lower_bound Lower bound of SRLB
206 * @param upper_bound Upper bound of SRLB
208 * @return 0 on success, -1 otherwise
210 int isis_sr_cfg_srlb_update(struct isis_area
*area
, uint32_t lower_bound
,
211 uint32_t upper_bound
)
213 struct isis_sr_db
*srdb
= &area
->srdb
;
214 struct listnode
*node
;
215 struct sr_adjacency
*sra
;
217 sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
218 area
->area_tag
, lower_bound
, upper_bound
);
220 /* Just store new SRLB values if Label Manager is not available.
221 * SRLB will be configured later when SR start */
222 if (!isis_zebra_label_manager_ready()) {
223 srdb
->config
.srlb_lower_bound
= lower_bound
;
224 srdb
->config
.srlb_upper_bound
= upper_bound
;
228 /* LM is ready, start by deleting the old SRLB */
229 sr_local_block_delete(area
);
231 srdb
->config
.srlb_lower_bound
= lower_bound
;
232 srdb
->config
.srlb_upper_bound
= upper_bound
;
235 /* Initialize new SRLB */
236 if (sr_local_block_init(area
) != 0)
239 /* Reinstall local Adjacency-SIDs with new labels. */
240 for (ALL_LIST_ELEMENTS_RO(area
->srdb
.adj_sids
, node
, sra
))
241 sr_adj_sid_update(sra
, &srdb
->srlb
);
243 /* Update and Flood LSP */
244 lsp_regenerate_schedule(area
, area
->is_type
, 0);
245 } else if (srdb
->config
.enabled
) {
246 /* Try to enable SR again using the new SRLB. */
254 * Add new Prefix-SID configuration to the SRDB.
256 * @param area IS-IS area
257 * @param prefix Prefix to be added
259 * @return Newly added Prefix-SID configuration structure
261 struct sr_prefix_cfg
*isis_sr_cfg_prefix_add(struct isis_area
*area
,
262 const struct prefix
*prefix
)
264 struct sr_prefix_cfg
*pcfg
;
265 struct interface
*ifp
;
267 sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area
->area_tag
, prefix
);
269 pcfg
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*pcfg
));
270 pcfg
->prefix
= *prefix
;
273 /* Pull defaults from the YANG module. */
274 pcfg
->sid_type
= yang_get_default_enum(
275 "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR
);
276 pcfg
->last_hop_behavior
= yang_get_default_enum(
277 "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR
);
279 /* Set the N-flag when appropriate. */
280 ifp
= if_lookup_prefix(prefix
, VRF_DEFAULT
);
281 if (ifp
&& sr_prefix_is_node_sid(ifp
, prefix
))
282 pcfg
->node_sid
= true;
284 /* Save prefix-sid configuration. */
285 srdb_prefix_cfg_add(&area
->srdb
.config
.prefix_sids
, pcfg
);
291 * Removal of locally configured Prefix-SID.
293 * @param pcfg Configured Prefix-SID
295 void isis_sr_cfg_prefix_del(struct sr_prefix_cfg
*pcfg
)
297 struct isis_area
*area
= pcfg
->area
;
299 sr_debug("ISIS-Sr (%s): Delete local Prefix-SID %pFX %s %u",
300 area
->area_tag
, &pcfg
->prefix
,
301 pcfg
->sid_type
== SR_SID_VALUE_TYPE_INDEX
? "index" : "label",
304 srdb_prefix_cfg_del(&area
->srdb
.config
.prefix_sids
, pcfg
);
305 XFREE(MTYPE_ISIS_SR_INFO
, pcfg
);
309 * Lookup for Prefix-SID in the local configuration.
311 * @param area IS-IS area
312 * @param prefix Prefix to lookup
314 * @return Configured Prefix-SID structure if found, NULL otherwise
316 struct sr_prefix_cfg
*isis_sr_cfg_prefix_find(struct isis_area
*area
,
317 union prefixconstptr prefix
)
319 struct sr_prefix_cfg pcfg
= {};
321 prefix_copy(&pcfg
.prefix
, prefix
.p
);
322 return srdb_prefix_cfg_find(&area
->srdb
.config
.prefix_sids
, &pcfg
);
326 * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
328 * @param pcfg Prefix-SID configuration
329 * @param external False if prefix is locally configured, true otherwise
330 * @param psid Prefix-SID sub-TLV to be updated
332 void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg
*pcfg
, bool external
,
333 struct isis_prefix_sid
*psid
)
335 /* Set SID algorithm. */
336 psid
->algorithm
= SR_ALGORITHM_SPF
;
340 switch (pcfg
->last_hop_behavior
) {
341 case SR_LAST_HOP_BEHAVIOR_EXP_NULL
:
342 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
343 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
345 case SR_LAST_HOP_BEHAVIOR_NO_PHP
:
346 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
347 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
349 case SR_LAST_HOP_BEHAVIOR_PHP
:
350 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
351 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
355 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_READVERTISED
);
357 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NODE
);
360 psid
->value
= pcfg
->sid
;
361 if (pcfg
->sid_type
== SR_SID_VALUE_TYPE_ABSOLUTE
) {
362 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_VALUE
);
363 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_LOCAL
);
367 /* --- Segment Routing Prefix Management functions -------------------------- */
370 * Add Segment Routing Prefix to a given Segment Routing Node.
372 * @param area IS-IS area
373 * @param srn Segment Routing Node
374 * @param prefix Prefix to be added
375 * @param local True if prefix is locally configured, false otherwise
376 * @param psid Prefix-SID sub-TLVs
378 * @return New Segment Routing Prefix structure
380 static struct sr_prefix
*sr_prefix_add(struct isis_area
*area
,
382 union prefixconstptr prefix
, bool local
,
383 const struct isis_prefix_sid
*psid
)
385 struct sr_prefix
*srp
;
387 srp
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*srp
));
388 prefix_copy(&srp
->prefix
, prefix
.p
);
390 srp
->input_label
= MPLS_INVALID_LABEL
;
392 srp
->type
= ISIS_SR_PREFIX_LOCAL
;
393 isis_sr_nexthop_reset(&srp
->u
.local
.info
);
395 srp
->type
= ISIS_SR_PREFIX_REMOTE
;
396 srp
->u
.remote
.rinfo
= NULL
;
399 srdb_node_prefix_add(&srn
->prefix_sids
, srp
);
400 /* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
401 srdb_area_prefix_add(&area
->srdb
.prefix_sids
[srn
->level
- 1], srp
);
403 sr_debug(" |- Added new SR Prefix-SID %pFX %s %u to SR Node %s",
404 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
405 srp
->sid
.value
, sysid_print(srn
->sysid
));
411 * Remove given Segment Prefix from given Segment Routing Node.
412 * Prefix-SID is un-installed first.
414 * @param area IS-IS area
415 * @param srn Segment Routing Node
416 * @param srp Segment Routing Prefix
418 static void sr_prefix_del(struct isis_area
*area
, struct sr_node
*srn
,
419 struct sr_prefix
*srp
)
421 sr_debug(" |- Delete SR Prefix-SID %pFX %s %u to SR Node %s",
422 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
423 srp
->sid
.value
, sysid_print(srn
->sysid
));
425 sr_prefix_uninstall(srp
);
426 srdb_node_prefix_del(&srn
->prefix_sids
, srp
);
427 srdb_area_prefix_del(&area
->srdb
.prefix_sids
[srn
->level
- 1], srp
);
428 XFREE(MTYPE_ISIS_SR_INFO
, srp
);
432 * Find Segment Routing Prefix by Area.
434 * @param area IS-IS area
435 * @param level IS-IS level
436 * @param prefix Prefix to lookup
438 * @return Segment Routing Prefix structure if found, NULL otherwise
440 static struct sr_prefix
*sr_prefix_find_by_area(struct isis_area
*area
,
442 union prefixconstptr prefix
)
444 struct sr_prefix srp
= {};
446 prefix_copy(&srp
.prefix
, prefix
.p
);
447 return srdb_area_prefix_find(&area
->srdb
.prefix_sids
[level
- 1], &srp
);
451 * Find Segment Routing Prefix by Segment Routing Node.
453 * @param srn Segment Routing Node
454 * @param prefix Prefix to lookup
456 * @return Segment Routing Prefix structure if found, NULL otherwise
458 static struct sr_prefix
*sr_prefix_find_by_node(struct sr_node
*srn
,
459 union prefixconstptr prefix
)
461 struct sr_prefix srp
= {};
463 prefix_copy(&srp
.prefix
, prefix
.p
);
464 return srdb_node_prefix_find(&srn
->prefix_sids
, &srp
);
467 /* --- Segment Routing Node Management functions ---------------------------- */
470 * Add Segment Routing Node to the Segment Routing Data Base.
472 * @param area IS-IS area
473 * @param level IS-IS level
474 * @param sysid Node System ID
475 * @param cap Segment Routing Capability sub-TLVs
477 * @return New Segment Routing Node structure
479 static struct sr_node
*sr_node_add(struct isis_area
*area
, int level
,
480 const uint8_t *sysid
)
484 srn
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*srn
));
486 memcpy(srn
->sysid
, sysid
, ISIS_SYS_ID_LEN
);
488 srdb_node_prefix_init(&srn
->prefix_sids
);
489 srdb_node_add(&area
->srdb
.sr_nodes
[level
- 1], srn
);
491 sr_debug(" |- Added new SR Node %s", sysid_print(srn
->sysid
));
496 static void sr_node_del(struct isis_area
*area
, int level
, struct sr_node
*srn
)
498 * Remove Segment Routing Node from the Segment Routing Data Base.
499 * All Prefix-SID attached to this Segment Routing Node are removed first.
501 * @param area IS-IS area
502 * @param level IS-IS level
503 * @param srn Segment Routing Node to be deleted
507 sr_debug(" |- Delete SR Node %s", sysid_print(srn
->sysid
));
509 /* Remove and uninstall Prefix-SIDs. */
510 while (srdb_node_prefix_count(&srn
->prefix_sids
) > 0) {
511 struct sr_prefix
*srp
;
513 srp
= srdb_node_prefix_first(&srn
->prefix_sids
);
514 sr_prefix_del(area
, srn
, srp
);
517 srdb_node_del(&area
->srdb
.sr_nodes
[level
- 1], srn
);
518 XFREE(MTYPE_ISIS_SR_INFO
, srn
);
522 * Find Segment Routing Node in the Segment Routing Data Base per system ID.
524 * @param area IS-IS area
525 * @param level IS-IS level
526 * @param sysid Node System ID to lookup
528 * @return Segment Routing Node structure if found, NULL otherwise
530 static struct sr_node
*sr_node_find(struct isis_area
*area
, int level
,
531 const uint8_t *sysid
)
533 struct sr_node srn
= {};
535 memcpy(srn
.sysid
, sysid
, ISIS_SYS_ID_LEN
);
536 return srdb_node_find(&area
->srdb
.sr_nodes
[level
- 1], &srn
);
540 * Update Segment Routing Node following an SRGB update. This function
541 * is called when a neighbor SR Node has updated its SRGB.
543 * @param area IS-IS area
544 * @param level IS-IS level
545 * @param sysid Segment Routing Node system ID
547 static void sr_node_srgb_update(struct isis_area
*area
, int level
,
550 struct sr_prefix
*srp
;
552 sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
555 frr_each (srdb_area_prefix
, &area
->srdb
.prefix_sids
[level
- 1], srp
) {
556 struct listnode
*node
;
557 struct isis_nexthop
*nh
;
559 if (srp
->type
== ISIS_SR_PREFIX_LOCAL
)
562 if (srp
->u
.remote
.rinfo
== NULL
)
565 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
, node
,
567 if (memcmp(nh
->sysid
, sysid
, ISIS_SYS_ID_LEN
) != 0)
571 * The Prefix-SID input label hasn't changed. We could
572 * re-install all Prefix-SID with "Make Before Break"
573 * option. Zebra layer will update output label(s) by
574 * adding new entry before removing the old one(s).
576 sr_prefix_reinstall(srp
, true);
582 /* --- Segment Routing Nexthop information Management functions ------------- */
585 * Update Segment Routing Nexthop.
587 * @param srnh Segment Routing next hop
588 * @param label Output MPLS label
590 void isis_sr_nexthop_update(struct sr_nexthop_info
*srnh
, mpls_label_t label
)
593 if (srnh
->uptime
== 0)
594 srnh
->uptime
= time(NULL
);
598 * Reset Segment Routing Nexthop.
600 * @param srnh Segment Routing Nexthop
602 void isis_sr_nexthop_reset(struct sr_nexthop_info
*srnh
)
604 srnh
->label
= MPLS_INVALID_LABEL
;
608 /* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
611 * Lookup IS-IS route in the Shortest Path Tree.
613 * @param area IS-IS area
614 * @param tree_id Shortest Path Tree identifier
615 * @param srp Segment Routing Prefix to lookup
617 * @return Route Information for this prefix if found, NULL otherwise
619 static struct isis_route_info
*sr_prefix_lookup_route(struct isis_area
*area
,
620 enum spf_tree_id tree_id
,
621 struct sr_prefix
*srp
)
623 struct route_node
*rn
;
624 int level
= srp
->srn
->level
;
626 rn
= route_node_lookup(area
->spftree
[tree_id
][level
- 1]->route_table
,
629 route_unlock_node(rn
);
638 * Compute input label for the given Prefix-SID.
640 * @param srp Segment Routing Prefix
642 * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
644 static mpls_label_t
sr_prefix_in_label(const struct sr_prefix
*srp
)
646 const struct sr_node
*srn
= srp
->srn
;
647 struct isis_area
*area
= srn
->area
;
649 /* Return SID value as MPLS label if it is an Absolute SID */
650 if (CHECK_FLAG(srp
->sid
.flags
,
651 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
))
652 return srp
->sid
.value
;
654 /* Check that SID index falls inside the SRGB */
655 if (srp
->sid
.value
>= (area
->srdb
.config
.srgb_upper_bound
656 - area
->srdb
.config
.srgb_lower_bound
+ 1)) {
657 flog_warn(EC_ISIS_SID_OVERFLOW
,
658 "%s: SID index %u falls outside local SRGB range",
659 __func__
, srp
->sid
.value
);
660 return MPLS_INVALID_LABEL
;
663 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
664 return (area
->srdb
.config
.srgb_lower_bound
+ srp
->sid
.value
);
668 * Compute output label for the given Prefix-SID.
670 * @param srp Segment Routing Prefix
671 * @param srn_nexthop Segment Routing nexthop node
672 * @param sysid System ID of the SR node which advertised the Prefix-SID
674 * @return MPLS label or MPLS_INVALID_LABEL in case of error
676 static mpls_label_t
sr_prefix_out_label(const struct sr_prefix
*srp
,
677 const struct sr_node
*srn_nexthop
,
678 const uint8_t *sysid
)
680 const struct sr_node
*srn
= srp
->srn
;
682 /* Check if the nexthop SR Node is the last hop? */
683 if (memcmp(sysid
, srn
->sysid
, ISIS_SYS_ID_LEN
) == 0) {
684 /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
685 if (!CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_NO_PHP
))
686 return MPLS_LABEL_IMPLICIT_NULL
;
688 /* SR-Node requests Implicit NULL Label */
689 if (CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
)) {
690 if (srp
->prefix
.family
== AF_INET
)
691 return MPLS_LABEL_IPV4_EXPLICIT_NULL
;
693 return MPLS_LABEL_IPV6_EXPLICIT_NULL
;
698 /* Return SID value as MPLS label if it is an Absolute SID */
699 if (CHECK_FLAG(srp
->sid
.flags
,
700 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
)) {
702 * V/L SIDs have local significance, so only adjacent routers
703 * can use them (RFC8667 section #2.1.1.1)
705 if (srp
->srn
!= srn_nexthop
)
706 return MPLS_INVALID_LABEL
;
707 return srp
->sid
.value
;
710 /* Check that SID index falls inside the SRGB */
711 if (srp
->sid
.value
>= srn_nexthop
->cap
.srgb
.range_size
) {
712 flog_warn(EC_ISIS_SID_OVERFLOW
,
713 "%s: SID index %u falls outside remote SRGB range",
714 __func__
, srp
->sid
.value
);
715 return MPLS_INVALID_LABEL
;
718 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
719 return (srn_nexthop
->cap
.srgb
.lower_bound
+ srp
->sid
.value
);
723 * Process local Prefix-SID and install it if possible. Input label is
724 * computed before installing it in LFIB.
726 * @param srp Segment Routing Prefix
728 * @return 0 on success, -1 otherwise
730 static int sr_prefix_install_local(struct sr_prefix
*srp
)
732 mpls_label_t input_label
;
733 const struct sr_node
*srn
= srp
->srn
;
736 * No need to install Label for local Prefix-SID unless the
737 * no-PHP option is configured.
739 if (!CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_NO_PHP
)
740 || CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
))
743 sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s) with nexthop self",
744 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
745 srp
->sid
.value
, circuit_t2string(srn
->level
));
747 /* Compute input label and check that is valid. */
748 input_label
= sr_prefix_in_label(srp
);
749 if (input_label
== MPLS_INVALID_LABEL
)
752 /* Update internal state. */
753 srp
->input_label
= input_label
;
754 isis_sr_nexthop_update(&srp
->u
.local
.info
, MPLS_LABEL_IMPLICIT_NULL
);
756 /* Install Prefix-SID in the forwarding plane. */
757 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE
, srp
);
763 * Process remote Prefix-SID and install it if possible. Input and Output
764 * labels are computed before installing them in LFIB.
766 * @param srp Segment Routing Prefix
768 * @return 0 on success, -1 otherwise
770 static int sr_prefix_install_remote(struct sr_prefix
*srp
)
772 const struct sr_node
*srn
= srp
->srn
;
773 struct isis_area
*area
= srn
->area
;
774 enum spf_tree_id tree_id
;
775 struct listnode
*node
;
776 struct isis_nexthop
*nexthop
;
777 mpls_label_t input_label
;
778 size_t nexthop_num
= 0;
780 /* Lookup to associated IS-IS route. */
781 tree_id
= (srp
->prefix
.family
== AF_INET
) ? SPFTREE_IPV4
: SPFTREE_IPV6
;
782 srp
->u
.remote
.rinfo
= sr_prefix_lookup_route(area
, tree_id
, srp
);
783 if (!srp
->u
.remote
.rinfo
)
784 /* SPF hasn't converged for this route yet. */
787 /* Compute input label and check that is valid. */
788 input_label
= sr_prefix_in_label(srp
);
789 if (input_label
== MPLS_INVALID_LABEL
)
792 sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s)", &srp
->prefix
,
793 IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
794 srp
->sid
.value
, circuit_t2string(srn
->level
));
796 /* Process all SPF nexthops */
797 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
, node
,
799 struct sr_node
*srn_nexthop
;
800 mpls_label_t output_label
;
802 /* Check if the nexthop advertised a SRGB. */
803 srn_nexthop
= sr_node_find(area
, srn
->level
, nexthop
->sysid
);
808 * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
811 if ((nexthop
->family
== AF_INET
812 && !IS_SR_IPV4(srn_nexthop
->cap
.srgb
))
813 || (nexthop
->family
== AF_INET6
814 && !IS_SR_IPV6(srn_nexthop
->cap
.srgb
)))
817 /* Compute output label and check if it is valid */
819 sr_prefix_out_label(srp
, srn_nexthop
, nexthop
->sysid
);
820 if (output_label
== MPLS_INVALID_LABEL
)
824 static char buf
[INET6_ADDRSTRLEN
];
826 inet_ntop(nexthop
->family
, &nexthop
->ip
, buf
,
828 zlog_debug(" |- nexthop %s label %u", buf
,
832 isis_sr_nexthop_update(&nexthop
->sr
, output_label
);
836 isis_sr_nexthop_reset(&nexthop
->sr
);
839 /* Check that we found at least one valid nexthop */
840 if (nexthop_num
== 0) {
841 sr_debug(" |- no valid nexthops");
845 /* Update internal state. */
846 srp
->input_label
= input_label
;
848 /* Install Prefix-SID in the forwarding plane. */
849 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE
, srp
);
855 * Process local or remote Prefix-SID and install it if possible.
857 * @param srp Segment Routing Prefix
859 static void sr_prefix_install(struct sr_prefix
*srp
)
861 const struct sr_node
*srn
= srp
->srn
;
862 struct isis_area
*area
= srn
->area
;
865 sr_debug("ISIS-Sr (%s): Install Prefix-SID %pFX %s %u", area
->area_tag
,
866 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
869 /* L1 routes are preferred over the L2 ones. */
870 if (area
->is_type
== IS_LEVEL_1_AND_2
) {
871 struct sr_prefix
*srp_l1
, *srp_l2
;
873 switch (srn
->level
) {
875 srp_l2
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
,
878 sr_prefix_uninstall(srp_l2
);
881 srp_l1
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
,
891 /* Install corresponding LFIB entry */
892 if (srp
->type
== ISIS_SR_PREFIX_LOCAL
)
893 ret
= sr_prefix_install_local(srp
);
895 ret
= sr_prefix_install_remote(srp
);
897 sr_prefix_uninstall(srp
);
901 * Uninstall local or remote Prefix-SID.
903 * @param srp Segment Routing Prefix
905 static void sr_prefix_uninstall(struct sr_prefix
*srp
)
907 struct listnode
*node
;
908 struct isis_nexthop
*nexthop
;
910 /* Check that Input Label is valid */
911 if (srp
->input_label
== MPLS_INVALID_LABEL
)
914 sr_debug("ISIS-Sr: Un-install Prefix-SID %pFX %s %u", &srp
->prefix
,
915 IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
918 /* Uninstall Prefix-SID from the forwarding plane. */
919 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE
, srp
);
921 /* Reset internal state. */
922 srp
->input_label
= MPLS_INVALID_LABEL
;
924 case ISIS_SR_PREFIX_LOCAL
:
925 isis_sr_nexthop_reset(&srp
->u
.local
.info
);
927 case ISIS_SR_PREFIX_REMOTE
:
928 if (srp
->u
.remote
.rinfo
) {
929 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
,
931 isis_sr_nexthop_reset(&nexthop
->sr
);
938 * Reinstall local or remote Prefix-SID.
940 * @param srp Segment Routing Prefix
942 static inline void sr_prefix_reinstall(struct sr_prefix
*srp
,
943 bool make_before_break
)
946 * Make Before Break can be used only when we know for sure that
947 * the Prefix-SID input label hasn't changed. Otherwise we need to
948 * uninstall the Prefix-SID first using the old input label before
951 if (!make_before_break
)
952 sr_prefix_uninstall(srp
);
954 /* New input label is computed in sr_prefix_install() function */
955 sr_prefix_install(srp
);
958 /* --- IS-IS LSP Parse functions -------------------------------------------- */
961 * Compare Router Capabilities. Only Flags, SRGB and Algorithm are used for the
962 * comparison. MSD and SRLB modification must not trigger and SR-Prefix update.
964 * @param r1 First Router Capabilities to compare
965 * @param r2 Second Router Capabilities to compare
966 * @return 0 if r1 and r2 are equal or -1 otherwise
968 static int router_cap_cmp(const struct isis_router_cap
*r1
,
969 const struct isis_router_cap
*r2
)
971 if (r1
->flags
== r2
->flags
972 && r1
->srgb
.lower_bound
== r2
->srgb
.lower_bound
973 && r1
->srgb
.range_size
== r2
->srgb
.range_size
974 && r1
->algo
[0] == r2
->algo
[0])
981 * Parse all SR-related information from the given Router Capabilities TLV.
983 * @param area IS-IS area
984 * @param level IS-IS level
985 * @param sysid System ID of the LSP
986 * @param router_cap Router Capability subTLVs
988 * @return Segment Routing Node structure for this System ID
990 static struct sr_node
*
991 parse_router_cap_tlv(struct isis_area
*area
, int level
, const uint8_t *sysid
,
992 const struct isis_router_cap
*router_cap
)
996 if (!router_cap
|| router_cap
->srgb
.range_size
== 0)
999 sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area
->area_tag
);
1001 srn
= sr_node_find(area
, level
, sysid
);
1003 if (router_cap_cmp(&srn
->cap
, router_cap
) != 0) {
1004 srn
->state
= SRDB_STATE_MODIFIED
;
1006 srn
->state
= SRDB_STATE_UNCHANGED
;
1007 sr_debug(" |- Found %s SR Node %s",
1008 srn
->state
== SRDB_STATE_MODIFIED
? "Modified"
1010 sysid_print(srn
->sysid
));
1012 srn
= sr_node_add(area
, level
, sysid
);
1013 srn
->state
= SRDB_STATE_NEW
;
1017 * Update Router Capabilities in any case as SRLB or MSD
1018 * modification are not take into account for comparison.
1020 srn
->cap
= *router_cap
;
1026 * Parse list of Prefix-SID Sub-TLVs.
1028 * @param srn Segment Routing Node
1029 * @param prefix Prefix to be parsed
1030 * @param local True if prefix comes from own LSP, false otherwise
1031 * @param prefix_sids Prefix SID subTLVs
1033 static void parse_prefix_sid_subtlvs(struct sr_node
*srn
,
1034 union prefixconstptr prefix
, bool local
,
1035 struct isis_item_list
*prefix_sids
)
1037 struct isis_area
*area
= srn
->area
;
1038 struct isis_item
*i
;
1040 sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area
->area_tag
);
1042 /* Parse list of Prefix SID subTLVs */
1043 for (i
= prefix_sids
->head
; i
; i
= i
->next
) {
1044 struct isis_prefix_sid
*psid
= (struct isis_prefix_sid
*)i
;
1045 struct sr_prefix
*srp
;
1047 /* Only SPF algorithm is supported right now */
1048 if (psid
->algorithm
!= SR_ALGORITHM_SPF
)
1051 /* Compute corresponding Segment Routing Prefix */
1052 srp
= sr_prefix_find_by_node(srn
, prefix
);
1054 if (srp
->sid
.flags
!= psid
->flags
1055 || srp
->sid
.algorithm
!= psid
->algorithm
1056 || srp
->sid
.value
!= psid
->value
) {
1058 srp
->state
= SRDB_STATE_MODIFIED
;
1059 } else if (srp
->state
== SRDB_STATE_VALIDATED
)
1060 srp
->state
= SRDB_STATE_UNCHANGED
;
1061 sr_debug(" |- Found %s Prefix-SID %pFX",
1062 srp
->state
== SRDB_STATE_MODIFIED
1068 srp
= sr_prefix_add(area
, srn
, prefix
, local
, psid
);
1069 srp
->state
= SRDB_STATE_NEW
;
1072 * Stop the Prefix-SID iteration since we only support the SPF
1073 * algorithm for now.
1080 * Parse all SR-related information from the given LSP.
1082 * @param area IS-IS area
1083 * @param level IS-IS level
1084 * @param srn Segment Routing Node
1085 * @param lsp IS-IS LSP
1087 static void parse_lsp(struct isis_area
*area
, int level
, struct sr_node
**srn
,
1088 struct isis_lsp
*lsp
)
1090 struct isis_item_list
*items
;
1091 struct isis_item
*i
;
1092 bool local
= lsp
->own_lsp
;
1094 /* Check LSP sequence number */
1095 if (lsp
->hdr
.seqno
== 0) {
1096 zlog_warn("%s: lsp with 0 seq_num - ignore", __func__
);
1100 sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area
->area_tag
,
1101 sysid_print(lsp
->hdr
.lsp_id
));
1103 /* Parse the Router Capability TLV. */
1105 *srn
= parse_router_cap_tlv(area
, level
, lsp
->hdr
.lsp_id
,
1106 lsp
->tlvs
->router_cap
);
1111 /* Parse the Extended IP Reachability TLV. */
1112 items
= &lsp
->tlvs
->extended_ip_reach
;
1113 for (i
= items
->head
; i
; i
= i
->next
) {
1114 struct isis_extended_ip_reach
*ir
;
1116 ir
= (struct isis_extended_ip_reach
*)i
;
1120 parse_prefix_sid_subtlvs(*srn
, &ir
->prefix
, local
,
1121 &ir
->subtlvs
->prefix_sids
);
1124 /* Parse Multi Topology Reachable IPv6 Prefixes TLV. */
1125 items
= isis_lookup_mt_items(&lsp
->tlvs
->mt_ipv6_reach
,
1126 ISIS_MT_IPV6_UNICAST
);
1127 for (i
= items
? items
->head
: NULL
; i
; i
= i
->next
) {
1128 struct isis_ipv6_reach
*ir
;
1130 ir
= (struct isis_ipv6_reach
*)i
;
1134 parse_prefix_sid_subtlvs(*srn
, &ir
->prefix
, local
,
1135 &ir
->subtlvs
->prefix_sids
);
1140 * Parse all SR-related information from the entire LSPDB.
1142 * @param area IS-IS area
1144 static void parse_lspdb(struct isis_area
*area
)
1146 struct isis_lsp
*lsp
;
1148 sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area
->area_tag
);
1150 /* Process all LSP from Level 1 & 2 */
1151 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
1152 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
) {
1153 struct isis_lsp
*frag
;
1154 struct listnode
*node
;
1155 struct sr_node
*srn
= NULL
;
1157 /* Skip Pseudo ID LSP and LSP without TLVs */
1158 if (LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
))
1163 /* Parse LSP, then fragment */
1164 parse_lsp(area
, level
, &srn
, lsp
);
1165 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
1166 parse_lsp(area
, level
, &srn
, frag
);
1172 * Process any new/deleted/modified Prefix-SID in the LSPDB.
1174 * @param srn Segment Routing Node
1175 * @param srp Segment Routing Prefix
1177 static void process_prefix_changes(struct sr_node
*srn
, struct sr_prefix
*srp
)
1179 struct isis_area
*area
= srn
->area
;
1181 /* Install/reinstall/uninstall Prefix-SID if necessary. */
1182 switch (srp
->state
) {
1183 case SRDB_STATE_NEW
:
1184 sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
1185 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1186 sr_prefix_install(srp
);
1188 case SRDB_STATE_MODIFIED
:
1190 "ISIS-Sr (%s): Modified Prefix-SID %pFX for SR node %s",
1191 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1192 sr_prefix_reinstall(srp
, false);
1194 case SRDB_STATE_UNCHANGED
:
1197 sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
1198 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1199 sr_prefix_del(area
, srn
, srp
);
1203 /* Validate SRDB State for next LSPDB parsing */
1204 srp
->state
= SRDB_STATE_VALIDATED
;
1208 * Process any new/deleted/modified SRGB in the LSPDB.
1210 * @param area IS-IS area
1211 * @param level IS-IS level
1212 * @param srn Segment Routing Node
1214 static void process_node_changes(struct isis_area
*area
, int level
,
1215 struct sr_node
*srn
)
1217 struct sr_prefix
*srp
;
1218 uint8_t sysid
[ISIS_SYS_ID_LEN
];
1221 memcpy(sysid
, srn
->sysid
, sizeof(sysid
));
1224 * If an neighbor router's SRGB was changed or created, then reinstall
1225 * all Prefix-SIDs from all nodes that use this neighbor as nexthop.
1227 adjacent
= !!isis_adj_find(area
, level
, sysid
);
1228 switch (srn
->state
) {
1229 case SRDB_STATE_NEW
:
1230 case SRDB_STATE_MODIFIED
:
1231 sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
1232 area
->area_tag
, sysid_print(srn
->sysid
));
1234 sr_node_srgb_update(area
, level
, sysid
);
1236 case SRDB_STATE_UNCHANGED
:
1239 /* SR capabilities have been removed. Delete SR-Node */
1240 sr_debug("ISIS-Sr (%s): Remove SR node %s", area
->area_tag
,
1241 sysid_print(srn
->sysid
));
1243 sr_node_del(area
, level
, srn
);
1244 /* and Update remaining Prefix-SID from all remaining SR Node */
1246 sr_node_srgb_update(area
, level
, sysid
);
1250 /* Validate SRDB State for next LSPDB parsing */
1251 srn
->state
= SRDB_STATE_VALIDATED
;
1253 /* Finally, process all Prefix-SID of this SR Node */
1254 frr_each_safe (srdb_node_prefix
, &srn
->prefix_sids
, srp
)
1255 process_prefix_changes(srn
, srp
);
1259 * Delete all backup Adj-SIDs.
1261 * @param area IS-IS area
1262 * @param level IS-IS level
1264 void isis_area_delete_backup_adj_sids(struct isis_area
*area
, int level
)
1266 struct sr_adjacency
*sra
;
1267 struct listnode
*node
, *nnode
;
1269 for (ALL_LIST_ELEMENTS(area
->srdb
.adj_sids
, node
, nnode
, sra
))
1270 if (sra
->type
== ISIS_SR_LAN_BACKUP
1271 && (sra
->adj
->level
& level
))
1272 sr_adj_sid_del(sra
);
1276 * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
1278 * @param area IS-IS area
1280 void isis_area_verify_sr(struct isis_area
*area
)
1282 struct sr_node
*srn
;
1284 if (!area
->srdb
.enabled
)
1287 /* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
1290 /* Process possible SR-related changes in the LDPSB. */
1291 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
1292 frr_each_safe (srdb_node
, &area
->srdb
.sr_nodes
[level
- 1], srn
)
1293 process_node_changes(area
, level
, srn
);
1298 * Once a route is updated in the SPT, reinstall or uninstall its corresponding
1299 * Prefix-SID (if any).
1301 * @param area IS-IS area
1302 * @param prefix Prefix to be updated
1303 * @param route_info New Route Information
1307 static int sr_route_update(struct isis_area
*area
, struct prefix
*prefix
,
1308 struct isis_route_info
*route_info
)
1310 struct sr_prefix
*srp
;
1312 if (!area
->srdb
.enabled
)
1315 sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area
->area_tag
,
1318 /* Lookup to Segment Routing Prefix for this prefix */
1319 switch (area
->is_type
) {
1321 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
, prefix
);
1324 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
, prefix
);
1326 case IS_LEVEL_1_AND_2
:
1327 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
, prefix
);
1329 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
, prefix
);
1332 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown area level",
1337 /* Skip NULL or local Segment Routing Prefix */
1338 if (!srp
|| srp
->type
== ISIS_SR_PREFIX_LOCAL
)
1341 /* Install or unintall Prefix-SID if route is Active or not */
1342 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)) {
1344 * The Prefix-SID input label hasn't changed. We could use the
1345 * "Make Before Break" option. Zebra layer will update output
1346 * label by adding new label(s) before removing old one(s).
1348 sr_prefix_reinstall(srp
, true);
1349 srp
->u
.remote
.rinfo
= route_info
;
1351 sr_prefix_uninstall(srp
);
1352 srp
->u
.remote
.rinfo
= NULL
;
1358 /* --- Segment Routing Local Block management functions --------------------- */
1361 * Initialize Segment Routing Local Block from SRDB configuration and reserve
1362 * block of bits to manage label allocation.
1364 * @param area IS-IS area
1366 static int sr_local_block_init(struct isis_area
*area
)
1368 struct isis_sr_db
*srdb
= &area
->srdb
;
1369 struct sr_local_block
*srlb
= &srdb
->srlb
;
1371 /* Check if SRLB is not already configured */
1376 * Request SRLB to the label manager. If the allocation fails, return
1377 * an error to disable SR until a new SRLB is successfully allocated.
1379 if (isis_zebra_request_label_range(
1380 srdb
->config
.srlb_lower_bound
,
1381 srdb
->config
.srlb_upper_bound
1382 - srdb
->config
.srlb_lower_bound
+ 1)) {
1383 srlb
->active
= false;
1387 sr_debug("ISIS-Sr (%s): Got new SRLB [%u/%u]", area
->area_tag
,
1388 srdb
->config
.srlb_lower_bound
, srdb
->config
.srlb_upper_bound
);
1390 /* Initialize the SRLB */
1391 srlb
->start
= srdb
->config
.srlb_lower_bound
;
1392 srlb
->end
= srdb
->config
.srlb_upper_bound
;
1394 /* Compute the needed Used Mark number and allocate them */
1395 srlb
->max_block
= (srlb
->end
- srlb
->start
+ 1) / SRLB_BLOCK_SIZE
;
1396 if (((srlb
->end
- srlb
->start
+ 1) % SRLB_BLOCK_SIZE
) != 0)
1398 srlb
->used_mark
= XCALLOC(MTYPE_ISIS_SR_INFO
,
1399 srlb
->max_block
* SRLB_BLOCK_SIZE
);
1400 srlb
->active
= true;
1406 * Remove Segment Routing Local Block.
1408 * @param area IS-IS area
1410 static void sr_local_block_delete(struct isis_area
*area
)
1412 struct isis_sr_db
*srdb
= &area
->srdb
;
1413 struct sr_local_block
*srlb
= &srdb
->srlb
;
1415 /* Check if SRLB is not already delete */
1419 sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area
->area_tag
,
1420 srlb
->start
, srlb
->end
);
1422 /* First release the label block */
1423 isis_zebra_release_label_range(srdb
->config
.srlb_lower_bound
,
1424 srdb
->config
.srlb_upper_bound
);
1426 /* Then reset SRLB structure */
1427 if (srlb
->used_mark
!= NULL
)
1428 XFREE(MTYPE_ISIS_SR_INFO
, srlb
->used_mark
);
1429 srlb
->active
= false;
1433 * Request a label from the Segment Routing Local Block.
1435 * @param srlb Segment Routing Local Block
1437 * @return First available label on success or MPLS_INVALID_LABEL if the
1438 * block of labels is full
1440 static mpls_label_t
sr_local_block_request_label(struct sr_local_block
*srlb
)
1447 /* Check if we ran out of available labels */
1448 if (srlb
->current
>= srlb
->end
)
1449 return MPLS_INVALID_LABEL
;
1451 /* Get first available label and mark it used */
1452 label
= srlb
->current
+ srlb
->start
;
1453 index
= srlb
->current
/ SRLB_BLOCK_SIZE
;
1454 pos
= 1ULL << (srlb
->current
% SRLB_BLOCK_SIZE
);
1455 srlb
->used_mark
[index
] |= pos
;
1457 /* Jump to the next free position */
1459 pos
= srlb
->current
% SRLB_BLOCK_SIZE
;
1460 while (srlb
->current
< srlb
->end
) {
1463 if (!((1ULL << pos
) & srlb
->used_mark
[index
]))
1467 pos
= srlb
->current
% SRLB_BLOCK_SIZE
;
1475 * Release label in the Segment Routing Local Block.
1477 * @param srlb Segment Routing Local Block
1478 * @param label Label to be release
1480 * @return 0 on success or -1 if label falls outside SRLB
1482 static int sr_local_block_release_label(struct sr_local_block
*srlb
,
1488 /* Check that label falls inside the SRLB */
1489 if ((label
< srlb
->start
) || (label
> srlb
->end
)) {
1490 flog_warn(EC_ISIS_SID_OVERFLOW
,
1491 "%s: Returning label %u is outside SRLB [%u/%u]",
1492 __func__
, label
, srlb
->start
, srlb
->end
);
1496 index
= (label
- srlb
->start
) / SRLB_BLOCK_SIZE
;
1497 pos
= 1ULL << ((label
- srlb
->start
) % SRLB_BLOCK_SIZE
);
1498 srlb
->used_mark
[index
] &= ~pos
;
1499 /* Reset current to the first available position */
1500 for (index
= 0; index
< srlb
->max_block
; index
++) {
1501 if (srlb
->used_mark
[index
] != 0xFFFFFFFFFFFFFFFF) {
1502 for (pos
= 0; pos
< SRLB_BLOCK_SIZE
; pos
++)
1503 if (!((1ULL << pos
) & srlb
->used_mark
[index
])) {
1505 index
* SRLB_BLOCK_SIZE
+ pos
;
1515 /* --- Segment Routing Adjacency-SID management functions ------------------- */
1518 * Add new local Adjacency-SID.
1520 * @param adj IS-IS Adjacency
1521 * @param family Inet Family (IPv4 or IPv6)
1522 * @param backup True to initialize backup Adjacency SID
1523 * @param nexthops List of backup nexthops (for backup Adj-SIDs only)
1525 void sr_adj_sid_add_single(struct isis_adjacency
*adj
, int family
, bool backup
,
1526 struct list
*nexthops
)
1528 struct isis_circuit
*circuit
= adj
->circuit
;
1529 struct isis_area
*area
= circuit
->area
;
1530 struct sr_adjacency
*sra
;
1531 struct isis_adj_sid
*adj_sid
;
1532 struct isis_lan_adj_sid
*ladj_sid
;
1533 union g_addr nexthop
= {};
1535 mpls_label_t input_label
;
1537 sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area
->area_tag
,
1538 backup
? "Backup" : "Primary");
1540 /* Determine nexthop IP address */
1543 if (!circuit
->ip_router
|| !adj
->ipv4_address_count
)
1546 nexthop
.ipv4
= adj
->ipv4_addresses
[0];
1549 if (!circuit
->ipv6_router
|| !adj
->ipv6_address_count
)
1552 nexthop
.ipv6
= adj
->ipv6_addresses
[0];
1555 flog_err(EC_LIB_DEVELOPMENT
,
1556 "%s: unexpected address-family: %u", __func__
, family
);
1560 /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
1561 flags
= EXT_SUBTLV_LINK_ADJ_SID_VFLG
| EXT_SUBTLV_LINK_ADJ_SID_LFLG
;
1562 if (family
== AF_INET6
)
1563 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_FFLG
);
1565 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_BFLG
);
1567 /* Get a label from the SRLB for this Adjacency */
1568 input_label
= sr_local_block_request_label(&area
->srdb
.srlb
);
1569 if (input_label
== MPLS_INVALID_LABEL
)
1572 if (circuit
->ext
== NULL
)
1573 circuit
->ext
= isis_alloc_ext_subtlvs();
1575 sra
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*sra
));
1576 sra
->type
= backup
? ISIS_SR_LAN_BACKUP
: ISIS_SR_ADJ_NORMAL
;
1577 sra
->input_label
= input_label
;
1578 sra
->nexthop
.family
= family
;
1579 sra
->nexthop
.address
= nexthop
;
1581 if (backup
&& nexthops
) {
1582 struct isis_vertex_adj
*vadj
;
1583 struct listnode
*node
;
1585 sra
->backup_nexthops
= list_new();
1586 for (ALL_LIST_ELEMENTS_RO(nexthops
, node
, vadj
)) {
1587 struct isis_adjacency
*adj
= vadj
->sadj
->adj
;
1588 struct mpls_label_stack
*label_stack
;
1590 label_stack
= vadj
->label_stack
;
1591 adjinfo2nexthop(family
, sra
->backup_nexthops
, adj
,
1596 switch (circuit
->circ_type
) {
1597 /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
1598 case CIRCUIT_T_BROADCAST
:
1599 ladj_sid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*ladj_sid
));
1600 ladj_sid
->family
= family
;
1601 ladj_sid
->flags
= flags
;
1602 ladj_sid
->weight
= 0;
1603 memcpy(ladj_sid
->neighbor_id
, adj
->sysid
,
1604 sizeof(ladj_sid
->neighbor_id
));
1605 ladj_sid
->sid
= input_label
;
1606 isis_tlvs_add_lan_adj_sid(circuit
->ext
, ladj_sid
);
1607 sra
->u
.ladj_sid
= ladj_sid
;
1609 /* Adjacency-SID for Point to Point interface section #2.2.1 */
1611 adj_sid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*adj_sid
));
1612 adj_sid
->family
= family
;
1613 adj_sid
->flags
= flags
;
1614 adj_sid
->weight
= 0;
1615 adj_sid
->sid
= input_label
;
1616 isis_tlvs_add_adj_sid(circuit
->ext
, adj_sid
);
1617 sra
->u
.adj_sid
= adj_sid
;
1620 flog_err(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1621 __func__
, circuit
->circ_type
);
1625 /* Add Adjacency-SID in SRDB */
1627 listnode_add(area
->srdb
.adj_sids
, sra
);
1628 listnode_add(adj
->adj_sids
, sra
);
1630 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD
, sra
);
1634 * Add Primary and Backup local Adjacency SID.
1636 * @param adj IS-IS Adjacency
1637 * @param family Inet Family (IPv4 or IPv6)
1639 static void sr_adj_sid_add(struct isis_adjacency
*adj
, int family
)
1641 sr_adj_sid_add_single(adj
, family
, false, NULL
);
1644 static void sr_adj_sid_update(struct sr_adjacency
*sra
,
1645 struct sr_local_block
*srlb
)
1647 struct isis_circuit
*circuit
= sra
->adj
->circuit
;
1649 /* First remove the old MPLS Label */
1650 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE
, sra
);
1652 /* Got new label in the new SRLB */
1653 sra
->input_label
= sr_local_block_request_label(srlb
);
1654 if (sra
->input_label
== MPLS_INVALID_LABEL
)
1657 switch (circuit
->circ_type
) {
1658 case CIRCUIT_T_BROADCAST
:
1659 sra
->u
.ladj_sid
->sid
= sra
->input_label
;
1662 sra
->u
.adj_sid
->sid
= sra
->input_label
;
1665 flog_warn(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1666 __func__
, circuit
->circ_type
);
1670 /* Finally configure the new MPLS Label */
1671 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD
, sra
);
1675 * Delete local Adj-SID.
1677 * @param sra Segment Routing Adjacency
1679 static void sr_adj_sid_del(struct sr_adjacency
*sra
)
1681 struct isis_circuit
*circuit
= sra
->adj
->circuit
;
1682 struct isis_area
*area
= circuit
->area
;
1684 sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area
->area_tag
);
1686 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE
, sra
);
1688 /* Release dynamic label and remove subTLVs */
1689 switch (circuit
->circ_type
) {
1690 case CIRCUIT_T_BROADCAST
:
1691 sr_local_block_release_label(&area
->srdb
.srlb
,
1692 sra
->u
.ladj_sid
->sid
);
1693 isis_tlvs_del_lan_adj_sid(circuit
->ext
, sra
->u
.ladj_sid
);
1696 sr_local_block_release_label(&area
->srdb
.srlb
,
1697 sra
->u
.adj_sid
->sid
);
1698 isis_tlvs_del_adj_sid(circuit
->ext
, sra
->u
.adj_sid
);
1701 flog_err(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1702 __func__
, circuit
->circ_type
);
1706 if (sra
->type
== ISIS_SR_LAN_BACKUP
&& sra
->backup_nexthops
) {
1707 sra
->backup_nexthops
->del
=
1708 (void (*)(void *))isis_nexthop_delete
;
1709 list_delete(&sra
->backup_nexthops
);
1712 /* Remove Adjacency-SID from the SRDB */
1713 listnode_delete(area
->srdb
.adj_sids
, sra
);
1714 listnode_delete(sra
->adj
->adj_sids
, sra
);
1715 XFREE(MTYPE_ISIS_SR_INFO
, sra
);
1719 * Lookup Segment Routing Adj-SID by family and type.
1721 * @param adj IS-IS Adjacency
1722 * @param family Inet Family (IPv4 or IPv6)
1723 * @param type Adjacency SID type
1725 struct sr_adjacency
*isis_sr_adj_sid_find(struct isis_adjacency
*adj
,
1726 int family
, enum sr_adj_type type
)
1728 struct sr_adjacency
*sra
;
1729 struct listnode
*node
;
1731 for (ALL_LIST_ELEMENTS_RO(adj
->adj_sids
, node
, sra
))
1732 if (sra
->nexthop
.family
== family
&& sra
->type
== type
)
1739 * Remove all Adjacency-SIDs associated to an adjacency that is going down.
1741 * @param adj IS-IS Adjacency
1745 static int sr_adj_state_change(struct isis_adjacency
*adj
)
1747 struct sr_adjacency
*sra
;
1748 struct listnode
*node
, *nnode
;
1750 if (!adj
->circuit
->area
->srdb
.enabled
)
1753 if (adj
->adj_state
== ISIS_ADJ_UP
)
1756 for (ALL_LIST_ELEMENTS(adj
->adj_sids
, node
, nnode
, sra
))
1757 sr_adj_sid_del(sra
);
1763 * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
1764 * IPv6 address to corresponding Adjacency-SID accordingly.
1766 * @param adj IS-IS Adjacency
1767 * @param family Inet Family (IPv4 or IPv6)
1771 static int sr_adj_ip_enabled(struct isis_adjacency
*adj
, int family
)
1773 if (!adj
->circuit
->area
->srdb
.enabled
)
1776 sr_adj_sid_add(adj
, family
);
1782 * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
1783 * delete the corresponding Adjacency-SID(s) accordingly.
1785 * @param adj IS-IS Adjacency
1786 * @param family Inet Family (IPv4 or IPv6)
1790 static int sr_adj_ip_disabled(struct isis_adjacency
*adj
, int family
)
1792 struct sr_adjacency
*sra
;
1793 struct listnode
*node
, *nnode
;
1795 if (!adj
->circuit
->area
->srdb
.enabled
)
1798 for (ALL_LIST_ELEMENTS(adj
->adj_sids
, node
, nnode
, sra
))
1799 if (sra
->nexthop
.family
== family
)
1800 sr_adj_sid_del(sra
);
1806 * Activate local Prefix-SID when loopback interface goes up for IS-IS.
1808 * @param ifp Loopback Interface
1812 static int sr_if_new_hook(struct interface
*ifp
)
1814 struct isis_circuit
*circuit
;
1815 struct isis_area
*area
;
1816 struct connected
*connected
;
1817 struct listnode
*node
;
1819 /* Get corresponding circuit */
1820 circuit
= circuit_scan_by_ifp(ifp
);
1824 area
= circuit
->area
;
1829 * Update the Node-SID flag of the configured Prefix-SID mappings if
1830 * necessary. This needs to be done here since isisd reads the startup
1831 * configuration before receiving interface information from zebra.
1833 FOR_ALL_INTERFACES_ADDRESSES (ifp
, connected
, node
) {
1834 struct sr_prefix_cfg
*pcfg
;
1836 pcfg
= isis_sr_cfg_prefix_find(area
, connected
->address
);
1840 if (sr_prefix_is_node_sid(ifp
, &pcfg
->prefix
)
1841 && !pcfg
->node_sid
) {
1842 pcfg
->node_sid
= true;
1843 lsp_regenerate_schedule(area
, area
->is_type
, 0);
1850 /* --- Segment Routing Show information functions --------------------------- */
1853 * Show LFIB operation in human readable format.
1855 * @param buf Buffer to store string output. Must be pre-allocate
1856 * @param size Size of the buffer
1857 * @param label_in Input Label
1858 * @param label_out Output Label
1859 * @param label_stack Output Label Stack (TI-LFA)
1861 * @return String containing LFIB operation in human readable format
1863 static char *sr_op2str(char *buf
, size_t size
, mpls_label_t label_in
,
1864 mpls_label_t label_out
,
1865 const struct mpls_label_stack
*label_stack
)
1870 if (label_in
== MPLS_INVALID_LABEL
) {
1871 snprintf(buf
, size
, "no-op.");
1876 char buf_labels
[256];
1878 mpls_label2str(label_stack
->num_labels
, &label_stack
->label
[0],
1879 buf_labels
, sizeof(buf_labels
), 1);
1881 snprintf(buf
, size
, "Swap(%u, %s)", label_in
, buf_labels
);
1885 switch (label_out
) {
1886 case MPLS_LABEL_IMPLICIT_NULL
:
1887 snprintf(buf
, size
, "Pop(%u)", label_in
);
1889 case MPLS_LABEL_IPV4_EXPLICIT_NULL
:
1890 case MPLS_LABEL_IPV6_EXPLICIT_NULL
:
1891 snprintf(buf
, size
, "Swap(%u, null)", label_in
);
1893 case MPLS_INVALID_LABEL
:
1894 snprintf(buf
, size
, "no-op.");
1897 snprintf(buf
, size
, "Swap(%u, %u)", label_in
, label_out
);
1904 * Show Local Prefix-SID.
1906 * @param vty VTY output
1907 * @param tt Table format
1908 * @param area IS-IS area
1909 * @param srp Segment Routing Prefix
1911 static void show_prefix_sid_local(struct vty
*vty
, struct ttable
*tt
,
1912 const struct isis_area
*area
,
1913 const struct sr_prefix
*srp
)
1915 const struct sr_nexthop_info
*srnh
= &srp
->u
.local
.info
;
1916 char buf_prefix
[BUFSIZ
];
1917 char buf_oper
[BUFSIZ
];
1918 char buf_iface
[BUFSIZ
];
1919 char buf_uptime
[BUFSIZ
];
1921 if (srnh
->label
!= MPLS_INVALID_LABEL
) {
1922 struct interface
*ifp
;
1923 ifp
= if_lookup_prefix(&srp
->prefix
, VRF_DEFAULT
);
1925 strlcpy(buf_iface
, ifp
->name
, sizeof(buf_iface
));
1927 snprintf(buf_iface
, sizeof(buf_iface
), "-");
1928 log_uptime(srnh
->uptime
, buf_uptime
, sizeof(buf_uptime
));
1930 snprintf(buf_iface
, sizeof(buf_iface
), "-");
1931 snprintf(buf_uptime
, sizeof(buf_uptime
), "-");
1933 sr_op2str(buf_oper
, sizeof(buf_oper
), srp
->input_label
,
1934 MPLS_LABEL_IMPLICIT_NULL
, NULL
);
1936 ttable_add_row(tt
, "%s|%u|%s|-|%s|%s",
1937 prefix2str(&srp
->prefix
, buf_prefix
, sizeof(buf_prefix
)),
1938 srp
->sid
.value
, buf_oper
, buf_iface
, buf_uptime
);
1942 * Show Remote Prefix-SID.
1944 * @param vty VTY output
1945 * @param tt Table format
1946 * @param area IS-IS area
1947 * @param srp Segment Routing Prefix
1949 static void show_prefix_sid_remote(struct vty
*vty
, struct ttable
*tt
,
1950 const struct isis_area
*area
,
1951 const struct sr_prefix
*srp
, bool backup
)
1953 struct isis_nexthop
*nexthop
;
1954 struct listnode
*node
;
1955 char buf_prefix
[BUFSIZ
];
1956 char buf_oper
[BUFSIZ
];
1957 char buf_nhop
[BUFSIZ
];
1958 char buf_iface
[BUFSIZ
];
1959 char buf_uptime
[BUFSIZ
];
1961 struct isis_route_info
*rinfo
;
1963 (void)prefix2str(&srp
->prefix
, buf_prefix
, sizeof(buf_prefix
));
1965 rinfo
= srp
->u
.remote
.rinfo
;
1966 if (rinfo
&& backup
)
1967 rinfo
= rinfo
->backup
;
1969 ttable_add_row(tt
, "%s|%u|%s|-|-|-", buf_prefix
, srp
->sid
.value
,
1970 sr_op2str(buf_oper
, sizeof(buf_oper
),
1972 MPLS_LABEL_IMPLICIT_NULL
, NULL
));
1976 for (ALL_LIST_ELEMENTS_RO(rinfo
->nexthops
, node
, nexthop
)) {
1977 struct interface
*ifp
;
1979 inet_ntop(nexthop
->family
, &nexthop
->ip
, buf_nhop
,
1981 ifp
= if_lookup_by_index(nexthop
->ifindex
, VRF_DEFAULT
);
1983 strlcpy(buf_iface
, ifp
->name
, sizeof(buf_iface
));
1985 snprintf(buf_iface
, sizeof(buf_iface
), "ifindex %u",
1987 if (nexthop
->sr
.label
== MPLS_INVALID_LABEL
)
1988 snprintf(buf_uptime
, sizeof(buf_uptime
), "-");
1990 log_uptime(nexthop
->sr
.uptime
, buf_uptime
,
1991 sizeof(buf_uptime
));
1992 sr_op2str(buf_oper
, sizeof(buf_oper
), srp
->input_label
,
1993 nexthop
->sr
.label
, nexthop
->label_stack
);
1996 ttable_add_row(tt
, "%s|%u|%s|%s|%s|%s", buf_prefix
,
1997 srp
->sid
.value
, buf_oper
, buf_nhop
,
1998 buf_iface
, buf_uptime
);
2000 ttable_add_row(tt
, "|||%s|%s|%s|%s", buf_oper
, buf_nhop
,
2001 buf_iface
, buf_uptime
);
2009 * @param vty VTY output
2010 * @param area IS-IS area
2011 * @param level IS-IS level
2013 static void show_prefix_sids(struct vty
*vty
, struct isis_area
*area
, int level
,
2016 struct sr_prefix
*srp
;
2019 if (srdb_area_prefix_count(&area
->srdb
.prefix_sids
[level
- 1]) == 0)
2022 vty_out(vty
, " IS-IS %s Prefix-SIDs:\n\n", circuit_t2string(level
));
2024 /* Prepare table. */
2025 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
2026 ttable_add_row(tt
, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
2027 tt
->style
.cell
.rpad
= 2;
2028 tt
->style
.corner
= '+';
2030 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
2032 /* Process all Prefix-SID from the SRDB */
2033 frr_each (srdb_area_prefix
, &area
->srdb
.prefix_sids
[level
- 1], srp
) {
2034 switch (srp
->type
) {
2035 case ISIS_SR_PREFIX_LOCAL
:
2036 show_prefix_sid_local(vty
, tt
, area
, srp
);
2038 case ISIS_SR_PREFIX_REMOTE
:
2039 show_prefix_sid_remote(vty
, tt
, area
, srp
, backup
);
2044 /* Dump the generated table. */
2045 if (tt
->nrows
> 1) {
2048 table
= ttable_dump(tt
, "\n");
2049 vty_out(vty
, "%s\n", table
);
2050 XFREE(MTYPE_TMP
, table
);
2056 * Declaration of new show commands.
2058 DEFUN(show_sr_prefix_sids
, show_sr_prefix_sids_cmd
,
2059 "show isis [vrf <NAME|all>] segment-routing prefix-sids [backup]",
2060 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
2063 "Segment-Routing Prefix-SIDs\n"
2064 "Show backup Prefix-SIDs\n")
2066 struct listnode
*node
, *inode
;
2067 struct isis_area
*area
;
2068 struct isis
*isis
= NULL
;
2069 const char *vrf_name
= VRF_DEFAULT_NAME
;
2070 bool all_vrf
= false;
2071 bool backup
= false;
2074 ISIS_FIND_VRF_ARGS(argv
, argc
, idx
, vrf_name
, all_vrf
);
2075 if (argv_find(argv
, argc
, "backup", &idx
))
2080 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
2081 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
,
2083 vty_out(vty
, "Area %s:\n",
2084 area
->area_tag
? area
->area_tag
2086 for (int level
= ISIS_LEVEL1
;
2087 level
<= ISIS_LEVELS
; level
++)
2088 show_prefix_sids(vty
, area
,
2094 isis
= isis_lookup_by_vrfname(vrf_name
);
2096 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
,
2098 vty_out(vty
, "Area %s:\n",
2099 area
->area_tag
? area
->area_tag
2101 for (int level
= ISIS_LEVEL1
;
2102 level
<= ISIS_LEVELS
; level
++)
2103 show_prefix_sids(vty
, area
, level
,
2113 * Show Segment Routing Node.
2115 * @param vty VTY output
2116 * @param area IS-IS area
2117 * @param level IS-IS level
2119 static void show_node(struct vty
*vty
, struct isis_area
*area
, int level
)
2121 struct sr_node
*srn
;
2124 if (srdb_area_prefix_count(&area
->srdb
.prefix_sids
[level
- 1]) == 0)
2127 vty_out(vty
, " IS-IS %s SR-Node:\n\n", circuit_t2string(level
));
2129 /* Prepare table. */
2130 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
2131 ttable_add_row(tt
, "System ID|SRGB|SRLB|Algorithm|MSD");
2132 tt
->style
.cell
.rpad
= 2;
2133 tt
->style
.corner
= '+';
2135 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
2137 /* Process all SR-Node from the SRDB */
2138 frr_each (srdb_node
, &area
->srdb
.sr_nodes
[level
- 1], srn
) {
2140 tt
, "%s|%u - %u|%u - %u|%s|%u",
2141 sysid_print(srn
->sysid
),
2142 srn
->cap
.srgb
.lower_bound
,
2143 srn
->cap
.srgb
.lower_bound
+ srn
->cap
.srgb
.range_size
2145 srn
->cap
.srlb
.lower_bound
,
2146 srn
->cap
.srlb
.lower_bound
+ srn
->cap
.srlb
.range_size
2148 srn
->cap
.algo
[0] == SR_ALGORITHM_SPF
? "SPF" : "S-SPF",
2152 /* Dump the generated table. */
2153 if (tt
->nrows
> 1) {
2156 table
= ttable_dump(tt
, "\n");
2157 vty_out(vty
, "%s\n", table
);
2158 XFREE(MTYPE_TMP
, table
);
2163 DEFUN(show_sr_node
, show_sr_node_cmd
,
2164 "show isis segment-routing node",
2167 "Segment-Routing node\n")
2169 struct listnode
*node
, *inode
;
2170 struct isis_area
*area
;
2173 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
2174 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2175 vty_out(vty
, "Area %s:\n",
2176 area
->area_tag
? area
->area_tag
: "null");
2178 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
;
2180 show_node(vty
, area
, level
);
2188 /* --- IS-IS Segment Routing Management function ---------------------------- */
2191 * Thread function to re-attempt connection to the Label Manager and thus be
2192 * able to start Segment Routing.
2194 * @param start Thread structure that contains area as argument
2196 * @return 1 on success
2198 static int sr_start_label_manager(struct thread
*start
)
2200 struct isis_area
*area
;
2202 area
= THREAD_ARG(start
);
2204 /* re-attempt to start SR & Label Manager connection */
2205 isis_sr_start(area
);
2211 * Enable SR on the given IS-IS area.
2213 * @param area IS-IS area
2215 * @return 0 on success, -1 otherwise
2217 int isis_sr_start(struct isis_area
*area
)
2219 struct isis_sr_db
*srdb
= &area
->srdb
;
2220 struct isis_adjacency
*adj
;
2221 struct listnode
*node
;
2223 /* First start Label Manager if not ready */
2224 if (!isis_zebra_label_manager_ready())
2225 if (isis_zebra_label_manager_connect() < 0) {
2226 /* Re-attempt to connect to Label Manager in 1 sec. */
2227 thread_add_timer(master
, sr_start_label_manager
, area
,
2228 1, &srdb
->t_start_lm
);
2232 /* Label Manager is ready, initialize the SRLB */
2233 if (sr_local_block_init(area
) < 0)
2237 * Request SGRB to the label manager if not already active. If the
2238 * allocation fails, return an error to disable SR until a new SRGB
2239 * is successfully allocated.
2241 if (!srdb
->srgb_active
) {
2242 if (isis_zebra_request_label_range(
2243 srdb
->config
.srgb_lower_bound
,
2244 srdb
->config
.srgb_upper_bound
2245 - srdb
->config
.srgb_lower_bound
+ 1)
2247 srdb
->srgb_active
= false;
2250 srdb
->srgb_active
= true;
2253 sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
2256 /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
2257 for (ALL_LIST_ELEMENTS_RO(area
->adjacency_list
, node
, adj
)) {
2258 if (adj
->ipv4_address_count
> 0)
2259 sr_adj_sid_add(adj
, AF_INET
);
2260 if (adj
->ipv6_address_count
> 0)
2261 sr_adj_sid_add(adj
, AF_INET6
);
2264 area
->srdb
.enabled
= true;
2266 /* Regenerate LSPs to advertise Segment Routing capabilities. */
2267 lsp_regenerate_schedule(area
, area
->is_type
, 0);
2273 * Disable SR on the given IS-IS area.
2275 * @param area IS-IS area
2277 void isis_sr_stop(struct isis_area
*area
)
2279 struct isis_sr_db
*srdb
= &area
->srdb
;
2280 struct sr_adjacency
*sra
;
2281 struct listnode
*node
, *nnode
;
2283 sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
2286 /* Disable any re-attempt to connect to Label Manager */
2287 THREAD_TIMER_OFF(srdb
->t_start_lm
);
2289 /* Uninstall all local Adjacency-SIDs. */
2290 for (ALL_LIST_ELEMENTS(area
->srdb
.adj_sids
, node
, nnode
, sra
))
2291 sr_adj_sid_del(sra
);
2293 /* Uninstall all Prefix-SIDs from all SR Node. */
2294 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2295 while (srdb_node_count(&srdb
->sr_nodes
[level
- 1]) > 0) {
2296 struct sr_node
*srn
;
2298 srn
= srdb_node_first(&srdb
->sr_nodes
[level
- 1]);
2299 sr_node_del(area
, level
, srn
);
2303 /* Release SRGB if active. */
2304 if (srdb
->srgb_active
) {
2305 isis_zebra_release_label_range(srdb
->config
.srgb_lower_bound
,
2306 srdb
->config
.srgb_upper_bound
);
2307 srdb
->srgb_active
= false;
2311 sr_local_block_delete(area
);
2313 area
->srdb
.enabled
= false;
2315 /* Regenerate LSPs to advertise that the Node is no more SR enable. */
2316 lsp_regenerate_schedule(area
, area
->is_type
, 0);
2320 * IS-IS Segment Routing initialization for given area.
2322 * @param area IS-IS area
2324 void isis_sr_area_init(struct isis_area
*area
)
2326 struct isis_sr_db
*srdb
= &area
->srdb
;
2328 sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
2331 /* Initialize Segment Routing Data Base */
2332 memset(srdb
, 0, sizeof(*srdb
));
2333 srdb
->adj_sids
= list_new();
2335 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2336 srdb_node_init(&srdb
->sr_nodes
[level
- 1]);
2337 srdb_area_prefix_init(&srdb
->prefix_sids
[level
- 1]);
2340 /* Pull defaults from the YANG module. */
2342 srdb
->config
.enabled
= yang_get_default_bool("%s/enabled", ISIS_SR
);
2343 srdb
->config
.srgb_lower_bound
=
2344 yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR
);
2345 srdb
->config
.srgb_upper_bound
=
2346 yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR
);
2347 srdb
->config
.srlb_lower_bound
=
2348 yang_get_default_uint32("%s/srlb/lower-bound", ISIS_SR
);
2349 srdb
->config
.srlb_upper_bound
=
2350 yang_get_default_uint32("%s/srlb/upper-bound", ISIS_SR
);
2352 srdb
->config
.enabled
= false;
2353 srdb
->config
.srgb_lower_bound
= SRGB_LOWER_BOUND
;
2354 srdb
->config
.srgb_upper_bound
= SRGB_UPPER_BOUND
;
2355 srdb
->config
.srlb_lower_bound
= SRLB_LOWER_BOUND
;
2356 srdb
->config
.srlb_upper_bound
= SRLB_UPPER_BOUND
;
2358 srdb
->config
.msd
= 0;
2359 srdb_prefix_cfg_init(&srdb
->config
.prefix_sids
);
2363 * Terminate IS-IS Segment Routing for the given area.
2365 * @param area IS-IS area
2367 void isis_sr_area_term(struct isis_area
*area
)
2369 struct isis_sr_db
*srdb
= &area
->srdb
;
2371 /* Stop Segment Routing */
2372 if (area
->srdb
.enabled
)
2375 /* Clear Prefix-SID configuration. */
2376 while (srdb_prefix_cfg_count(&srdb
->config
.prefix_sids
) > 0) {
2377 struct sr_prefix_cfg
*pcfg
;
2379 pcfg
= srdb_prefix_cfg_first(&srdb
->config
.prefix_sids
);
2380 isis_sr_cfg_prefix_del(pcfg
);
2385 * IS-IS Segment Routing global initialization.
2387 void isis_sr_init(void)
2389 install_element(VIEW_NODE
, &show_sr_prefix_sids_cmd
);
2390 install_element(VIEW_NODE
, &show_sr_node_cmd
);
2392 /* Register hooks. */
2393 hook_register(isis_adj_state_change_hook
, sr_adj_state_change
);
2394 hook_register(isis_adj_ip_enabled_hook
, sr_adj_ip_enabled
);
2395 hook_register(isis_adj_ip_disabled_hook
, sr_adj_ip_disabled
);
2396 hook_register(isis_route_update_hook
, sr_route_update
);
2397 hook_register(isis_if_new_hook
, sr_if_new_hook
);
2401 * IS-IS Segment Routing global terminate.
2403 void isis_sr_term(void)
2405 /* Unregister hooks. */
2406 hook_unregister(isis_adj_state_change_hook
, sr_adj_state_change
);
2407 hook_unregister(isis_adj_ip_enabled_hook
, sr_adj_ip_enabled
);
2408 hook_unregister(isis_adj_ip_disabled_hook
, sr_adj_ip_disabled
);
2409 hook_unregister(isis_route_update_hook
, sr_route_update
);
2410 hook_unregister(isis_if_new_hook
, sr_if_new_hook
);