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
);
60 /* --- RB-Tree Management functions ----------------------------------------- */
63 * SR Prefix comparison for RB-Tree.
65 * @param a First SR prefix
66 * @param b Second SR prefix
68 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
70 static inline int sr_prefix_sid_compare(const struct sr_prefix
*a
,
71 const struct sr_prefix
*b
)
73 return prefix_cmp(&a
->prefix
, &b
->prefix
);
75 DECLARE_RBTREE_UNIQ(srdb_node_prefix
, struct sr_prefix
, node_entry
,
76 sr_prefix_sid_compare
)
77 DECLARE_RBTREE_UNIQ(srdb_area_prefix
, struct sr_prefix
, area_entry
,
78 sr_prefix_sid_compare
)
81 * Configured SR Prefix comparison for RB-Tree.
83 * @param a First SR prefix
84 * @param b Second SR prefix
86 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
88 static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg
*a
,
89 const struct sr_prefix_cfg
*b
)
91 return prefix_cmp(&a
->prefix
, &b
->prefix
);
93 DECLARE_RBTREE_UNIQ(srdb_prefix_cfg
, struct sr_prefix_cfg
, entry
,
94 sr_prefix_sid_cfg_compare
)
97 * SR Node comparison for RB-Tree.
99 * @param a First SR node
100 * @param b Second SR node
102 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
104 static inline int sr_node_compare(const struct sr_node
*a
,
105 const struct sr_node
*b
)
107 return memcmp(a
->sysid
, b
->sysid
, ISIS_SYS_ID_LEN
);
109 DECLARE_RBTREE_UNIQ(srdb_node
, struct sr_node
, entry
, sr_node_compare
)
111 /* --- Functions used for Yang model and CLI to configure Segment Routing --- */
114 * Check if prefix correspond to a Node SID.
116 * @param ifp Interface
117 * @param prefix Prefix to be checked
119 * @return True if the interface/address pair corresponds to a Node-SID
121 static bool sr_prefix_is_node_sid(const struct interface
*ifp
,
122 const struct prefix
*prefix
)
124 return (if_is_loopback(ifp
) && is_host_route(prefix
));
128 * Update local SRGB configuration. SRGB is reserved though Label Manager.
129 * This function trigger the update of local Prefix-SID installation.
131 * @param area IS-IS area
132 * @param lower_bound Lower bound of SRGB
133 * @param upper_bound Upper bound of SRGB
135 * @return 0 on success, -1 otherwise
137 int isis_sr_cfg_srgb_update(struct isis_area
*area
, uint32_t lower_bound
,
138 uint32_t upper_bound
)
140 struct isis_sr_db
*srdb
= &area
->srdb
;
142 sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
143 area
->area_tag
, lower_bound
, upper_bound
);
145 /* Just store new SRGB values if Label Manager is not available.
146 * SRGB will be configured later when SR start */
147 if (!isis_zebra_label_manager_ready()) {
148 srdb
->config
.srgb_lower_bound
= lower_bound
;
149 srdb
->config
.srgb_upper_bound
= upper_bound
;
153 /* Label Manager is ready, start by releasing the old SRGB. */
154 if (srdb
->srgb_active
) {
155 isis_zebra_release_label_range(srdb
->config
.srgb_lower_bound
,
156 srdb
->config
.srgb_upper_bound
);
157 srdb
->srgb_active
= false;
160 srdb
->config
.srgb_lower_bound
= lower_bound
;
161 srdb
->config
.srgb_upper_bound
= upper_bound
;
164 struct sr_prefix
*srp
;
166 /* then request new SRGB if SR is enabled. */
167 if (isis_zebra_request_label_range(
168 srdb
->config
.srgb_lower_bound
,
169 srdb
->config
.srgb_upper_bound
170 - srdb
->config
.srgb_lower_bound
+ 1) < 0) {
171 srdb
->srgb_active
= false;
174 srdb
->srgb_active
= true;
177 sr_debug(" |- Got new SRGB [%u/%u]",
178 srdb
->config
.srgb_lower_bound
,
179 srdb
->config
.srgb_upper_bound
);
181 /* Reinstall local Prefix-SIDs to update their input labels. */
182 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
183 frr_each (srdb_area_prefix
,
184 &area
->srdb
.prefix_sids
[level
- 1], srp
) {
185 sr_prefix_reinstall(srp
, false);
189 lsp_regenerate_schedule(area
, area
->is_type
, 0);
190 } else if (srdb
->config
.enabled
) {
191 /* Try to enable SR again using the new SRGB. */
199 * Update Segment Routing Local Block range which is reserved though the
200 * Label Manager. This function trigger the update of local Adjacency-SID
203 * @param area IS-IS area
204 * @param lower_bound Lower bound of SRLB
205 * @param upper_bound Upper bound of SRLB
207 * @return 0 on success, -1 otherwise
209 int isis_sr_cfg_srlb_update(struct isis_area
*area
, uint32_t lower_bound
,
210 uint32_t upper_bound
)
212 struct isis_sr_db
*srdb
= &area
->srdb
;
213 struct listnode
*node
, *nnode
;
214 struct sr_adjacency
*sra
;
216 sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
217 area
->area_tag
, lower_bound
, upper_bound
);
219 /* Just store new SRLB values if Label Manager is not available.
220 * SRLB will be configured later when SR start */
221 if (!isis_zebra_label_manager_ready()) {
222 srdb
->config
.srlb_lower_bound
= lower_bound
;
223 srdb
->config
.srlb_upper_bound
= upper_bound
;
227 /* LM is ready, start by deleting the old SRLB */
228 sr_local_block_delete(area
);
230 srdb
->config
.srlb_lower_bound
= lower_bound
;
231 srdb
->config
.srlb_upper_bound
= upper_bound
;
234 /* Initialize new SRLB */
235 if (sr_local_block_init(area
) != 0)
238 /* Reinstall local Adjacency-SIDs with new labels. */
239 for (ALL_LIST_ELEMENTS(area
->srdb
.adj_sids
, node
, nnode
, sra
))
240 sr_adj_sid_update(sra
, &srdb
->srlb
);
242 /* Update and Flood LSP */
243 lsp_regenerate_schedule(area
, area
->is_type
, 0);
244 } else if (srdb
->config
.enabled
) {
245 /* Try to enable SR again using the new SRLB. */
253 * Add new Prefix-SID configuration to the SRDB.
255 * @param area IS-IS area
256 * @param prefix Prefix to be added
258 * @return Newly added Prefix-SID configuration structure
260 struct sr_prefix_cfg
*isis_sr_cfg_prefix_add(struct isis_area
*area
,
261 const struct prefix
*prefix
)
263 struct sr_prefix_cfg
*pcfg
;
264 struct interface
*ifp
;
266 sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area
->area_tag
, prefix
);
268 pcfg
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*pcfg
));
269 pcfg
->prefix
= *prefix
;
272 /* Pull defaults from the YANG module. */
273 pcfg
->sid_type
= yang_get_default_enum(
274 "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR
);
275 pcfg
->last_hop_behavior
= yang_get_default_enum(
276 "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR
);
278 /* Set the N-flag when appropriate. */
279 ifp
= if_lookup_prefix(prefix
, VRF_DEFAULT
);
280 if (ifp
&& sr_prefix_is_node_sid(ifp
, prefix
))
281 pcfg
->node_sid
= true;
283 /* Save prefix-sid configuration. */
284 srdb_prefix_cfg_add(&area
->srdb
.config
.prefix_sids
, pcfg
);
290 * Removal of locally configured Prefix-SID.
292 * @param pcfg Configured Prefix-SID
294 void isis_sr_cfg_prefix_del(struct sr_prefix_cfg
*pcfg
)
296 struct isis_area
*area
= pcfg
->area
;
298 sr_debug("ISIS-Sr (%s): Delete local Prefix-SID %pFX %s %u",
299 area
->area_tag
, &pcfg
->prefix
,
300 pcfg
->sid_type
== SR_SID_VALUE_TYPE_INDEX
? "index" : "label",
303 srdb_prefix_cfg_del(&area
->srdb
.config
.prefix_sids
, pcfg
);
304 XFREE(MTYPE_ISIS_SR_INFO
, pcfg
);
308 * Lookup for Prefix-SID in the local configuration.
310 * @param area IS-IS area
311 * @param prefix Prefix to lookup
313 * @return Configured Prefix-SID structure if found, NULL otherwise
315 struct sr_prefix_cfg
*isis_sr_cfg_prefix_find(struct isis_area
*area
,
316 union prefixconstptr prefix
)
318 struct sr_prefix_cfg pcfg
= {};
320 prefix_copy(&pcfg
.prefix
, prefix
.p
);
321 return srdb_prefix_cfg_find(&area
->srdb
.config
.prefix_sids
, &pcfg
);
325 * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
327 * @param pcfg Prefix-SID configuration
328 * @param external False if prefix is locally configured, true otherwise
329 * @param psid Prefix-SID sub-TLV to be updated
331 void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg
*pcfg
, bool external
,
332 struct isis_prefix_sid
*psid
)
334 /* Set SID algorithm. */
335 psid
->algorithm
= SR_ALGORITHM_SPF
;
339 switch (pcfg
->last_hop_behavior
) {
340 case SR_LAST_HOP_BEHAVIOR_EXP_NULL
:
341 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
342 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
344 case SR_LAST_HOP_BEHAVIOR_NO_PHP
:
345 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
346 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
348 case SR_LAST_HOP_BEHAVIOR_PHP
:
349 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NO_PHP
);
350 UNSET_FLAG(psid
->flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
);
354 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_READVERTISED
);
356 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_NODE
);
359 psid
->value
= pcfg
->sid
;
360 if (pcfg
->sid_type
== SR_SID_VALUE_TYPE_ABSOLUTE
) {
361 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_VALUE
);
362 SET_FLAG(psid
->flags
, ISIS_PREFIX_SID_LOCAL
);
366 /* --- Segment Routing Prefix Management functions -------------------------- */
369 * Add Segment Routing Prefix to a given Segment Routing Node.
371 * @param area IS-IS area
372 * @param srn Segment Routing Node
373 * @param prefix Prefix to be added
374 * @param local True if prefix is locally configured, false otherwise
375 * @param psid Prefix-SID sub-TLVs
377 * @return New Segment Routing Prefix structure
379 static struct sr_prefix
*sr_prefix_add(struct isis_area
*area
,
381 union prefixconstptr prefix
, bool local
,
382 const struct isis_prefix_sid
*psid
)
384 struct sr_prefix
*srp
;
386 srp
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*srp
));
387 prefix_copy(&srp
->prefix
, prefix
.p
);
389 srp
->input_label
= MPLS_INVALID_LABEL
;
391 srp
->type
= ISIS_SR_PREFIX_LOCAL
;
392 isis_sr_nexthop_reset(&srp
->u
.local
.info
);
394 srp
->type
= ISIS_SR_PREFIX_REMOTE
;
395 srp
->u
.remote
.rinfo
= NULL
;
398 srdb_node_prefix_add(&srn
->prefix_sids
, srp
);
399 /* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
400 srdb_area_prefix_add(&area
->srdb
.prefix_sids
[srn
->level
- 1], srp
);
402 sr_debug(" |- Added new SR Prefix-SID %pFX %s %u to SR Node %s",
403 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
404 srp
->sid
.value
, sysid_print(srn
->sysid
));
410 * Remove given Segment Prefix from given Segment Routing Node.
411 * Prefix-SID is un-installed first.
413 * @param area IS-IS area
414 * @param srn Segment Routing Node
415 * @param srp Segment Routing Prefix
417 static void sr_prefix_del(struct isis_area
*area
, struct sr_node
*srn
,
418 struct sr_prefix
*srp
)
420 sr_debug(" |- Delete SR Prefix-SID %pFX %s %u to SR Node %s",
421 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
422 srp
->sid
.value
, sysid_print(srn
->sysid
));
424 sr_prefix_uninstall(srp
);
425 srdb_node_prefix_del(&srn
->prefix_sids
, srp
);
426 srdb_area_prefix_del(&area
->srdb
.prefix_sids
[srn
->level
- 1], srp
);
427 XFREE(MTYPE_ISIS_SR_INFO
, srp
);
431 * Find Segment Routing Prefix by Area.
433 * @param area IS-IS area
434 * @param level IS-IS level
435 * @param prefix Prefix to lookup
437 * @return Segment Routing Prefix structure if found, NULL otherwise
439 static struct sr_prefix
*sr_prefix_find_by_area(struct isis_area
*area
,
441 union prefixconstptr prefix
)
443 struct sr_prefix srp
= {};
445 prefix_copy(&srp
.prefix
, prefix
.p
);
446 return srdb_area_prefix_find(&area
->srdb
.prefix_sids
[level
- 1], &srp
);
450 * Find Segment Routing Prefix by Segment Routing Node.
452 * @param srn Segment Routing Node
453 * @param prefix Prefix to lookup
455 * @return Segment Routing Prefix structure if found, NULL otherwise
457 static struct sr_prefix
*sr_prefix_find_by_node(struct sr_node
*srn
,
458 union prefixconstptr prefix
)
460 struct sr_prefix srp
= {};
462 prefix_copy(&srp
.prefix
, prefix
.p
);
463 return srdb_node_prefix_find(&srn
->prefix_sids
, &srp
);
466 /* --- Segment Routing Node Management functions ---------------------------- */
469 * Add Segment Routing Node to the Segment Routing Data Base.
471 * @param area IS-IS area
472 * @param level IS-IS level
473 * @param sysid Node System ID
474 * @param cap Segment Routing Capability sub-TLVs
476 * @return New Segment Routing Node structure
478 static struct sr_node
*sr_node_add(struct isis_area
*area
, int level
,
479 const uint8_t *sysid
)
483 srn
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*srn
));
485 memcpy(srn
->sysid
, sysid
, ISIS_SYS_ID_LEN
);
487 srdb_node_prefix_init(&srn
->prefix_sids
);
488 srdb_node_add(&area
->srdb
.sr_nodes
[level
- 1], srn
);
490 sr_debug(" |- Added new SR Node %s", sysid_print(srn
->sysid
));
495 static void sr_node_del(struct isis_area
*area
, int level
, struct sr_node
*srn
)
497 * Remove Segment Routing Node from the Segment Routing Data Base.
498 * All Prefix-SID attached to this Segment Routing Node are removed first.
500 * @param area IS-IS area
501 * @param level IS-IS level
502 * @param srn Segment Routing Node to be deleted
506 sr_debug(" |- Delete SR Node %s", sysid_print(srn
->sysid
));
508 /* Remove and uninstall Prefix-SIDs. */
509 while (srdb_node_prefix_count(&srn
->prefix_sids
) > 0) {
510 struct sr_prefix
*srp
;
512 srp
= srdb_node_prefix_first(&srn
->prefix_sids
);
513 sr_prefix_del(area
, srn
, srp
);
516 srdb_node_del(&area
->srdb
.sr_nodes
[level
- 1], srn
);
517 XFREE(MTYPE_ISIS_SR_INFO
, srn
);
521 * Find Segment Routing Node in the Segment Routing Data Base per system ID.
523 * @param area IS-IS area
524 * @param level IS-IS level
525 * @param sysid Node System ID to lookup
527 * @return Segment Routing Node structure if found, NULL otherwise
529 static struct sr_node
*sr_node_find(struct isis_area
*area
, int level
,
530 const uint8_t *sysid
)
532 struct sr_node srn
= {};
534 memcpy(srn
.sysid
, sysid
, ISIS_SYS_ID_LEN
);
535 return srdb_node_find(&area
->srdb
.sr_nodes
[level
- 1], &srn
);
539 * Update Segment Routing Node following an SRGB update. This function
540 * is called when a neighbor SR Node has updated its SRGB.
542 * @param area IS-IS area
543 * @param level IS-IS level
544 * @param sysid Segment Routing Node system ID
546 static void sr_node_srgb_update(struct isis_area
*area
, int level
,
549 struct sr_prefix
*srp
;
551 sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
554 frr_each (srdb_area_prefix
, &area
->srdb
.prefix_sids
[level
- 1], srp
) {
555 struct listnode
*node
;
556 struct isis_nexthop
*nh
;
558 if (srp
->type
== ISIS_SR_PREFIX_LOCAL
)
561 if (srp
->u
.remote
.rinfo
== NULL
)
564 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
, node
,
566 if (memcmp(nh
->sysid
, sysid
, ISIS_SYS_ID_LEN
) != 0)
570 * The Prefix-SID input label hasn't changed. We could
571 * re-install all Prefix-SID with "Make Before Break"
572 * option. Zebra layer will update output label(s) by
573 * adding new entry before removing the old one(s).
575 sr_prefix_reinstall(srp
, true);
581 /* --- Segment Routing Nexthop information Management functions ------------- */
584 * Update Segment Routing Nexthop.
586 * @param srnh Segment Routing next hop
587 * @param label Output MPLS label
589 void isis_sr_nexthop_update(struct sr_nexthop_info
*srnh
, mpls_label_t label
)
592 if (srnh
->uptime
== 0)
593 srnh
->uptime
= time(NULL
);
597 * Reset Segment Routing Nexthop.
599 * @param srnh Segment Routing Nexthop
601 void isis_sr_nexthop_reset(struct sr_nexthop_info
*srnh
)
603 srnh
->label
= MPLS_INVALID_LABEL
;
607 /* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
610 * Lookup IS-IS route in the Shortest Path Tree.
612 * @param area IS-IS area
613 * @param tree_id Shortest Path Tree identifier
614 * @param srp Segment Routing Prefix to lookup
616 * @return Route Information for this prefix if found, NULL otherwise
618 static struct isis_route_info
*sr_prefix_lookup_route(struct isis_area
*area
,
619 enum spf_tree_id tree_id
,
620 struct sr_prefix
*srp
)
622 struct route_node
*rn
;
623 int level
= srp
->srn
->level
;
625 rn
= route_node_lookup(area
->spftree
[tree_id
][level
- 1]->route_table
,
628 route_unlock_node(rn
);
637 * Compute input label for the given Prefix-SID.
639 * @param srp Segment Routing Prefix
641 * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
643 static mpls_label_t
sr_prefix_in_label(const struct sr_prefix
*srp
)
645 const struct sr_node
*srn
= srp
->srn
;
646 struct isis_area
*area
= srn
->area
;
648 /* Return SID value as MPLS label if it is an Absolute SID */
649 if (CHECK_FLAG(srp
->sid
.flags
,
650 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
))
651 return srp
->sid
.value
;
653 /* Check that SID index falls inside the SRGB */
654 if (srp
->sid
.value
>= (area
->srdb
.config
.srgb_upper_bound
655 - area
->srdb
.config
.srgb_lower_bound
+ 1)) {
656 flog_warn(EC_ISIS_SID_OVERFLOW
,
657 "%s: SID index %u falls outside local SRGB range",
658 __func__
, srp
->sid
.value
);
659 return MPLS_INVALID_LABEL
;
662 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
663 return (area
->srdb
.config
.srgb_lower_bound
+ srp
->sid
.value
);
667 * Compute output label for the given Prefix-SID.
669 * @param srp Segment Routing Prefix
670 * @param srn_nexthop Segment Routing nexthop node
671 * @param sysid System ID of the SR node which advertised the Prefix-SID
673 * @return MPLS label or MPLS_INVALID_LABEL in case of error
675 static mpls_label_t
sr_prefix_out_label(const struct sr_prefix
*srp
,
676 const struct sr_node
*srn_nexthop
,
677 const uint8_t *sysid
)
679 const struct sr_node
*srn
= srp
->srn
;
681 /* Check if the nexthop SR Node is the last hop? */
682 if (memcmp(sysid
, srn
->sysid
, ISIS_SYS_ID_LEN
) == 0) {
683 /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
684 if (!CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_NO_PHP
))
685 return MPLS_LABEL_IMPLICIT_NULL
;
687 /* SR-Node requests Implicit NULL Label */
688 if (CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
)) {
689 if (srp
->prefix
.family
== AF_INET
)
690 return MPLS_LABEL_IPV4_EXPLICIT_NULL
;
692 return MPLS_LABEL_IPV6_EXPLICIT_NULL
;
697 /* Return SID value as MPLS label if it is an Absolute SID */
698 if (CHECK_FLAG(srp
->sid
.flags
,
699 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
)) {
701 * V/L SIDs have local significance, so only adjacent routers
702 * can use them (RFC8667 section #2.1.1.1)
704 if (srp
->srn
!= srn_nexthop
)
705 return MPLS_INVALID_LABEL
;
706 return srp
->sid
.value
;
709 /* Check that SID index falls inside the SRGB */
710 if (srp
->sid
.value
>= srn_nexthop
->cap
.srgb
.range_size
) {
711 flog_warn(EC_ISIS_SID_OVERFLOW
,
712 "%s: SID index %u falls outside remote SRGB range",
713 __func__
, srp
->sid
.value
);
714 return MPLS_INVALID_LABEL
;
717 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
718 return (srn_nexthop
->cap
.srgb
.lower_bound
+ srp
->sid
.value
);
722 * Process local Prefix-SID and install it if possible. Input label is
723 * computed before installing it in LFIB.
725 * @param srp Segment Routing Prefix
727 * @return 0 on success, -1 otherwise
729 static int sr_prefix_install_local(struct sr_prefix
*srp
)
731 mpls_label_t input_label
;
732 const struct sr_node
*srn
= srp
->srn
;
735 * No need to install Label for local Prefix-SID unless the
736 * no-PHP option is configured.
738 if (!CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_NO_PHP
)
739 || CHECK_FLAG(srp
->sid
.flags
, ISIS_PREFIX_SID_EXPLICIT_NULL
))
742 sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s) with nexthop self",
743 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
744 srp
->sid
.value
, circuit_t2string(srn
->level
));
746 /* Compute input label and check that is valid. */
747 input_label
= sr_prefix_in_label(srp
);
748 if (input_label
== MPLS_INVALID_LABEL
)
751 /* Update internal state. */
752 srp
->input_label
= input_label
;
753 isis_sr_nexthop_update(&srp
->u
.local
.info
, MPLS_LABEL_IMPLICIT_NULL
);
755 /* Install Prefix-SID in the forwarding plane. */
756 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE
, srp
);
762 * Process remote Prefix-SID and install it if possible. Input and Output
763 * labels are computed before installing them in LFIB.
765 * @param srp Segment Routing Prefix
767 * @return 0 on success, -1 otherwise
769 static int sr_prefix_install_remote(struct sr_prefix
*srp
)
771 const struct sr_node
*srn
= srp
->srn
;
772 struct isis_area
*area
= srn
->area
;
773 enum spf_tree_id tree_id
;
774 struct listnode
*node
;
775 struct isis_nexthop
*nexthop
;
776 mpls_label_t input_label
;
777 size_t nexthop_num
= 0;
779 /* Lookup to associated IS-IS route. */
780 tree_id
= (srp
->prefix
.family
== AF_INET
) ? SPFTREE_IPV4
: SPFTREE_IPV6
;
781 srp
->u
.remote
.rinfo
= sr_prefix_lookup_route(area
, tree_id
, srp
);
782 if (!srp
->u
.remote
.rinfo
)
783 /* SPF hasn't converged for this route yet. */
786 /* Compute input label and check that is valid. */
787 input_label
= sr_prefix_in_label(srp
);
788 if (input_label
== MPLS_INVALID_LABEL
)
791 sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s)", &srp
->prefix
,
792 IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
793 srp
->sid
.value
, circuit_t2string(srn
->level
));
795 /* Process all SPF nexthops */
796 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
, node
,
798 struct sr_node
*srn_nexthop
;
799 mpls_label_t output_label
;
801 /* Check if the nexthop advertised a SRGB. */
802 srn_nexthop
= sr_node_find(area
, srn
->level
, nexthop
->sysid
);
807 * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
810 if ((nexthop
->family
== AF_INET
811 && !IS_SR_IPV4(srn_nexthop
->cap
.srgb
))
812 || (nexthop
->family
== AF_INET6
813 && !IS_SR_IPV6(srn_nexthop
->cap
.srgb
)))
816 /* Compute output label and check if it is valid */
818 sr_prefix_out_label(srp
, srn_nexthop
, nexthop
->sysid
);
819 if (output_label
== MPLS_INVALID_LABEL
)
823 static char buf
[INET6_ADDRSTRLEN
];
825 inet_ntop(nexthop
->family
, &nexthop
->ip
, buf
,
827 zlog_debug(" |- nexthop %s label %u", buf
,
831 isis_sr_nexthop_update(&nexthop
->sr
, output_label
);
835 isis_sr_nexthop_reset(&nexthop
->sr
);
838 /* Check that we found at least one valid nexthop */
839 if (nexthop_num
== 0) {
840 sr_debug(" |- no valid nexthops");
844 /* Update internal state. */
845 srp
->input_label
= input_label
;
847 /* Install Prefix-SID in the forwarding plane. */
848 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE
, srp
);
854 * Process local or remote Prefix-SID and install it if possible.
856 * @param srp Segment Routing Prefix
858 static void sr_prefix_install(struct sr_prefix
*srp
)
860 const struct sr_node
*srn
= srp
->srn
;
861 struct isis_area
*area
= srn
->area
;
864 sr_debug("ISIS-Sr (%s): Install Prefix-SID %pFX %s %u", area
->area_tag
,
865 &srp
->prefix
, IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
868 /* L1 routes are preferred over the L2 ones. */
869 if (area
->is_type
== IS_LEVEL_1_AND_2
) {
870 struct sr_prefix
*srp_l1
, *srp_l2
;
872 switch (srn
->level
) {
874 srp_l2
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
,
877 sr_prefix_uninstall(srp_l2
);
880 srp_l1
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
,
890 /* Install corresponding LFIB entry */
891 if (srp
->type
== ISIS_SR_PREFIX_LOCAL
)
892 ret
= sr_prefix_install_local(srp
);
894 ret
= sr_prefix_install_remote(srp
);
896 sr_prefix_uninstall(srp
);
900 * Uninstall local or remote Prefix-SID.
902 * @param srp Segment Routing Prefix
904 static void sr_prefix_uninstall(struct sr_prefix
*srp
)
906 struct listnode
*node
;
907 struct isis_nexthop
*nexthop
;
909 /* Check that Input Label is valid */
910 if (srp
->input_label
== MPLS_INVALID_LABEL
)
913 sr_debug("ISIS-Sr: Un-install Prefix-SID %pFX %s %u", &srp
->prefix
,
914 IS_SID_VALUE(srp
->sid
.flags
) ? "label" : "index",
917 /* Uninstall Prefix-SID from the forwarding plane. */
918 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE
, srp
);
920 /* Reset internal state. */
921 srp
->input_label
= MPLS_INVALID_LABEL
;
923 case ISIS_SR_PREFIX_LOCAL
:
924 isis_sr_nexthop_reset(&srp
->u
.local
.info
);
926 case ISIS_SR_PREFIX_REMOTE
:
927 if (srp
->u
.remote
.rinfo
) {
928 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
,
930 isis_sr_nexthop_reset(&nexthop
->sr
);
937 * Reinstall local or remote Prefix-SID.
939 * @param srp Segment Routing Prefix
941 static inline void sr_prefix_reinstall(struct sr_prefix
*srp
,
942 bool make_before_break
)
945 * Make Before Break can be used only when we know for sure that
946 * the Prefix-SID input label hasn't changed. Otherwise we need to
947 * uninstall the Prefix-SID first using the old input label before
950 if (!make_before_break
)
951 sr_prefix_uninstall(srp
);
953 /* New input label is computed in sr_prefix_install() function */
954 sr_prefix_install(srp
);
957 /* --- IS-IS LSP Parse functions -------------------------------------------- */
960 * Compare Router Capabilities. Only Flags, SRGB and Algorithm are used for the
961 * comparison. MSD and SRLB modification must not trigger and SR-Prefix update.
963 * @param r1 First Router Capabilities to compare
964 * @param r2 Second Router Capabilities to compare
965 * @return 0 if r1 and r2 are equal or -1 otherwise
967 static int router_cap_cmp(const struct isis_router_cap
*r1
,
968 const struct isis_router_cap
*r2
)
970 if (r1
->flags
== r2
->flags
971 && r1
->srgb
.lower_bound
== r2
->srgb
.lower_bound
972 && r1
->srgb
.range_size
== r2
->srgb
.range_size
973 && r1
->algo
[0] == r2
->algo
[0])
980 * Parse all SR-related information from the given Router Capabilities TLV.
982 * @param area IS-IS area
983 * @param level IS-IS level
984 * @param sysid System ID of the LSP
985 * @param router_cap Router Capability subTLVs
987 * @return Segment Routing Node structure for this System ID
989 static struct sr_node
*
990 parse_router_cap_tlv(struct isis_area
*area
, int level
, const uint8_t *sysid
,
991 const struct isis_router_cap
*router_cap
)
995 if (!router_cap
|| router_cap
->srgb
.range_size
== 0)
998 sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area
->area_tag
);
1000 srn
= sr_node_find(area
, level
, sysid
);
1002 if (router_cap_cmp(&srn
->cap
, router_cap
) != 0) {
1003 srn
->state
= SRDB_STATE_MODIFIED
;
1005 srn
->state
= SRDB_STATE_UNCHANGED
;
1006 sr_debug(" |- Found %s SR Node %s",
1007 srn
->state
== SRDB_STATE_MODIFIED
? "Modified"
1009 sysid_print(srn
->sysid
));
1011 srn
= sr_node_add(area
, level
, sysid
);
1012 srn
->state
= SRDB_STATE_NEW
;
1016 * Update Router Capabilities in any case as SRLB or MSD
1017 * modification are not take into account for comparison.
1019 srn
->cap
= *router_cap
;
1025 * Parse list of Prefix-SID Sub-TLVs.
1027 * @param srn Segment Routing Node
1028 * @param prefix Prefix to be parsed
1029 * @param local True if prefix comes from own LSP, false otherwise
1030 * @param prefix_sids Prefix SID subTLVs
1032 static void parse_prefix_sid_subtlvs(struct sr_node
*srn
,
1033 union prefixconstptr prefix
, bool local
,
1034 struct isis_item_list
*prefix_sids
)
1036 struct isis_area
*area
= srn
->area
;
1037 struct isis_item
*i
;
1039 sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area
->area_tag
);
1041 /* Parse list of Prefix SID subTLVs */
1042 for (i
= prefix_sids
->head
; i
; i
= i
->next
) {
1043 struct isis_prefix_sid
*psid
= (struct isis_prefix_sid
*)i
;
1044 struct sr_prefix
*srp
;
1046 /* Only SPF algorithm is supported right now */
1047 if (psid
->algorithm
!= SR_ALGORITHM_SPF
)
1050 /* Compute corresponding Segment Routing Prefix */
1051 srp
= sr_prefix_find_by_node(srn
, prefix
);
1053 if (srp
->sid
.flags
!= psid
->flags
1054 || srp
->sid
.algorithm
!= psid
->algorithm
1055 || srp
->sid
.value
!= psid
->value
) {
1057 srp
->state
= SRDB_STATE_MODIFIED
;
1059 srp
->state
= SRDB_STATE_UNCHANGED
;
1060 sr_debug(" |- Found %s Prefix-SID %pFX",
1061 srp
->state
== SRDB_STATE_MODIFIED
1067 srp
= sr_prefix_add(area
, srn
, prefix
, local
, psid
);
1068 srp
->state
= SRDB_STATE_NEW
;
1071 * Stop the Prefix-SID iteration since we only support the SPF
1072 * algorithm for now.
1079 * Parse all SR-related information from the given LSP.
1081 * @param area IS-IS area
1082 * @param level IS-IS level
1083 * @param srn Segment Routing Node
1084 * @param lsp IS-IS LSP
1086 static void parse_lsp(struct isis_area
*area
, int level
, struct sr_node
**srn
,
1087 struct isis_lsp
*lsp
)
1089 struct isis_item_list
*items
;
1090 struct isis_item
*i
;
1091 bool local
= lsp
->own_lsp
;
1093 /* Check LSP sequence number */
1094 if (lsp
->hdr
.seqno
== 0) {
1095 zlog_warn("%s: lsp with 0 seq_num - ignore", __func__
);
1099 sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area
->area_tag
,
1100 sysid_print(lsp
->hdr
.lsp_id
));
1102 /* Parse the Router Capability TLV. */
1104 *srn
= parse_router_cap_tlv(area
, level
, lsp
->hdr
.lsp_id
,
1105 lsp
->tlvs
->router_cap
);
1110 /* Parse the Extended IP Reachability TLV. */
1111 items
= &lsp
->tlvs
->extended_ip_reach
;
1112 for (i
= items
->head
; i
; i
= i
->next
) {
1113 struct isis_extended_ip_reach
*ir
;
1115 ir
= (struct isis_extended_ip_reach
*)i
;
1119 parse_prefix_sid_subtlvs(*srn
, &ir
->prefix
, local
,
1120 &ir
->subtlvs
->prefix_sids
);
1123 /* Parse Multi Topology Reachable IPv6 Prefixes TLV. */
1124 items
= isis_lookup_mt_items(&lsp
->tlvs
->mt_ipv6_reach
,
1125 ISIS_MT_IPV6_UNICAST
);
1126 for (i
= items
? items
->head
: NULL
; i
; i
= i
->next
) {
1127 struct isis_ipv6_reach
*ir
;
1129 ir
= (struct isis_ipv6_reach
*)i
;
1133 parse_prefix_sid_subtlvs(*srn
, &ir
->prefix
, local
,
1134 &ir
->subtlvs
->prefix_sids
);
1139 * Parse all SR-related information from the entire LSPDB.
1141 * @param area IS-IS area
1143 static void parse_lspdb(struct isis_area
*area
)
1145 struct isis_lsp
*lsp
;
1147 sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area
->area_tag
);
1149 /* Process all LSP from Level 1 & 2 */
1150 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
1151 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
) {
1152 struct isis_lsp
*frag
;
1153 struct listnode
*node
;
1154 struct sr_node
*srn
= NULL
;
1156 /* Skip Pseudo ID LSP and LSP without TLVs */
1157 if (LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
))
1162 /* Parse LSP, then fragment */
1163 parse_lsp(area
, level
, &srn
, lsp
);
1164 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
))
1165 parse_lsp(area
, level
, &srn
, frag
);
1171 * Process any new/deleted/modified Prefix-SID in the LSPDB.
1173 * @param srn Segment Routing Node
1174 * @param srp Segment Routing Prefix
1176 static void process_prefix_changes(struct sr_node
*srn
, struct sr_prefix
*srp
)
1178 struct isis_area
*area
= srn
->area
;
1180 /* Install/reinstall/uninstall Prefix-SID if necessary. */
1181 switch (srp
->state
) {
1182 case SRDB_STATE_NEW
:
1183 sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
1184 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1185 sr_prefix_install(srp
);
1187 case SRDB_STATE_MODIFIED
:
1189 "ISIS-Sr (%s): Modified Prefix-SID %pFX for SR node %s",
1190 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1191 sr_prefix_reinstall(srp
, false);
1193 case SRDB_STATE_UNCHANGED
:
1196 sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
1197 area
->area_tag
, &srp
->prefix
, sysid_print(srn
->sysid
));
1198 sr_prefix_del(area
, srn
, srp
);
1202 /* Validate SRDB State for next LSPDB parsing */
1203 srp
->state
= SRDB_STATE_VALIDATED
;
1207 * Process any new/deleted/modified SRGB in the LSPDB.
1209 * @param area IS-IS area
1210 * @param level IS-IS level
1211 * @param srn Segment Routing Node
1213 static void process_node_changes(struct isis_area
*area
, int level
,
1214 struct sr_node
*srn
)
1216 struct sr_prefix
*srp
;
1217 uint8_t sysid
[ISIS_SYS_ID_LEN
];
1220 memcpy(sysid
, srn
->sysid
, sizeof(sysid
));
1223 * If an neighbor router's SRGB was changed or created, then reinstall
1224 * all Prefix-SIDs from all nodes that use this neighbor as nexthop.
1226 adjacent
= isis_adj_exists(area
, level
, sysid
);
1227 switch (srn
->state
) {
1228 case SRDB_STATE_NEW
:
1229 case SRDB_STATE_MODIFIED
:
1230 sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
1231 area
->area_tag
, sysid_print(srn
->sysid
));
1233 sr_node_srgb_update(area
, level
, sysid
);
1235 case SRDB_STATE_UNCHANGED
:
1238 /* SR capabilities have been removed. Delete SR-Node */
1239 sr_debug("ISIS-Sr (%s): Remove SR node %s", area
->area_tag
,
1240 sysid_print(srn
->sysid
));
1242 sr_node_del(area
, level
, srn
);
1243 /* and Update remaining Prefix-SID from all remaining SR Node */
1245 sr_node_srgb_update(area
, level
, sysid
);
1249 /* Validate SRDB State for next LSPDB parsing */
1250 srn
->state
= SRDB_STATE_VALIDATED
;
1252 /* Finally, process all Prefix-SID of this SR Node */
1253 frr_each_safe (srdb_node_prefix
, &srn
->prefix_sids
, srp
)
1254 process_prefix_changes(srn
, srp
);
1258 * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
1260 * @param area IS-IS area
1262 void isis_area_verify_sr(struct isis_area
*area
)
1264 struct sr_node
*srn
;
1266 if (!area
->srdb
.enabled
)
1269 /* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
1272 /* Process possible SR-related changes in the LDPSB. */
1273 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
1274 frr_each_safe (srdb_node
, &area
->srdb
.sr_nodes
[level
- 1], srn
)
1275 process_node_changes(area
, level
, srn
);
1280 * Once a route is updated in the SPT, reinstall or uninstall its corresponding
1281 * Prefix-SID (if any).
1283 * @param area IS-IS area
1284 * @param prefix Prefix to be updated
1285 * @param route_info New Route Information
1289 static int sr_route_update(struct isis_area
*area
, struct prefix
*prefix
,
1290 struct isis_route_info
*route_info
)
1292 struct sr_prefix
*srp
;
1294 if (!area
->srdb
.enabled
)
1297 sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area
->area_tag
,
1300 /* Lookup to Segment Routing Prefix for this prefix */
1301 switch (area
->is_type
) {
1303 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
, prefix
);
1306 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
, prefix
);
1308 case IS_LEVEL_1_AND_2
:
1309 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL1
, prefix
);
1311 srp
= sr_prefix_find_by_area(area
, ISIS_LEVEL2
, prefix
);
1314 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown area level",
1319 /* Skip NULL or local Segment Routing Prefix */
1320 if (!srp
|| srp
->type
== ISIS_SR_PREFIX_LOCAL
)
1323 /* Install or unintall Prefix-SID if route is Active or not */
1324 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)) {
1326 * The Prefix-SID input label hasn't changed. We could use the
1327 * "Make Before Break" option. Zebra layer will update output
1328 * label by adding new label(s) before removing old one(s).
1330 sr_prefix_reinstall(srp
, true);
1331 srp
->u
.remote
.rinfo
= route_info
;
1333 sr_prefix_uninstall(srp
);
1334 srp
->u
.remote
.rinfo
= NULL
;
1340 /* --- Segment Routing Local Block management functions --------------------- */
1343 * Initialize Segment Routing Local Block from SRDB configuration and reserve
1344 * block of bits to manage label allocation.
1346 * @param area IS-IS area
1348 static int sr_local_block_init(struct isis_area
*area
)
1350 struct isis_sr_db
*srdb
= &area
->srdb
;
1351 struct sr_local_block
*srlb
= &srdb
->srlb
;
1353 /* Check if SRLB is not already configured */
1358 * Request SRLB to the label manager. If the allocation fails, return
1359 * an error to disable SR until a new SRLB is successfully allocated.
1361 if (isis_zebra_request_label_range(
1362 srdb
->config
.srlb_lower_bound
,
1363 srdb
->config
.srlb_upper_bound
1364 - srdb
->config
.srlb_lower_bound
+ 1)) {
1365 srlb
->active
= false;
1369 sr_debug("ISIS-Sr (%s): Got new SRLB [%u/%u]", area
->area_tag
,
1370 srdb
->config
.srlb_lower_bound
, srdb
->config
.srlb_upper_bound
);
1372 /* Initialize the SRLB */
1373 srlb
->start
= srdb
->config
.srlb_lower_bound
;
1374 srlb
->end
= srdb
->config
.srlb_upper_bound
;
1376 /* Compute the needed Used Mark number and allocate them */
1377 srlb
->max_block
= (srlb
->end
- srlb
->start
+ 1) / SRLB_BLOCK_SIZE
;
1378 if (((srlb
->end
- srlb
->start
+ 1) % SRLB_BLOCK_SIZE
) != 0)
1380 srlb
->used_mark
= XCALLOC(MTYPE_ISIS_SR_INFO
,
1381 srlb
->max_block
* SRLB_BLOCK_SIZE
);
1382 srlb
->active
= true;
1388 * Remove Segment Routing Local Block.
1390 * @param area IS-IS area
1392 static void sr_local_block_delete(struct isis_area
*area
)
1394 struct isis_sr_db
*srdb
= &area
->srdb
;
1395 struct sr_local_block
*srlb
= &srdb
->srlb
;
1397 /* Check if SRLB is not already delete */
1401 sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area
->area_tag
,
1402 srlb
->start
, srlb
->end
);
1404 /* First release the label block */
1405 isis_zebra_release_label_range(srdb
->config
.srlb_lower_bound
,
1406 srdb
->config
.srlb_upper_bound
);
1408 /* Then reset SRLB structure */
1409 if (srlb
->used_mark
!= NULL
)
1410 XFREE(MTYPE_ISIS_SR_INFO
, srlb
->used_mark
);
1411 srlb
->active
= false;
1415 * Request a label from the Segment Routing Local Block.
1417 * @param srlb Segment Routing Local Block
1419 * @return First available label on success or MPLS_INVALID_LABEL if the
1420 * block of labels is full
1422 static mpls_label_t
sr_local_block_request_label(struct sr_local_block
*srlb
)
1429 /* Check if we ran out of available labels */
1430 if (srlb
->current
>= srlb
->end
)
1431 return MPLS_INVALID_LABEL
;
1433 /* Get first available label and mark it used */
1434 label
= srlb
->current
+ srlb
->start
;
1435 index
= srlb
->current
/ SRLB_BLOCK_SIZE
;
1436 pos
= 1ULL << (srlb
->current
% SRLB_BLOCK_SIZE
);
1437 srlb
->used_mark
[index
] |= pos
;
1439 /* Jump to the next free position */
1441 pos
= srlb
->current
% SRLB_BLOCK_SIZE
;
1442 while (srlb
->current
< srlb
->end
) {
1445 if (!((1ULL << pos
) & srlb
->used_mark
[index
]))
1449 pos
= srlb
->current
% SRLB_BLOCK_SIZE
;
1457 * Release label in the Segment Routing Local Block.
1459 * @param srlb Segment Routing Local Block
1460 * @param label Label to be release
1462 * @return 0 on success or -1 if label falls outside SRLB
1464 static int sr_local_block_release_label(struct sr_local_block
*srlb
,
1470 /* Check that label falls inside the SRLB */
1471 if ((label
< srlb
->start
) || (label
> srlb
->end
)) {
1472 flog_warn(EC_ISIS_SID_OVERFLOW
,
1473 "%s: Returning label %u is outside SRLB [%u/%u]",
1474 __func__
, label
, srlb
->start
, srlb
->end
);
1478 index
= (label
- srlb
->start
) / SRLB_BLOCK_SIZE
;
1479 pos
= 1ULL << ((label
- srlb
->start
) % SRLB_BLOCK_SIZE
);
1480 srlb
->used_mark
[index
] &= ~pos
;
1481 /* Reset current to the first available position */
1482 for (index
= 0; index
< srlb
->max_block
; index
++) {
1483 if (srlb
->used_mark
[index
] != 0xFFFFFFFFFFFFFFFF) {
1484 for (pos
= 0; pos
< SRLB_BLOCK_SIZE
; pos
++)
1485 if (!((1ULL << pos
) & srlb
->used_mark
[index
])) {
1487 index
* SRLB_BLOCK_SIZE
+ pos
;
1497 /* --- Segment Routing Adjacency-SID management functions ------------------- */
1500 * Add new local Adjacency-SID.
1502 * @param adj IS-IS Adjacency
1503 * @param family Inet Family (IPv4 or IPv6)
1504 * @param backup True to initialize backup Adjacency SID
1506 static void sr_adj_sid_add_single(struct isis_adjacency
*adj
, int family
,
1509 struct isis_circuit
*circuit
= adj
->circuit
;
1510 struct isis_area
*area
= circuit
->area
;
1511 struct sr_adjacency
*sra
;
1512 struct isis_adj_sid
*adj_sid
;
1513 struct isis_lan_adj_sid
*ladj_sid
;
1514 union g_addr nexthop
= {};
1516 mpls_label_t input_label
;
1518 sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area
->area_tag
,
1519 backup
? "Backup" : "Primary");
1521 /* Determine nexthop IP address */
1524 if (!circuit
->ip_router
)
1527 nexthop
.ipv4
= adj
->ipv4_addresses
[0];
1530 if (!circuit
->ipv6_router
)
1533 nexthop
.ipv6
= adj
->ipv6_addresses
[0];
1536 flog_err(EC_LIB_DEVELOPMENT
,
1537 "%s: unexpected address-family: %u", __func__
, family
);
1541 /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
1542 flags
= EXT_SUBTLV_LINK_ADJ_SID_VFLG
| EXT_SUBTLV_LINK_ADJ_SID_LFLG
;
1543 if (family
== AF_INET6
)
1544 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_FFLG
);
1546 SET_FLAG(flags
, EXT_SUBTLV_LINK_ADJ_SID_BFLG
);
1548 /* Get a label from the SRLB for this Adjacency */
1549 input_label
= sr_local_block_request_label(&area
->srdb
.srlb
);
1550 if (input_label
== MPLS_INVALID_LABEL
)
1553 if (circuit
->ext
== NULL
)
1554 circuit
->ext
= isis_alloc_ext_subtlvs();
1556 sra
= XCALLOC(MTYPE_ISIS_SR_INFO
, sizeof(*sra
));
1557 sra
->type
= backup
? ISIS_SR_LAN_BACKUP
: ISIS_SR_ADJ_NORMAL
;
1558 sra
->nexthop
.family
= family
;
1559 sra
->nexthop
.address
= nexthop
;
1560 sra
->nexthop
.label
= input_label
;
1561 switch (circuit
->circ_type
) {
1562 /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
1563 case CIRCUIT_T_BROADCAST
:
1564 ladj_sid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*ladj_sid
));
1565 ladj_sid
->family
= family
;
1566 ladj_sid
->flags
= flags
;
1567 ladj_sid
->weight
= 0;
1568 memcpy(ladj_sid
->neighbor_id
, adj
->sysid
,
1569 sizeof(ladj_sid
->neighbor_id
));
1570 ladj_sid
->sid
= input_label
;
1571 isis_tlvs_add_lan_adj_sid(circuit
->ext
, ladj_sid
);
1572 sra
->u
.ladj_sid
= ladj_sid
;
1574 /* Adjacency-SID for Point to Point interface section #2.2.1 */
1576 adj_sid
= XCALLOC(MTYPE_ISIS_SUBTLV
, sizeof(*adj_sid
));
1577 adj_sid
->family
= family
;
1578 adj_sid
->flags
= flags
;
1579 adj_sid
->weight
= 0;
1580 adj_sid
->sid
= input_label
;
1581 isis_tlvs_add_adj_sid(circuit
->ext
, adj_sid
);
1582 sra
->u
.adj_sid
= adj_sid
;
1585 flog_err(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1586 __func__
, circuit
->circ_type
);
1590 /* Add Adjacency-SID in SRDB */
1592 listnode_add(area
->srdb
.adj_sids
, sra
);
1593 listnode_add(adj
->adj_sids
, sra
);
1595 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD
, sra
);
1599 * Add Primary and Backup local Adjacency SID.
1601 * @param adj IS-IS Adjacency
1602 * @param family Inet Family (IPv4 or IPv6)
1604 static void sr_adj_sid_add(struct isis_adjacency
*adj
, int family
)
1606 sr_adj_sid_add_single(adj
, family
, false);
1607 sr_adj_sid_add_single(adj
, family
, true);
1610 static void sr_adj_sid_update(struct sr_adjacency
*sra
,
1611 struct sr_local_block
*srlb
)
1613 struct isis_circuit
*circuit
= sra
->adj
->circuit
;
1615 /* First remove the old MPLS Label */
1616 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE
, sra
);
1618 /* Got new label in the new SRLB */
1619 sra
->nexthop
.label
= sr_local_block_request_label(srlb
);
1620 if (sra
->nexthop
.label
== MPLS_INVALID_LABEL
)
1623 switch (circuit
->circ_type
) {
1624 case CIRCUIT_T_BROADCAST
:
1625 sra
->u
.ladj_sid
->sid
= sra
->nexthop
.label
;
1628 sra
->u
.adj_sid
->sid
= sra
->nexthop
.label
;
1631 flog_warn(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1632 __func__
, circuit
->circ_type
);
1636 /* Finally configure the new MPLS Label */
1637 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD
, sra
);
1641 * Delete local Adj-SID.
1643 * @param sra Segment Routing Adjacency
1645 static void sr_adj_sid_del(struct sr_adjacency
*sra
)
1647 struct isis_circuit
*circuit
= sra
->adj
->circuit
;
1648 struct isis_area
*area
= circuit
->area
;
1650 sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area
->area_tag
);
1652 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE
, sra
);
1654 /* Release dynamic label and remove subTLVs */
1655 switch (circuit
->circ_type
) {
1656 case CIRCUIT_T_BROADCAST
:
1657 sr_local_block_release_label(&area
->srdb
.srlb
,
1658 sra
->u
.ladj_sid
->sid
);
1659 isis_tlvs_del_lan_adj_sid(circuit
->ext
, sra
->u
.ladj_sid
);
1662 sr_local_block_release_label(&area
->srdb
.srlb
,
1663 sra
->u
.adj_sid
->sid
);
1664 isis_tlvs_del_adj_sid(circuit
->ext
, sra
->u
.adj_sid
);
1667 flog_err(EC_LIB_DEVELOPMENT
, "%s: unexpected circuit type: %u",
1668 __func__
, circuit
->circ_type
);
1672 /* Remove Adjacency-SID from the SRDB */
1673 listnode_delete(area
->srdb
.adj_sids
, sra
);
1674 listnode_delete(sra
->adj
->adj_sids
, sra
);
1675 XFREE(MTYPE_ISIS_SR_INFO
, sra
);
1679 * Remove all Adjacency-SIDs associated to an adjacency that is going down.
1681 * @param adj IS-IS Adjacency
1685 static int sr_adj_state_change(struct isis_adjacency
*adj
)
1687 struct sr_adjacency
*sra
;
1688 struct listnode
*node
, *nnode
;
1690 if (!adj
->circuit
->area
->srdb
.enabled
)
1693 if (adj
->adj_state
== ISIS_ADJ_UP
)
1696 for (ALL_LIST_ELEMENTS(adj
->adj_sids
, node
, nnode
, sra
))
1697 sr_adj_sid_del(sra
);
1703 * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
1704 * IPv6 address to corresponding Adjacency-SID accordingly.
1706 * @param adj IS-IS Adjacency
1707 * @param family Inet Family (IPv4 or IPv6)
1711 static int sr_adj_ip_enabled(struct isis_adjacency
*adj
, int family
)
1713 if (!adj
->circuit
->area
->srdb
.enabled
)
1716 sr_adj_sid_add(adj
, family
);
1722 * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
1723 * delete the corresponding Adjacency-SID(s) accordingly.
1725 * @param adj IS-IS Adjacency
1726 * @param family Inet Family (IPv4 or IPv6)
1730 static int sr_adj_ip_disabled(struct isis_adjacency
*adj
, int family
)
1732 struct sr_adjacency
*sra
;
1733 struct listnode
*node
, *nnode
;
1735 if (!adj
->circuit
->area
->srdb
.enabled
)
1738 for (ALL_LIST_ELEMENTS(adj
->adj_sids
, node
, nnode
, sra
))
1739 if (sra
->nexthop
.family
== family
)
1740 sr_adj_sid_del(sra
);
1746 * Activate local Prefix-SID when loopback interface goes up for IS-IS.
1748 * @param ifp Loopback Interface
1752 static int sr_if_new_hook(struct interface
*ifp
)
1754 struct isis_circuit
*circuit
;
1755 struct isis_area
*area
;
1756 struct connected
*connected
;
1757 struct listnode
*node
;
1759 /* Get corresponding circuit */
1760 circuit
= circuit_scan_by_ifp(ifp
);
1764 area
= circuit
->area
;
1769 * Update the Node-SID flag of the configured Prefix-SID mappings if
1770 * necessary. This needs to be done here since isisd reads the startup
1771 * configuration before receiving interface information from zebra.
1773 FOR_ALL_INTERFACES_ADDRESSES (ifp
, connected
, node
) {
1774 struct sr_prefix_cfg
*pcfg
;
1776 pcfg
= isis_sr_cfg_prefix_find(area
, connected
->address
);
1780 if (sr_prefix_is_node_sid(ifp
, &pcfg
->prefix
)
1781 && !pcfg
->node_sid
) {
1782 pcfg
->node_sid
= true;
1783 lsp_regenerate_schedule(area
, area
->is_type
, 0);
1790 /* --- Segment Routing Show information functions --------------------------- */
1793 * Show LFIB operation in human readable format.
1795 * @param buf Buffer to store string output. Must be pre-allocate
1796 * @param size Size of the buffer
1797 * @param label_in Input Label
1798 * @param label_out Output Label
1800 * @return String containing LFIB operation in human readable format
1802 static char *sr_op2str(char *buf
, size_t size
, mpls_label_t label_in
,
1803 mpls_label_t label_out
)
1808 if (label_in
== MPLS_INVALID_LABEL
) {
1809 snprintf(buf
, size
, "no-op.");
1813 switch (label_out
) {
1814 case MPLS_LABEL_IMPLICIT_NULL
:
1815 snprintf(buf
, size
, "Pop(%u)", label_in
);
1817 case MPLS_LABEL_IPV4_EXPLICIT_NULL
:
1818 case MPLS_LABEL_IPV6_EXPLICIT_NULL
:
1819 snprintf(buf
, size
, "Swap(%u, null)", label_in
);
1821 case MPLS_INVALID_LABEL
:
1822 snprintf(buf
, size
, "no-op.");
1825 snprintf(buf
, size
, "Swap(%u, %u)", label_in
, label_out
);
1832 * Show Local Prefix-SID.
1834 * @param vty VTY output
1835 * @param tt Table format
1836 * @param area IS-IS area
1837 * @param srp Segment Routing Prefix
1839 static void show_prefix_sid_local(struct vty
*vty
, struct ttable
*tt
,
1840 const struct isis_area
*area
,
1841 const struct sr_prefix
*srp
)
1843 const struct sr_nexthop_info
*srnh
= &srp
->u
.local
.info
;
1844 char buf_prefix
[BUFSIZ
];
1845 char buf_oper
[BUFSIZ
];
1846 char buf_iface
[BUFSIZ
];
1847 char buf_uptime
[BUFSIZ
];
1849 if (srnh
->label
!= MPLS_INVALID_LABEL
) {
1850 struct interface
*ifp
;
1851 ifp
= if_lookup_prefix(&srp
->prefix
, VRF_DEFAULT
);
1853 strlcpy(buf_iface
, ifp
->name
, sizeof(buf_iface
));
1855 snprintf(buf_iface
, sizeof(buf_iface
), "-");
1856 log_uptime(srnh
->uptime
, buf_uptime
, sizeof(buf_uptime
));
1858 snprintf(buf_iface
, sizeof(buf_iface
), "-");
1859 snprintf(buf_uptime
, sizeof(buf_uptime
), "-");
1861 sr_op2str(buf_oper
, sizeof(buf_oper
), srp
->input_label
,
1862 MPLS_LABEL_IMPLICIT_NULL
);
1864 ttable_add_row(tt
, "%s|%u|%s|-|%s|%s",
1865 prefix2str(&srp
->prefix
, buf_prefix
, sizeof(buf_prefix
)),
1866 srp
->sid
.value
, buf_oper
, buf_iface
, buf_uptime
);
1870 * Show Remote Prefix-SID.
1872 * @param vty VTY output
1873 * @param tt Table format
1874 * @param area IS-IS area
1875 * @param srp Segment Routing Prefix
1877 static void show_prefix_sid_remote(struct vty
*vty
, struct ttable
*tt
,
1878 const struct isis_area
*area
,
1879 const struct sr_prefix
*srp
)
1881 struct isis_nexthop
*nexthop
;
1882 struct listnode
*node
;
1883 char buf_prefix
[BUFSIZ
];
1884 char buf_oper
[BUFSIZ
];
1885 char buf_nhop
[BUFSIZ
];
1886 char buf_iface
[BUFSIZ
];
1887 char buf_uptime
[BUFSIZ
];
1890 (void)prefix2str(&srp
->prefix
, buf_prefix
, sizeof(buf_prefix
));
1892 if (!srp
->u
.remote
.rinfo
) {
1893 ttable_add_row(tt
, "%s|%u|%s|-|-|-", buf_prefix
, srp
->sid
.value
,
1894 sr_op2str(buf_oper
, sizeof(buf_oper
),
1896 MPLS_LABEL_IMPLICIT_NULL
));
1900 for (ALL_LIST_ELEMENTS_RO(srp
->u
.remote
.rinfo
->nexthops
, node
,
1902 struct interface
*ifp
;
1904 inet_ntop(nexthop
->family
, &nexthop
->ip
, buf_nhop
,
1906 ifp
= if_lookup_by_index(nexthop
->ifindex
, VRF_DEFAULT
);
1908 strlcpy(buf_iface
, ifp
->name
, sizeof(buf_iface
));
1910 snprintf(buf_iface
, sizeof(buf_iface
), "ifindex %u",
1912 if (nexthop
->sr
.label
== MPLS_INVALID_LABEL
)
1913 snprintf(buf_uptime
, sizeof(buf_uptime
), "-");
1915 log_uptime(nexthop
->sr
.uptime
, buf_uptime
,
1916 sizeof(buf_uptime
));
1917 sr_op2str(buf_oper
, sizeof(buf_oper
), srp
->input_label
,
1921 ttable_add_row(tt
, "%s|%u|%s|%s|%s|%s", buf_prefix
,
1922 srp
->sid
.value
, buf_oper
, buf_nhop
,
1923 buf_iface
, buf_uptime
);
1925 ttable_add_row(tt
, "|||%s|%s|%s|%s", buf_oper
, buf_nhop
,
1926 buf_iface
, buf_uptime
);
1934 * @param vty VTY output
1935 * @param area IS-IS area
1936 * @param level IS-IS level
1938 static void show_prefix_sids(struct vty
*vty
, struct isis_area
*area
, int level
)
1940 struct sr_prefix
*srp
;
1943 if (srdb_area_prefix_count(&area
->srdb
.prefix_sids
[level
- 1]) == 0)
1946 vty_out(vty
, " IS-IS %s Prefix-SIDs:\n\n", circuit_t2string(level
));
1948 /* Prepare table. */
1949 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
1950 ttable_add_row(tt
, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
1951 tt
->style
.cell
.rpad
= 2;
1952 tt
->style
.corner
= '+';
1954 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
1956 /* Process all Prefix-SID from the SRDB */
1957 frr_each (srdb_area_prefix
, &area
->srdb
.prefix_sids
[level
- 1], srp
) {
1958 switch (srp
->type
) {
1959 case ISIS_SR_PREFIX_LOCAL
:
1960 show_prefix_sid_local(vty
, tt
, area
, srp
);
1962 case ISIS_SR_PREFIX_REMOTE
:
1963 show_prefix_sid_remote(vty
, tt
, area
, srp
);
1968 /* Dump the generated table. */
1969 if (tt
->nrows
> 1) {
1972 table
= ttable_dump(tt
, "\n");
1973 vty_out(vty
, "%s\n", table
);
1974 XFREE(MTYPE_TMP
, table
);
1980 * Declaration of new show commands.
1982 DEFUN(show_sr_prefix_sids
, show_sr_prefix_sids_cmd
,
1983 "show isis segment-routing prefix-sids",
1986 "Segment-Routing Prefix-SIDs\n")
1988 struct listnode
*node
;
1989 struct isis_area
*area
;
1991 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1992 vty_out(vty
, "Area %s:\n",
1993 area
->area_tag
? area
->area_tag
: "null");
1995 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1996 show_prefix_sids(vty
, area
, level
);
2003 * Show Segment Routing Node.
2005 * @param vty VTY output
2006 * @param area IS-IS area
2007 * @param level IS-IS level
2009 static void show_node(struct vty
*vty
, struct isis_area
*area
, int level
)
2011 struct sr_node
*srn
;
2014 if (srdb_area_prefix_count(&area
->srdb
.prefix_sids
[level
- 1]) == 0)
2017 vty_out(vty
, " IS-IS %s SR-Node:\n\n", circuit_t2string(level
));
2019 /* Prepare table. */
2020 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
2021 ttable_add_row(tt
, "System ID|SRGB|SRLB|Algorithm|MSD");
2022 tt
->style
.cell
.rpad
= 2;
2023 tt
->style
.corner
= '+';
2025 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
2027 /* Process all SR-Node from the SRDB */
2028 frr_each (srdb_node
, &area
->srdb
.sr_nodes
[level
- 1], srn
) {
2030 tt
, "%s|%u - %u|%u - %u|%s|%u",
2031 sysid_print(srn
->sysid
),
2032 srn
->cap
.srgb
.lower_bound
,
2033 srn
->cap
.srgb
.lower_bound
+ srn
->cap
.srgb
.range_size
2035 srn
->cap
.srlb
.lower_bound
,
2036 srn
->cap
.srlb
.lower_bound
+ srn
->cap
.srlb
.range_size
2038 srn
->cap
.algo
[0] == SR_ALGORITHM_SPF
? "SPF" : "S-SPF",
2042 /* Dump the generated table. */
2043 if (tt
->nrows
> 1) {
2046 table
= ttable_dump(tt
, "\n");
2047 vty_out(vty
, "%s\n", table
);
2048 XFREE(MTYPE_TMP
, table
);
2053 DEFUN(show_sr_node
, show_sr_node_cmd
,
2054 "show isis segment-routing node",
2057 "Segment-Routing node\n")
2059 struct listnode
*node
;
2060 struct isis_area
*area
;
2062 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2063 vty_out(vty
, "Area %s:\n",
2064 area
->area_tag
? area
->area_tag
: "null");
2066 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
2067 show_node(vty
, area
, level
);
2074 /* --- IS-IS Segment Routing Management function ---------------------------- */
2077 * Thread function to re-attempt connection to the Label Manager and thus be
2078 * able to start Segment Routing.
2080 * @param start Thread structure that contains area as argument
2082 * @return 1 on success
2084 static int sr_start_label_manager(struct thread
*start
)
2086 struct isis_area
*area
;
2088 area
= THREAD_ARG(start
);
2090 /* re-attempt to start SR & Label Manager connection */
2091 isis_sr_start(area
);
2097 * Enable SR on the given IS-IS area.
2099 * @param area IS-IS area
2101 * @return 0 on success, -1 otherwise
2103 int isis_sr_start(struct isis_area
*area
)
2105 struct isis_sr_db
*srdb
= &area
->srdb
;
2106 struct isis_circuit
*circuit
;
2107 struct listnode
*node
;
2109 /* First start Label Manager if not ready */
2110 if (!isis_zebra_label_manager_ready())
2111 if (isis_zebra_label_manager_connect() < 0) {
2112 /* Re-attempt to connect to Label Manager in 1 sec. */
2113 thread_add_timer(master
, sr_start_label_manager
, area
,
2114 1, &srdb
->t_start_lm
);
2118 /* Label Manager is ready, initialize the SRLB */
2119 if (sr_local_block_init(area
) < 0)
2123 * Request SGRB to the label manager if not already active. If the
2124 * allocation fails, return an error to disable SR until a new SRGB
2125 * is successfully allocated.
2127 if (!srdb
->srgb_active
) {
2128 if (isis_zebra_request_label_range(
2129 srdb
->config
.srgb_lower_bound
,
2130 srdb
->config
.srgb_upper_bound
2131 - srdb
->config
.srgb_lower_bound
+ 1)
2133 srdb
->srgb_active
= false;
2136 srdb
->srgb_active
= true;
2139 sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
2142 /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
2143 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
2144 struct isis_adjacency
*adj
;
2145 struct listnode
*anode
;
2147 switch (circuit
->circ_type
) {
2148 case CIRCUIT_T_BROADCAST
:
2149 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
;
2151 for (ALL_LIST_ELEMENTS_RO(
2152 circuit
->u
.bc
.adjdb
[level
- 1],
2154 if (adj
->ipv4_address_count
> 0)
2155 sr_adj_sid_add(adj
, AF_INET
);
2156 if (adj
->ipv6_address_count
> 0)
2157 sr_adj_sid_add(adj
, AF_INET6
);
2162 adj
= circuit
->u
.p2p
.neighbor
;
2163 if (adj
&& adj
->ipv4_address_count
> 0)
2164 sr_adj_sid_add(adj
, AF_INET
);
2165 if (adj
&& adj
->ipv6_address_count
> 0)
2166 sr_adj_sid_add(adj
, AF_INET6
);
2173 area
->srdb
.enabled
= true;
2175 /* Regenerate LSPs to advertise Segment Routing capabilities. */
2176 lsp_regenerate_schedule(area
, area
->is_type
, 0);
2182 * Disable SR on the given IS-IS area.
2184 * @param area IS-IS area
2186 void isis_sr_stop(struct isis_area
*area
)
2188 struct isis_sr_db
*srdb
= &area
->srdb
;
2189 struct sr_adjacency
*sra
;
2190 struct listnode
*node
, *nnode
;
2192 sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
2195 /* Disable any re-attempt to connect to Label Manager */
2196 THREAD_TIMER_OFF(srdb
->t_start_lm
);
2198 /* Uninstall all local Adjacency-SIDs. */
2199 for (ALL_LIST_ELEMENTS(area
->srdb
.adj_sids
, node
, nnode
, sra
))
2200 sr_adj_sid_del(sra
);
2202 /* Uninstall all Prefix-SIDs from all SR Node. */
2203 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2204 while (srdb_node_count(&srdb
->sr_nodes
[level
- 1]) > 0) {
2205 struct sr_node
*srn
;
2207 srn
= srdb_node_first(&srdb
->sr_nodes
[level
- 1]);
2208 sr_node_del(area
, level
, srn
);
2212 /* Release SRGB if active. */
2213 if (srdb
->srgb_active
) {
2214 isis_zebra_release_label_range(srdb
->config
.srgb_lower_bound
,
2215 srdb
->config
.srgb_upper_bound
);
2216 srdb
->srgb_active
= false;
2220 sr_local_block_delete(area
);
2222 area
->srdb
.enabled
= false;
2224 /* Regenerate LSPs to advertise that the Node is no more SR enable. */
2225 lsp_regenerate_schedule(area
, area
->is_type
, 0);
2229 * IS-IS Segment Routing initialization for given area.
2231 * @param area IS-IS area
2233 void isis_sr_area_init(struct isis_area
*area
)
2235 struct isis_sr_db
*srdb
= &area
->srdb
;
2237 sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
2240 /* Initialize Segment Routing Data Base */
2241 memset(srdb
, 0, sizeof(*srdb
));
2242 srdb
->adj_sids
= list_new();
2244 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2245 srdb_node_init(&srdb
->sr_nodes
[level
- 1]);
2246 srdb_area_prefix_init(&srdb
->prefix_sids
[level
- 1]);
2249 /* Pull defaults from the YANG module. */
2251 srdb
->config
.enabled
= yang_get_default_bool("%s/enabled", ISIS_SR
);
2252 srdb
->config
.srgb_lower_bound
=
2253 yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR
);
2254 srdb
->config
.srgb_upper_bound
=
2255 yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR
);
2256 srdb
->config
.srlb_lower_bound
=
2257 yang_get_default_uint32("%s/srlb/lower-bound", ISIS_SR
);
2258 srdb
->config
.srlb_upper_bound
=
2259 yang_get_default_uint32("%s/srlb/upper-bound", ISIS_SR
);
2261 srdb
->config
.enabled
= false;
2262 srdb
->config
.srgb_lower_bound
= SRGB_LOWER_BOUND
;
2263 srdb
->config
.srgb_upper_bound
= SRGB_UPPER_BOUND
;
2264 srdb
->config
.srlb_lower_bound
= SRLB_LOWER_BOUND
;
2265 srdb
->config
.srlb_upper_bound
= SRLB_UPPER_BOUND
;
2267 srdb
->config
.msd
= 0;
2268 srdb_prefix_cfg_init(&srdb
->config
.prefix_sids
);
2272 * Terminate IS-IS Segment Routing for the given area.
2274 * @param area IS-IS area
2276 void isis_sr_area_term(struct isis_area
*area
)
2278 struct isis_sr_db
*srdb
= &area
->srdb
;
2280 /* Stop Segment Routing */
2281 if (area
->srdb
.enabled
)
2284 /* Clear Prefix-SID configuration. */
2285 while (srdb_prefix_cfg_count(&srdb
->config
.prefix_sids
) > 0) {
2286 struct sr_prefix_cfg
*pcfg
;
2288 pcfg
= srdb_prefix_cfg_first(&srdb
->config
.prefix_sids
);
2289 isis_sr_cfg_prefix_del(pcfg
);
2294 * IS-IS Segment Routing global initialization.
2296 void isis_sr_init(void)
2298 install_element(VIEW_NODE
, &show_sr_prefix_sids_cmd
);
2299 install_element(VIEW_NODE
, &show_sr_node_cmd
);
2301 /* Register hooks. */
2302 hook_register(isis_adj_state_change_hook
, sr_adj_state_change
);
2303 hook_register(isis_adj_ip_enabled_hook
, sr_adj_ip_enabled
);
2304 hook_register(isis_adj_ip_disabled_hook
, sr_adj_ip_disabled
);
2305 hook_register(isis_route_update_hook
, sr_route_update
);
2306 hook_register(isis_if_new_hook
, sr_if_new_hook
);
2310 * IS-IS Segment Routing global terminate.
2312 void isis_sr_term(void)
2314 /* Unregister hooks. */
2315 hook_unregister(isis_adj_state_change_hook
, sr_adj_state_change
);
2316 hook_unregister(isis_adj_ip_enabled_hook
, sr_adj_ip_enabled
);
2317 hook_unregister(isis_adj_ip_disabled_hook
, sr_adj_ip_disabled
);
2318 hook_unregister(isis_route_update_hook
, sr_route_update
);
2319 hook_unregister(isis_if_new_hook
, sr_if_new_hook
);