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