]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_sr.c
*: Rename `struct thread` to `struct event`
[mirror_frr.git] / isisd / isis_sr.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
26f6acaf 2/*
f2333421 3 * This is an implementation of Segment Routing for IS-IS as per RFC 8667
26f6acaf 4 *
f2333421 5 * Copyright (C) 2019 Orange http://www.orange.com
26f6acaf
RW
6 *
7 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
8 * Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
26f6acaf
RW
9 */
10
11#include <zebra.h>
12
13#include "if.h"
14#include "linklist.h"
15#include "log.h"
16#include "command.h"
17#include "termtable.h"
18#include "memory.h"
19#include "prefix.h"
20#include "table.h"
d47d6089 21#include "srcdest_table.h"
26f6acaf
RW
22#include "vty.h"
23#include "zclient.h"
24#include "lib/lib_errors.h"
25
26#include "isisd/isisd.h"
27#include "isisd/isis_spf.h"
28#include "isisd/isis_spf_private.h"
29#include "isisd/isis_adjacency.h"
30#include "isisd/isis_route.h"
31#include "isisd/isis_mt.h"
32#include "isisd/isis_sr.h"
33#include "isisd/isis_tlvs.h"
34#include "isisd/isis_misc.h"
35#include "isisd/isis_zebra.h"
36#include "isisd/isis_errors.h"
37
f2333421 38/* Local variables and functions */
bf8d3d6a 39DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information");
26f6acaf 40
d8391312
OD
41static void sr_local_block_delete(struct isis_area *area);
42static int sr_local_block_init(struct isis_area *area);
43static void sr_adj_sid_update(struct sr_adjacency *sra,
44 struct sr_local_block *srlb);
054fda12 45static void sr_adj_sid_del(struct sr_adjacency *sra);
26f6acaf 46
f2333421 47/* --- RB-Tree Management functions ----------------------------------------- */
26f6acaf 48
f2333421 49/**
d47d6089 50 * Configured SR Prefix comparison for RB-Tree.
f2333421
OD
51 *
52 * @param a First SR prefix
53 * @param b Second SR prefix
54 *
55 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
56 */
d47d6089
RW
57static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
58 const struct sr_prefix_cfg *b)
26f6acaf
RW
59{
60 return prefix_cmp(&a->prefix, &b->prefix);
61}
d47d6089 62DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
960b9a53 63 sr_prefix_sid_cfg_compare);
26f6acaf 64
f2333421 65/**
d47d6089 66 * Find SRGB associated to a System ID.
f2333421 67 *
d47d6089
RW
68 * @param area IS-IS LSP database
69 * @param sysid System ID to lookup
f2333421 70 *
d47d6089 71 * @return Pointer to SRGB if found, NULL otherwise
f2333421 72 */
d47d6089
RW
73struct isis_sr_block *isis_sr_find_srgb(struct lspdb_head *lspdb,
74 const uint8_t *sysid)
26f6acaf 75{
d47d6089
RW
76 struct isis_lsp *lsp;
77
78 lsp = isis_root_system_lsp(lspdb, sysid);
79 if (!lsp)
80 return NULL;
81
82 if (!lsp->tlvs->router_cap
83 || lsp->tlvs->router_cap->srgb.range_size == 0)
84 return NULL;
85
86 return &lsp->tlvs->router_cap->srgb;
26f6acaf 87}
26f6acaf 88
f2333421 89/**
d47d6089 90 * Compute input label for the given Prefix-SID.
f2333421 91 *
d47d6089
RW
92 * @param area IS-IS area
93 * @param psid IS-IS Prefix-SID Sub-TLV
94 * @param local Indicates whether the Prefix-SID is local or not
f2333421 95 *
d47d6089 96 * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
f2333421 97 */
d47d6089
RW
98mpls_label_t sr_prefix_in_label(struct isis_area *area,
99 struct isis_prefix_sid *psid, bool local)
26f6acaf 100{
d47d6089
RW
101 /*
102 * No need to assign a label for local Prefix-SIDs unless the no-PHP
103 * flag is set.
104 */
105 if (local
106 && (!CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP)
107 || CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL)))
108 return MPLS_INVALID_LABEL;
109
110 /* Return SID value as MPLS label if it is an Absolute SID */
111 if (CHECK_FLAG(psid->flags,
112 ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
113 return psid->value;
114
115 /* Check that SID index falls inside the SRGB */
116 if (psid->value >= (area->srdb.config.srgb_upper_bound
117 - area->srdb.config.srgb_lower_bound + 1)) {
118 flog_warn(EC_ISIS_SID_OVERFLOW,
119 "%s: SID index %u falls outside local SRGB range",
120 __func__, psid->value);
121 return MPLS_INVALID_LABEL;
122 }
123
124 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
125 return (area->srdb.config.srgb_lower_bound + psid->value);
126}
127
128/**
129 * Compute output label for the given Prefix-SID.
130 *
131 * @param lspdb IS-IS LSP database
132 * @param family Prefix-SID address family
133 * @param psid Prefix-SID Sub-TLV
134 * @param nh_sysid System ID of the nexthop node
135 * @param last_hop Indicates whether the nexthop node is the last hop
136 *
137 * @return MPLS label or MPLS_INVALID_LABEL in case of error
138 */
139mpls_label_t sr_prefix_out_label(struct lspdb_head *lspdb, int family,
140 struct isis_prefix_sid *psid,
141 const uint8_t *nh_sysid, bool last_hop)
142{
143 struct isis_sr_block *nh_srgb;
144
145 if (last_hop) {
146 if (!CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP))
147 return MPLS_LABEL_IMPLICIT_NULL;
148
149 if (CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL)) {
150 if (family == AF_INET)
151 return MPLS_LABEL_IPV4_EXPLICIT_NULL;
152 else
153 return MPLS_LABEL_IPV6_EXPLICIT_NULL;
154 }
155 /* Fallthrough */
156 }
157
158 /* Return SID value as MPLS label if it is an Absolute SID */
159 if (CHECK_FLAG(psid->flags,
160 ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
161 /*
162 * V/L SIDs have local significance, so only adjacent routers
163 * can use them (RFC8667 section #2.1.1.1)
164 */
165 if (!last_hop)
166 return MPLS_INVALID_LABEL;
167 return psid->value;
168 }
169
170 /* Check that SID index falls inside the SRGB */
171 nh_srgb = isis_sr_find_srgb(lspdb, nh_sysid);
172 if (!nh_srgb)
173 return MPLS_INVALID_LABEL;
174
175 /*
176 * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
177 * IPv6 packets.
178 */
179 if ((family == AF_INET && !IS_SR_IPV4(nh_srgb))
180 || (family == AF_INET6 && !IS_SR_IPV6(nh_srgb)))
181 return MPLS_INVALID_LABEL;
182
183 if (psid->value >= nh_srgb->range_size) {
184 flog_warn(EC_ISIS_SID_OVERFLOW,
185 "%s: SID index %u falls outside remote SRGB range",
186 __func__, psid->value);
187 return MPLS_INVALID_LABEL;
188 }
189
190 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
191 return (nh_srgb->lower_bound + psid->value);
26f6acaf 192}
26f6acaf 193
f2333421 194/* --- Functions used for Yang model and CLI to configure Segment Routing --- */
26f6acaf 195
f2333421
OD
196/**
197 * Check if prefix correspond to a Node SID.
198 *
199 * @param ifp Interface
200 * @param prefix Prefix to be checked
201 *
202 * @return True if the interface/address pair corresponds to a Node-SID
203 */
b1d80d43
OD
204static bool sr_prefix_is_node_sid(const struct interface *ifp,
205 const struct prefix *prefix)
26f6acaf
RW
206{
207 return (if_is_loopback(ifp) && is_host_route(prefix));
208}
209
f2333421
OD
210/**
211 * Update local SRGB configuration. SRGB is reserved though Label Manager.
212 * This function trigger the update of local Prefix-SID installation.
213 *
214 * @param area IS-IS area
215 * @param lower_bound Lower bound of SRGB
216 * @param upper_bound Upper bound of SRGB
217 *
218 * @return 0 on success, -1 otherwise
219 */
26f6acaf
RW
220int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
221 uint32_t upper_bound)
222{
223 struct isis_sr_db *srdb = &area->srdb;
224
d8391312
OD
225 sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
226 area->area_tag, lower_bound, upper_bound);
b407c77a 227
58fbcdf2
OD
228 /* Just store new SRGB values if Label Manager is not available.
229 * SRGB will be configured later when SR start */
230 if (!isis_zebra_label_manager_ready()) {
231 srdb->config.srgb_lower_bound = lower_bound;
232 srdb->config.srgb_upper_bound = upper_bound;
233 return 0;
234 }
235
236 /* Label Manager is ready, start by releasing the old SRGB. */
237 if (srdb->srgb_active) {
238 isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
26f6acaf 239 srdb->config.srgb_upper_bound);
58fbcdf2
OD
240 srdb->srgb_active = false;
241 }
26f6acaf
RW
242
243 srdb->config.srgb_lower_bound = lower_bound;
244 srdb->config.srgb_upper_bound = upper_bound;
245
246 if (srdb->enabled) {
d8391312 247 /* then request new SRGB if SR is enabled. */
26f6acaf
RW
248 if (isis_zebra_request_label_range(
249 srdb->config.srgb_lower_bound,
250 srdb->config.srgb_upper_bound
58fbcdf2
OD
251 - srdb->config.srgb_lower_bound + 1) < 0) {
252 srdb->srgb_active = false;
26f6acaf 253 return -1;
58fbcdf2
OD
254 } else
255 srdb->srgb_active = true;
256
26f6acaf 257
d8391312 258 sr_debug(" |- Got new SRGB [%u/%u]",
b407c77a
OD
259 srdb->config.srgb_lower_bound,
260 srdb->config.srgb_upper_bound);
261
26f6acaf
RW
262 lsp_regenerate_schedule(area, area->is_type, 0);
263 } else if (srdb->config.enabled) {
264 /* Try to enable SR again using the new SRGB. */
58fbcdf2 265 isis_sr_start(area);
26f6acaf
RW
266 }
267
268 return 0;
269}
270
d8391312
OD
271/**
272 * Update Segment Routing Local Block range which is reserved though the
273 * Label Manager. This function trigger the update of local Adjacency-SID
274 * installation.
275 *
276 * @param area IS-IS area
277 * @param lower_bound Lower bound of SRLB
278 * @param upper_bound Upper bound of SRLB
279 *
280 * @return 0 on success, -1 otherwise
281 */
282int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound,
283 uint32_t upper_bound)
284{
285 struct isis_sr_db *srdb = &area->srdb;
36944791 286 struct listnode *node;
d8391312 287 struct sr_adjacency *sra;
d8391312
OD
288
289 sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
290 area->area_tag, lower_bound, upper_bound);
291
58fbcdf2
OD
292 /* Just store new SRLB values if Label Manager is not available.
293 * SRLB will be configured later when SR start */
294 if (!isis_zebra_label_manager_ready()) {
295 srdb->config.srlb_lower_bound = lower_bound;
296 srdb->config.srlb_upper_bound = upper_bound;
297 return 0;
298 }
299
300 /* LM is ready, start by deleting the old SRLB */
d8391312
OD
301 sr_local_block_delete(area);
302
303 srdb->config.srlb_lower_bound = lower_bound;
304 srdb->config.srlb_upper_bound = upper_bound;
305
58fbcdf2 306 if (srdb->enabled) {
d47d6089
RW
307 /* Initialize new SRLB */
308 if (sr_local_block_init(area) != 0)
309 return -1;
26f6acaf 310
d47d6089
RW
311 /* Reinstall local Adjacency-SIDs with new labels. */
312 for (ALL_LIST_ELEMENTS_RO(area->srdb.adj_sids, node, sra))
313 sr_adj_sid_update(sra, &srdb->srlb);
26f6acaf 314
d47d6089
RW
315 /* Update and Flood LSP */
316 lsp_regenerate_schedule(area, area->is_type, 0);
317 } else if (srdb->config.enabled) {
318 /* Try to enable SR again using the new SRLB. */
319 isis_sr_start(area);
26f6acaf 320 }
d47d6089
RW
321
322 return 0;
26f6acaf
RW
323}
324
f2333421 325/**
d47d6089 326 * Add new Prefix-SID configuration to the SRDB.
f2333421 327 *
d47d6089
RW
328 * @param area IS-IS area
329 * @param prefix Prefix to be added
330 *
331 * @return Newly added Prefix-SID configuration structure
f2333421 332 */
d47d6089
RW
333struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
334 const struct prefix *prefix)
26f6acaf 335{
d47d6089
RW
336 struct sr_prefix_cfg *pcfg;
337 struct interface *ifp;
26f6acaf 338
d47d6089 339 sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
26f6acaf 340
d47d6089
RW
341 pcfg = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*pcfg));
342 pcfg->prefix = *prefix;
343 pcfg->area = area;
26f6acaf 344
d47d6089
RW
345 /* Pull defaults from the YANG module. */
346 pcfg->sid_type = yang_get_default_enum(
347 "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR);
348 pcfg->last_hop_behavior = yang_get_default_enum(
349 "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR);
26f6acaf 350
249c4457 351 /* Mark as node Sid if the prefix is host and configured in loopback */
d47d6089 352 ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
249c4457 353 if (ifp && sr_prefix_is_node_sid(ifp, prefix))
d47d6089 354 pcfg->node_sid = true;
26f6acaf 355
d47d6089
RW
356 /* Save prefix-sid configuration. */
357 srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
26f6acaf 358
d47d6089 359 return pcfg;
26f6acaf
RW
360}
361
f2333421 362/**
d47d6089 363 * Removal of locally configured Prefix-SID.
f2333421 364 *
d47d6089 365 * @param pcfg Configured Prefix-SID
f2333421 366 */
d47d6089 367void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
26f6acaf 368{
d47d6089 369 struct isis_area *area = pcfg->area;
26f6acaf 370
d47d6089
RW
371 sr_debug("ISIS-Sr (%s): Delete local Prefix-SID %pFX %s %u",
372 area->area_tag, &pcfg->prefix,
373 pcfg->sid_type == SR_SID_VALUE_TYPE_INDEX ? "index" : "label",
374 pcfg->sid);
375
376 srdb_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
377 XFREE(MTYPE_ISIS_SR_INFO, pcfg);
26f6acaf
RW
378}
379
f2333421 380/**
d47d6089 381 * Lookup for Prefix-SID in the local configuration.
f2333421 382 *
d47d6089
RW
383 * @param area IS-IS area
384 * @param prefix Prefix to lookup
385 *
386 * @return Configured Prefix-SID structure if found, NULL otherwise
f2333421 387 */
d47d6089
RW
388struct sr_prefix_cfg *isis_sr_cfg_prefix_find(struct isis_area *area,
389 union prefixconstptr prefix)
26f6acaf 390{
d47d6089 391 struct sr_prefix_cfg pcfg = {};
26f6acaf 392
d47d6089
RW
393 prefix_copy(&pcfg.prefix, prefix.p);
394 return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
26f6acaf
RW
395}
396
f2333421 397/**
d47d6089 398 * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
f2333421 399 *
d47d6089
RW
400 * @param pcfg Prefix-SID configuration
401 * @param external False if prefix is locally configured, true otherwise
402 * @param psid Prefix-SID sub-TLV to be updated
f2333421 403 */
d47d6089
RW
404void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
405 struct isis_prefix_sid *psid)
26f6acaf 406{
d47d6089
RW
407 /* Set SID algorithm. */
408 psid->algorithm = SR_ALGORITHM_SPF;
26f6acaf 409
d47d6089
RW
410 /* Set SID flags. */
411 psid->flags = 0;
412 switch (pcfg->last_hop_behavior) {
413 case SR_LAST_HOP_BEHAVIOR_EXP_NULL:
414 SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
415 SET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
cab10e86 416 break;
d47d6089
RW
417 case SR_LAST_HOP_BEHAVIOR_NO_PHP:
418 SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
419 UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
420 break;
421 case SR_LAST_HOP_BEHAVIOR_PHP:
422 UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
423 UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
cab10e86 424 break;
26f6acaf 425 }
d47d6089
RW
426 if (external)
427 SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED);
8f6a0d64 428 if (pcfg->node_sid && !pcfg->n_flag_clear)
d47d6089 429 SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);
26f6acaf 430
d47d6089
RW
431 /* Set SID value. */
432 psid->value = pcfg->sid;
433 if (pcfg->sid_type == SR_SID_VALUE_TYPE_ABSOLUTE) {
434 SET_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE);
435 SET_FLAG(psid->flags, ISIS_PREFIX_SID_LOCAL);
436 }
26f6acaf
RW
437}
438
054fda12
RW
439/**
440 * Delete all backup Adj-SIDs.
441 *
442 * @param area IS-IS area
443 * @param level IS-IS level
444 */
445void isis_area_delete_backup_adj_sids(struct isis_area *area, int level)
446{
447 struct sr_adjacency *sra;
448 struct listnode *node, *nnode;
449
450 for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
451 if (sra->type == ISIS_SR_LAN_BACKUP
452 && (sra->adj->level & level))
453 sr_adj_sid_del(sra);
454}
455
d8391312
OD
456/* --- Segment Routing Local Block management functions --------------------- */
457
458/**
459 * Initialize Segment Routing Local Block from SRDB configuration and reserve
460 * block of bits to manage label allocation.
461 *
462 * @param area IS-IS area
463 */
58fbcdf2 464static int sr_local_block_init(struct isis_area *area)
d8391312
OD
465{
466 struct isis_sr_db *srdb = &area->srdb;
467 struct sr_local_block *srlb = &srdb->srlb;
468
58fbcdf2
OD
469 /* Check if SRLB is not already configured */
470 if (srlb->active)
471 return 0;
472
d8391312
OD
473 /*
474 * Request SRLB to the label manager. If the allocation fails, return
475 * an error to disable SR until a new SRLB is successfully allocated.
476 */
477 if (isis_zebra_request_label_range(
478 srdb->config.srlb_lower_bound,
479 srdb->config.srlb_upper_bound
58fbcdf2
OD
480 - srdb->config.srlb_lower_bound + 1)) {
481 srlb->active = false;
482 return -1;
483 }
d8391312
OD
484
485 sr_debug("ISIS-Sr (%s): Got new SRLB [%u/%u]", area->area_tag,
486 srdb->config.srlb_lower_bound, srdb->config.srlb_upper_bound);
487
488 /* Initialize the SRLB */
489 srlb->start = srdb->config.srlb_lower_bound;
490 srlb->end = srdb->config.srlb_upper_bound;
491 srlb->current = 0;
492 /* Compute the needed Used Mark number and allocate them */
493 srlb->max_block = (srlb->end - srlb->start + 1) / SRLB_BLOCK_SIZE;
494 if (((srlb->end - srlb->start + 1) % SRLB_BLOCK_SIZE) != 0)
495 srlb->max_block++;
496 srlb->used_mark = XCALLOC(MTYPE_ISIS_SR_INFO,
497 srlb->max_block * SRLB_BLOCK_SIZE);
58fbcdf2
OD
498 srlb->active = true;
499
500 return 0;
d8391312
OD
501}
502
503/**
504 * Remove Segment Routing Local Block.
505 *
506 * @param area IS-IS area
507 */
508static void sr_local_block_delete(struct isis_area *area)
509{
510 struct isis_sr_db *srdb = &area->srdb;
511 struct sr_local_block *srlb = &srdb->srlb;
512
58fbcdf2
OD
513 /* Check if SRLB is not already delete */
514 if (!srlb->active)
515 return;
516
d8391312
OD
517 sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area->area_tag,
518 srlb->start, srlb->end);
519
520 /* First release the label block */
521 isis_zebra_release_label_range(srdb->config.srlb_lower_bound,
522 srdb->config.srlb_upper_bound);
523
524 /* Then reset SRLB structure */
525 if (srlb->used_mark != NULL)
526 XFREE(MTYPE_ISIS_SR_INFO, srlb->used_mark);
58fbcdf2 527 srlb->active = false;
d8391312
OD
528}
529
530/**
531 * Request a label from the Segment Routing Local Block.
532 *
533 * @param srlb Segment Routing Local Block
534 *
535 * @return First available label on success or MPLS_INVALID_LABEL if the
536 * block of labels is full
537 */
538static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb)
539{
d8391312
OD
540 mpls_label_t label;
541 uint32_t index;
542 uint32_t pos;
e90c0383 543 uint32_t size = srlb->end - srlb->start + 1;
d8391312
OD
544
545 /* Check if we ran out of available labels */
e90c0383 546 if (srlb->current >= size)
d8391312
OD
547 return MPLS_INVALID_LABEL;
548
549 /* Get first available label and mark it used */
550 label = srlb->current + srlb->start;
551 index = srlb->current / SRLB_BLOCK_SIZE;
552 pos = 1ULL << (srlb->current % SRLB_BLOCK_SIZE);
553 srlb->used_mark[index] |= pos;
554
555 /* Jump to the next free position */
556 srlb->current++;
557 pos = srlb->current % SRLB_BLOCK_SIZE;
e90c0383 558 while (srlb->current < size) {
d8391312
OD
559 if (pos == 0)
560 index++;
561 if (!((1ULL << pos) & srlb->used_mark[index]))
562 break;
563 else {
564 srlb->current++;
565 pos = srlb->current % SRLB_BLOCK_SIZE;
566 }
567 }
568
e90c0383
FR
569 if (srlb->current == size)
570 zlog_warn(
571 "SR: Warning, SRLB is depleted and next label request will fail");
572
d8391312
OD
573 return label;
574}
575
576/**
577 * Release label in the Segment Routing Local Block.
578 *
579 * @param srlb Segment Routing Local Block
580 * @param label Label to be release
581 *
582 * @return 0 on success or -1 if label falls outside SRLB
583 */
584static int sr_local_block_release_label(struct sr_local_block *srlb,
585 mpls_label_t label)
586{
587 uint32_t index;
588 uint32_t pos;
589
590 /* Check that label falls inside the SRLB */
591 if ((label < srlb->start) || (label > srlb->end)) {
592 flog_warn(EC_ISIS_SID_OVERFLOW,
593 "%s: Returning label %u is outside SRLB [%u/%u]",
594 __func__, label, srlb->start, srlb->end);
595 return -1;
596 }
597
598 index = (label - srlb->start) / SRLB_BLOCK_SIZE;
599 pos = 1ULL << ((label - srlb->start) % SRLB_BLOCK_SIZE);
600 srlb->used_mark[index] &= ~pos;
601 /* Reset current to the first available position */
602 for (index = 0; index < srlb->max_block; index++) {
603 if (srlb->used_mark[index] != 0xFFFFFFFFFFFFFFFF) {
604 for (pos = 0; pos < SRLB_BLOCK_SIZE; pos++)
605 if (!((1ULL << pos) & srlb->used_mark[index])) {
606 srlb->current =
607 index * SRLB_BLOCK_SIZE + pos;
608 break;
609 }
610 break;
611 }
612 }
613
614 return 0;
615}
616
f2333421 617/* --- Segment Routing Adjacency-SID management functions ------------------- */
26f6acaf 618
f2333421
OD
619/**
620 * Add new local Adjacency-SID.
621 *
054fda12
RW
622 * @param adj IS-IS Adjacency
623 * @param family Inet Family (IPv4 or IPv6)
624 * @param backup True to initialize backup Adjacency SID
625 * @param nexthops List of backup nexthops (for backup Adj-SIDs only)
f2333421 626 */
054fda12
RW
627void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
628 struct list *nexthops)
26f6acaf
RW
629{
630 struct isis_circuit *circuit = adj->circuit;
631 struct isis_area *area = circuit->area;
632 struct sr_adjacency *sra;
633 struct isis_adj_sid *adj_sid;
634 struct isis_lan_adj_sid *ladj_sid;
635 union g_addr nexthop = {};
636 uint8_t flags;
b1d80d43 637 mpls_label_t input_label;
26f6acaf 638
b407c77a
OD
639 sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area->area_tag,
640 backup ? "Backup" : "Primary");
641
f2333421 642 /* Determine nexthop IP address */
26f6acaf
RW
643 switch (family) {
644 case AF_INET:
0af5e414 645 if (!circuit->ip_router || !adj->ipv4_address_count)
26f6acaf
RW
646 return;
647
648 nexthop.ipv4 = adj->ipv4_addresses[0];
649 break;
650 case AF_INET6:
173f8887 651 if (!circuit->ipv6_router || !adj->ll_ipv6_count)
26f6acaf
RW
652 return;
653
173f8887 654 nexthop.ipv6 = adj->ll_ipv6_addrs[0];
26f6acaf
RW
655 break;
656 default:
657 flog_err(EC_LIB_DEVELOPMENT,
658 "%s: unexpected address-family: %u", __func__, family);
659 exit(1);
660 }
661
f2333421 662 /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
26f6acaf
RW
663 flags = EXT_SUBTLV_LINK_ADJ_SID_VFLG | EXT_SUBTLV_LINK_ADJ_SID_LFLG;
664 if (family == AF_INET6)
665 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG);
666 if (backup)
667 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG);
668
d8391312
OD
669 /* Get a label from the SRLB for this Adjacency */
670 input_label = sr_local_block_request_label(&area->srdb.srlb);
671 if (input_label == MPLS_INVALID_LABEL)
672 return;
673
26f6acaf
RW
674 if (circuit->ext == NULL)
675 circuit->ext = isis_alloc_ext_subtlvs();
676
26f6acaf
RW
677 sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
678 sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
054fda12 679 sra->input_label = input_label;
26f6acaf
RW
680 sra->nexthop.family = family;
681 sra->nexthop.address = nexthop;
054fda12
RW
682
683 if (backup && nexthops) {
684 struct isis_vertex_adj *vadj;
685 struct listnode *node;
686
687 sra->backup_nexthops = list_new();
688 for (ALL_LIST_ELEMENTS_RO(nexthops, node, vadj)) {
689 struct isis_adjacency *adj = vadj->sadj->adj;
690 struct mpls_label_stack *label_stack;
691
692 label_stack = vadj->label_stack;
d47d6089 693 adjinfo2nexthop(family, sra->backup_nexthops, adj, NULL,
054fda12
RW
694 label_stack);
695 }
696 }
697
26f6acaf 698 switch (circuit->circ_type) {
f2333421 699 /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
26f6acaf
RW
700 case CIRCUIT_T_BROADCAST:
701 ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid));
702 ladj_sid->family = family;
703 ladj_sid->flags = flags;
704 ladj_sid->weight = 0;
705 memcpy(ladj_sid->neighbor_id, adj->sysid,
706 sizeof(ladj_sid->neighbor_id));
b1d80d43 707 ladj_sid->sid = input_label;
26f6acaf
RW
708 isis_tlvs_add_lan_adj_sid(circuit->ext, ladj_sid);
709 sra->u.ladj_sid = ladj_sid;
710 break;
f2333421 711 /* Adjacency-SID for Point to Point interface section #2.2.1 */
26f6acaf
RW
712 case CIRCUIT_T_P2P:
713 adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid));
714 adj_sid->family = family;
715 adj_sid->flags = flags;
716 adj_sid->weight = 0;
b1d80d43 717 adj_sid->sid = input_label;
26f6acaf
RW
718 isis_tlvs_add_adj_sid(circuit->ext, adj_sid);
719 sra->u.adj_sid = adj_sid;
720 break;
721 default:
722 flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
723 __func__, circuit->circ_type);
724 exit(1);
725 }
f2333421
OD
726
727 /* Add Adjacency-SID in SRDB */
26f6acaf
RW
728 sra->adj = adj;
729 listnode_add(area->srdb.adj_sids, sra);
730 listnode_add(adj->adj_sids, sra);
731
c3f7b406 732 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
26f6acaf
RW
733}
734
f2333421
OD
735/**
736 * Add Primary and Backup local Adjacency SID.
737 *
738 * @param adj IS-IS Adjacency
739 * @param family Inet Family (IPv4 or IPv6)
740 */
b1d80d43 741static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
26f6acaf 742{
054fda12 743 sr_adj_sid_add_single(adj, family, false, NULL);
26f6acaf
RW
744}
745
d8391312
OD
746static void sr_adj_sid_update(struct sr_adjacency *sra,
747 struct sr_local_block *srlb)
748{
749 struct isis_circuit *circuit = sra->adj->circuit;
750
751 /* First remove the old MPLS Label */
752 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
753
754 /* Got new label in the new SRLB */
054fda12
RW
755 sra->input_label = sr_local_block_request_label(srlb);
756 if (sra->input_label == MPLS_INVALID_LABEL)
d8391312
OD
757 return;
758
759 switch (circuit->circ_type) {
760 case CIRCUIT_T_BROADCAST:
054fda12 761 sra->u.ladj_sid->sid = sra->input_label;
d8391312
OD
762 break;
763 case CIRCUIT_T_P2P:
054fda12 764 sra->u.adj_sid->sid = sra->input_label;
d8391312
OD
765 break;
766 default:
767 flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
768 __func__, circuit->circ_type);
769 break;
770 }
771
772 /* Finally configure the new MPLS Label */
773 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
774}
775
f2333421
OD
776/**
777 * Delete local Adj-SID.
778 *
779 * @param sra Segment Routing Adjacency
780 */
b1d80d43 781static void sr_adj_sid_del(struct sr_adjacency *sra)
26f6acaf
RW
782{
783 struct isis_circuit *circuit = sra->adj->circuit;
784 struct isis_area *area = circuit->area;
785
b407c77a 786 sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area->area_tag);
26f6acaf 787
c3f7b406 788 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
26f6acaf 789
f2333421 790 /* Release dynamic label and remove subTLVs */
26f6acaf
RW
791 switch (circuit->circ_type) {
792 case CIRCUIT_T_BROADCAST:
d8391312
OD
793 sr_local_block_release_label(&area->srdb.srlb,
794 sra->u.ladj_sid->sid);
26f6acaf
RW
795 isis_tlvs_del_lan_adj_sid(circuit->ext, sra->u.ladj_sid);
796 break;
797 case CIRCUIT_T_P2P:
d8391312
OD
798 sr_local_block_release_label(&area->srdb.srlb,
799 sra->u.adj_sid->sid);
26f6acaf
RW
800 isis_tlvs_del_adj_sid(circuit->ext, sra->u.adj_sid);
801 break;
802 default:
803 flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
804 __func__, circuit->circ_type);
805 exit(1);
806 }
807
054fda12
RW
808 if (sra->type == ISIS_SR_LAN_BACKUP && sra->backup_nexthops) {
809 sra->backup_nexthops->del =
810 (void (*)(void *))isis_nexthop_delete;
811 list_delete(&sra->backup_nexthops);
812 }
813
f2333421 814 /* Remove Adjacency-SID from the SRDB */
26f6acaf
RW
815 listnode_delete(area->srdb.adj_sids, sra);
816 listnode_delete(sra->adj->adj_sids, sra);
817 XFREE(MTYPE_ISIS_SR_INFO, sra);
818}
819
054fda12
RW
820/**
821 * Lookup Segment Routing Adj-SID by family and type.
822 *
823 * @param adj IS-IS Adjacency
824 * @param family Inet Family (IPv4 or IPv6)
825 * @param type Adjacency SID type
826 */
827struct sr_adjacency *isis_sr_adj_sid_find(struct isis_adjacency *adj,
828 int family, enum sr_adj_type type)
829{
830 struct sr_adjacency *sra;
831 struct listnode *node;
832
833 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, node, sra))
834 if (sra->nexthop.family == family && sra->type == type)
835 return sra;
836
837 return NULL;
838}
839
f2333421
OD
840/**
841 * Remove all Adjacency-SIDs associated to an adjacency that is going down.
842 *
843 * @param adj IS-IS Adjacency
844 *
845 * @return 0
846 */
b1d80d43 847static int sr_adj_state_change(struct isis_adjacency *adj)
26f6acaf
RW
848{
849 struct sr_adjacency *sra;
850 struct listnode *node, *nnode;
851
852 if (!adj->circuit->area->srdb.enabled)
853 return 0;
854
855 if (adj->adj_state == ISIS_ADJ_UP)
856 return 0;
857
858 for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
b1d80d43 859 sr_adj_sid_del(sra);
26f6acaf
RW
860
861 return 0;
862}
863
f2333421
OD
864/**
865 * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
866 * IPv6 address to corresponding Adjacency-SID accordingly.
867 *
868 * @param adj IS-IS Adjacency
869 * @param family Inet Family (IPv4 or IPv6)
173f8887 870 * @param global Indicate if it concerns the Local or Global IPv6 addresses
f2333421
OD
871 *
872 * @return 0
26f6acaf 873 */
173f8887
OD
874static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family,
875 bool global)
26f6acaf 876{
173f8887 877 if (!adj->circuit->area->srdb.enabled || global)
26f6acaf
RW
878 return 0;
879
b1d80d43 880 sr_adj_sid_add(adj, family);
26f6acaf
RW
881
882 return 0;
883}
884
f2333421
OD
885/**
886 * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
887 * delete the corresponding Adjacency-SID(s) accordingly.
888 *
889 * @param adj IS-IS Adjacency
890 * @param family Inet Family (IPv4 or IPv6)
173f8887 891 * @param global Indicate if it concerns the Local or Global IPv6 addresses
f2333421
OD
892 *
893 * @return 0
26f6acaf 894 */
173f8887
OD
895static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family,
896 bool global)
26f6acaf
RW
897{
898 struct sr_adjacency *sra;
899 struct listnode *node, *nnode;
900
173f8887 901 if (!adj->circuit->area->srdb.enabled || global)
26f6acaf
RW
902 return 0;
903
904 for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
905 if (sra->nexthop.family == family)
b1d80d43 906 sr_adj_sid_del(sra);
26f6acaf
RW
907
908 return 0;
909}
910
f2333421
OD
911/**
912 * Activate local Prefix-SID when loopback interface goes up for IS-IS.
913 *
914 * @param ifp Loopback Interface
915 *
916 * @return 0
917 */
b1d80d43 918static int sr_if_new_hook(struct interface *ifp)
26f6acaf
RW
919{
920 struct isis_circuit *circuit;
921 struct isis_area *area;
922 struct connected *connected;
923 struct listnode *node;
924
f2333421 925 /* Get corresponding circuit */
26f6acaf
RW
926 circuit = circuit_scan_by_ifp(ifp);
927 if (!circuit)
928 return 0;
929
930 area = circuit->area;
931 if (!area)
932 return 0;
933
934 /*
935 * Update the Node-SID flag of the configured Prefix-SID mappings if
936 * necessary. This needs to be done here since isisd reads the startup
937 * configuration before receiving interface information from zebra.
938 */
939 FOR_ALL_INTERFACES_ADDRESSES (ifp, connected, node) {
940 struct sr_prefix_cfg *pcfg;
941
942 pcfg = isis_sr_cfg_prefix_find(area, connected->address);
943 if (!pcfg)
944 continue;
945
249c4457 946 if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)) {
26f6acaf
RW
947 pcfg->node_sid = true;
948 lsp_regenerate_schedule(area, area->is_type, 0);
949 }
950 }
951
952 return 0;
953}
954
c0083e53
OD
955/**
956 * Show LFIB operation in human readable format.
957 *
c951ee6e
RW
958 * @param buf Buffer to store string output. Must be pre-allocate
959 * @param size Size of the buffer
960 * @param label_in Input Label
961 * @param label_out Output Label
c0083e53
OD
962 *
963 * @return String containing LFIB operation in human readable format
964 */
d47d6089
RW
965char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
966 mpls_label_t label_out)
c0083e53
OD
967{
968 if (size < 24)
969 return NULL;
970
971 if (label_in == MPLS_INVALID_LABEL) {
972 snprintf(buf, size, "no-op.");
973 return buf;
974 }
975
976 switch (label_out) {
977 case MPLS_LABEL_IMPLICIT_NULL:
978 snprintf(buf, size, "Pop(%u)", label_in);
979 break;
980 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
981 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
982 snprintf(buf, size, "Swap(%u, null)", label_in);
983 break;
984 case MPLS_INVALID_LABEL:
985 snprintf(buf, size, "no-op.");
986 break;
987 default:
988 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
989 break;
990 }
991 return buf;
992}
993
c0083e53
OD
994/**
995 * Show Segment Routing Node.
996 *
997 * @param vty VTY output
998 * @param area IS-IS area
999 * @param level IS-IS level
1000 */
1001static void show_node(struct vty *vty, struct isis_area *area, int level)
1002{
d47d6089 1003 struct isis_lsp *lsp;
c0083e53
OD
1004 struct ttable *tt;
1005
d47d6089 1006 vty_out(vty, " IS-IS %s SR-Nodes:\n\n", circuit_t2string(level));
c0083e53
OD
1007
1008 /* Prepare table. */
1009 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
d8391312 1010 ttable_add_row(tt, "System ID|SRGB|SRLB|Algorithm|MSD");
c0083e53
OD
1011 tt->style.cell.rpad = 2;
1012 tt->style.corner = '+';
1013 ttable_restyle(tt);
1014 ttable_rowseps(tt, 0, BOTTOM, true, '-');
1015
d47d6089
RW
1016 frr_each (lspdb, &area->lspdb[level - 1], lsp) {
1017 struct isis_router_cap *cap;
1018
1019 if (!lsp->tlvs)
1020 continue;
1021 cap = lsp->tlvs->router_cap;
1022 if (!cap)
1023 continue;
1024
d8391312
OD
1025 ttable_add_row(
1026 tt, "%s|%u - %u|%u - %u|%s|%u",
d47d6089
RW
1027 sysid_print(lsp->hdr.lsp_id), cap->srgb.lower_bound,
1028 cap->srgb.lower_bound + cap->srgb.range_size - 1,
1029 cap->srlb.lower_bound,
1030 cap->srlb.lower_bound + cap->srlb.range_size - 1,
1031 cap->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF",
1032 cap->msd);
c0083e53
OD
1033 }
1034
1035 /* Dump the generated table. */
1036 if (tt->nrows > 1) {
1037 char *table;
1038
1039 table = ttable_dump(tt, "\n");
1040 vty_out(vty, "%s\n", table);
1041 XFREE(MTYPE_TMP, table);
1042 }
1043 ttable_del(tt);
1044}
1045
1046DEFUN(show_sr_node, show_sr_node_cmd,
903ad92c
DL
1047 "show " PROTO_NAME " segment-routing node",
1048 SHOW_STR
1049 PROTO_HELP
c0083e53
OD
1050 "Segment-Routing\n"
1051 "Segment-Routing node\n")
1052{
36944791 1053 struct listnode *node, *inode;
c0083e53 1054 struct isis_area *area;
36944791 1055 struct isis *isis;
c0083e53 1056
36944791 1057 for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
eab88f36
K
1058 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
1059 vty_out(vty, "Area %s:\n",
1060 area->area_tag ? area->area_tag : "null");
7700a88a
OD
1061 if (!area->srdb.enabled) {
1062 vty_out(vty, " Segment Routing is disabled\n");
1063 continue;
1064 }
eab88f36
K
1065 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
1066 level++)
1067 show_node(vty, area, level);
1068 }
c0083e53
OD
1069 }
1070
1071 return CMD_SUCCESS;
1072}
1073
f2333421 1074/* --- IS-IS Segment Routing Management function ---------------------------- */
26f6acaf 1075
58fbcdf2
OD
1076/**
1077 * Thread function to re-attempt connection to the Label Manager and thus be
1078 * able to start Segment Routing.
1079 *
1080 * @param start Thread structure that contains area as argument
1081 *
1082 * @return 1 on success
1083 */
e6685141 1084static void sr_start_label_manager(struct event *start)
58fbcdf2
OD
1085{
1086 struct isis_area *area;
1087
1088 area = THREAD_ARG(start);
1089
1090 /* re-attempt to start SR & Label Manager connection */
1091 isis_sr_start(area);
58fbcdf2
OD
1092}
1093
f2333421
OD
1094/**
1095 * Enable SR on the given IS-IS area.
1096 *
1097 * @param area IS-IS area
1098 *
1099 * @return 0 on success, -1 otherwise
1100 */
26f6acaf
RW
1101int isis_sr_start(struct isis_area *area)
1102{
1103 struct isis_sr_db *srdb = &area->srdb;
75eddbc3 1104 struct isis_adjacency *adj;
26f6acaf
RW
1105 struct listnode *node;
1106
58fbcdf2
OD
1107 /* First start Label Manager if not ready */
1108 if (!isis_zebra_label_manager_ready())
1109 if (isis_zebra_label_manager_connect() < 0) {
1110 /* Re-attempt to connect to Label Manager in 1 sec. */
1111 thread_add_timer(master, sr_start_label_manager, area,
1112 1, &srdb->t_start_lm);
1113 return -1;
1114 }
1115
1116 /* Label Manager is ready, initialize the SRLB */
1117 if (sr_local_block_init(area) < 0)
d8391312
OD
1118 return -1;
1119
26f6acaf 1120 /*
58fbcdf2
OD
1121 * Request SGRB to the label manager if not already active. If the
1122 * allocation fails, return an error to disable SR until a new SRGB
1123 * is successfully allocated.
26f6acaf 1124 */
58fbcdf2
OD
1125 if (!srdb->srgb_active) {
1126 if (isis_zebra_request_label_range(
1127 srdb->config.srgb_lower_bound,
1128 srdb->config.srgb_upper_bound
1129 - srdb->config.srgb_lower_bound + 1)
1130 < 0) {
1131 srdb->srgb_active = false;
1132 return -1;
1133 } else
1134 srdb->srgb_active = true;
1135 }
26f6acaf 1136
b407c77a
OD
1137 sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
1138 area->area_tag);
26f6acaf 1139
f2333421 1140 /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
75eddbc3
RW
1141 for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
1142 if (adj->ipv4_address_count > 0)
1143 sr_adj_sid_add(adj, AF_INET);
173f8887 1144 if (adj->ll_ipv6_count > 0)
75eddbc3 1145 sr_adj_sid_add(adj, AF_INET6);
26f6acaf
RW
1146 }
1147
58fbcdf2
OD
1148 area->srdb.enabled = true;
1149
f2333421 1150 /* Regenerate LSPs to advertise Segment Routing capabilities. */
26f6acaf
RW
1151 lsp_regenerate_schedule(area, area->is_type, 0);
1152
1153 return 0;
1154}
1155
f2333421
OD
1156/**
1157 * Disable SR on the given IS-IS area.
1158 *
1159 * @param area IS-IS area
1160 */
26f6acaf
RW
1161void isis_sr_stop(struct isis_area *area)
1162{
1163 struct isis_sr_db *srdb = &area->srdb;
1164 struct sr_adjacency *sra;
1165 struct listnode *node, *nnode;
1166
b407c77a
OD
1167 sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
1168 area->area_tag);
26f6acaf 1169
58fbcdf2 1170 /* Disable any re-attempt to connect to Label Manager */
fa935aa7 1171 THREAD_OFF(srdb->t_start_lm);
58fbcdf2 1172
f2333421 1173 /* Uninstall all local Adjacency-SIDs. */
26f6acaf 1174 for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
b1d80d43 1175 sr_adj_sid_del(sra);
26f6acaf 1176
58fbcdf2
OD
1177 /* Release SRGB if active. */
1178 if (srdb->srgb_active) {
1179 isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
1180 srdb->config.srgb_upper_bound);
1181 srdb->srgb_active = false;
1182 }
26f6acaf 1183
d8391312
OD
1184 /* Delete SRLB */
1185 sr_local_block_delete(area);
1186
58fbcdf2
OD
1187 area->srdb.enabled = false;
1188
f2333421 1189 /* Regenerate LSPs to advertise that the Node is no more SR enable. */
26f6acaf
RW
1190 lsp_regenerate_schedule(area, area->is_type, 0);
1191}
1192
f2333421
OD
1193/**
1194 * IS-IS Segment Routing initialization for given area.
1195 *
1196 * @param area IS-IS area
1197 */
26f6acaf
RW
1198void isis_sr_area_init(struct isis_area *area)
1199{
1200 struct isis_sr_db *srdb = &area->srdb;
1201
b407c77a
OD
1202 sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
1203 area->area_tag);
1204
f2333421 1205 /* Initialize Segment Routing Data Base */
26f6acaf 1206 memset(srdb, 0, sizeof(*srdb));
26f6acaf
RW
1207 srdb->adj_sids = list_new();
1208
26f6acaf
RW
1209 /* Pull defaults from the YANG module. */
1210#ifndef FABRICD
1211 srdb->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SR);
01d43141
EDP
1212 srdb->config.srgb_lower_bound = yang_get_default_uint32(
1213 "%s/label-blocks/srgb/lower-bound", ISIS_SR);
1214 srdb->config.srgb_upper_bound = yang_get_default_uint32(
1215 "%s/label-blocks/srgb/upper-bound", ISIS_SR);
1216 srdb->config.srlb_lower_bound = yang_get_default_uint32(
1217 "%s/label-blocks/srlb/lower-bound", ISIS_SR);
1218 srdb->config.srlb_upper_bound = yang_get_default_uint32(
1219 "%s/label-blocks/srlb/upper-bound", ISIS_SR);
26f6acaf
RW
1220#else
1221 srdb->config.enabled = false;
1222 srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND;
1223 srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND;
d8391312
OD
1224 srdb->config.srlb_lower_bound = SRLB_LOWER_BOUND;
1225 srdb->config.srlb_upper_bound = SRLB_UPPER_BOUND;
26f6acaf
RW
1226#endif
1227 srdb->config.msd = 0;
cab10e86 1228 srdb_prefix_cfg_init(&srdb->config.prefix_sids);
26f6acaf
RW
1229}
1230
f2333421
OD
1231/**
1232 * Terminate IS-IS Segment Routing for the given area.
1233 *
1234 * @param area IS-IS area
1235 */
26f6acaf
RW
1236void isis_sr_area_term(struct isis_area *area)
1237{
1238 struct isis_sr_db *srdb = &area->srdb;
1239
1240 /* Stop Segment Routing */
1241 if (area->srdb.enabled)
1242 isis_sr_stop(area);
1243
1fa63850
OD
1244 /* Free Adjacency SID list */
1245 list_delete(&srdb->adj_sids);
1246
26f6acaf 1247 /* Clear Prefix-SID configuration. */
cab10e86 1248 while (srdb_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
26f6acaf
RW
1249 struct sr_prefix_cfg *pcfg;
1250
cab10e86 1251 pcfg = srdb_prefix_cfg_first(&srdb->config.prefix_sids);
26f6acaf
RW
1252 isis_sr_cfg_prefix_del(pcfg);
1253 }
1254}
1255
f2333421
OD
1256/**
1257 * IS-IS Segment Routing global initialization.
1258 */
26f6acaf
RW
1259void isis_sr_init(void)
1260{
c0083e53 1261 install_element(VIEW_NODE, &show_sr_node_cmd);
26f6acaf
RW
1262
1263 /* Register hooks. */
b1d80d43
OD
1264 hook_register(isis_adj_state_change_hook, sr_adj_state_change);
1265 hook_register(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
1266 hook_register(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
b1d80d43 1267 hook_register(isis_if_new_hook, sr_if_new_hook);
26f6acaf
RW
1268}
1269
f2333421
OD
1270/**
1271 * IS-IS Segment Routing global terminate.
1272 */
26f6acaf
RW
1273void isis_sr_term(void)
1274{
1275 /* Unregister hooks. */
b1d80d43
OD
1276 hook_unregister(isis_adj_state_change_hook, sr_adj_state_change);
1277 hook_unregister(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
1278 hook_unregister(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
b1d80d43 1279 hook_unregister(isis_if_new_hook, sr_if_new_hook);
26f6acaf 1280}