]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_sr.c
isisd: remove unnecessary QOBJ usage
[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"
34#include "vty.h"
35#include "zclient.h"
36#include "lib/lib_errors.h"
37
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"
49
f2333421 50/* Local variables and functions */
26f6acaf
RW
51DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
52
b1d80d43 53static void sr_prefix_uninstall(struct sr_prefix *srp);
c3f7b406 54static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
d8391312
OD
55static void sr_local_block_delete(struct isis_area *area);
56static int sr_local_block_init(struct isis_area *area);
57static void sr_adj_sid_update(struct sr_adjacency *sra,
58 struct sr_local_block *srlb);
26f6acaf 59
f2333421 60/* --- RB-Tree Management functions ----------------------------------------- */
26f6acaf 61
f2333421
OD
62/**
63 * SR Prefix comparison for RB-Tree.
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 */
26f6acaf
RW
70static inline int sr_prefix_sid_compare(const struct sr_prefix *a,
71 const struct sr_prefix *b)
72{
73 return prefix_cmp(&a->prefix, &b->prefix);
74}
cab10e86 75DECLARE_RBTREE_UNIQ(srdb_node_prefix, struct sr_prefix, node_entry,
26f6acaf 76 sr_prefix_sid_compare)
cab10e86 77DECLARE_RBTREE_UNIQ(srdb_area_prefix, struct sr_prefix, area_entry,
26f6acaf
RW
78 sr_prefix_sid_compare)
79
f2333421
OD
80/**
81 * Configured SR Prefix comparison for RB-Tree.
82 *
83 * @param a First SR prefix
84 * @param b Second SR prefix
85 *
86 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
87 */
26f6acaf
RW
88static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
89 const struct sr_prefix_cfg *b)
90{
91 return prefix_cmp(&a->prefix, &b->prefix);
92}
cab10e86 93DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
26f6acaf
RW
94 sr_prefix_sid_cfg_compare)
95
f2333421
OD
96/**
97 * SR Node comparison for RB-Tree.
98 *
99 * @param a First SR node
100 * @param b Second SR node
101 *
102 * @return -1 (a < b), 0 (a == b) or +1 (a > b)
103 */
26f6acaf
RW
104static inline int sr_node_compare(const struct sr_node *a,
105 const struct sr_node *b)
106{
107 return memcmp(a->sysid, b->sysid, ISIS_SYS_ID_LEN);
108}
cab10e86 109DECLARE_RBTREE_UNIQ(srdb_node, struct sr_node, entry, sr_node_compare)
26f6acaf 110
f2333421 111/* --- Functions used for Yang model and CLI to configure Segment Routing --- */
26f6acaf 112
f2333421
OD
113/**
114 * Check if prefix correspond to a Node SID.
115 *
116 * @param ifp Interface
117 * @param prefix Prefix to be checked
118 *
119 * @return True if the interface/address pair corresponds to a Node-SID
120 */
b1d80d43
OD
121static bool sr_prefix_is_node_sid(const struct interface *ifp,
122 const struct prefix *prefix)
26f6acaf
RW
123{
124 return (if_is_loopback(ifp) && is_host_route(prefix));
125}
126
f2333421
OD
127/**
128 * Update local SRGB configuration. SRGB is reserved though Label Manager.
129 * This function trigger the update of local Prefix-SID installation.
130 *
131 * @param area IS-IS area
132 * @param lower_bound Lower bound of SRGB
133 * @param upper_bound Upper bound of SRGB
134 *
135 * @return 0 on success, -1 otherwise
136 */
26f6acaf
RW
137int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
138 uint32_t upper_bound)
139{
140 struct isis_sr_db *srdb = &area->srdb;
141
d8391312
OD
142 sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
143 area->area_tag, lower_bound, upper_bound);
b407c77a 144
58fbcdf2
OD
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;
150 return 0;
151 }
152
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,
26f6acaf 156 srdb->config.srgb_upper_bound);
58fbcdf2
OD
157 srdb->srgb_active = false;
158 }
26f6acaf
RW
159
160 srdb->config.srgb_lower_bound = lower_bound;
161 srdb->config.srgb_upper_bound = upper_bound;
162
163 if (srdb->enabled) {
164 struct sr_prefix *srp;
165
d8391312 166 /* then request new SRGB if SR is enabled. */
26f6acaf
RW
167 if (isis_zebra_request_label_range(
168 srdb->config.srgb_lower_bound,
169 srdb->config.srgb_upper_bound
58fbcdf2
OD
170 - srdb->config.srgb_lower_bound + 1) < 0) {
171 srdb->srgb_active = false;
26f6acaf 172 return -1;
58fbcdf2
OD
173 } else
174 srdb->srgb_active = true;
175
26f6acaf 176
d8391312 177 sr_debug(" |- Got new SRGB [%u/%u]",
b407c77a
OD
178 srdb->config.srgb_lower_bound,
179 srdb->config.srgb_upper_bound);
180
26f6acaf
RW
181 /* Reinstall local Prefix-SIDs to update their input labels. */
182 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
cab10e86 183 frr_each (srdb_area_prefix,
26f6acaf 184 &area->srdb.prefix_sids[level - 1], srp) {
b1d80d43 185 sr_prefix_reinstall(srp, false);
26f6acaf
RW
186 }
187 }
188
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. */
58fbcdf2 192 isis_sr_start(area);
26f6acaf
RW
193 }
194
195 return 0;
196}
197
d8391312
OD
198/**
199 * Update Segment Routing Local Block range which is reserved though the
200 * Label Manager. This function trigger the update of local Adjacency-SID
201 * installation.
202 *
203 * @param area IS-IS area
204 * @param lower_bound Lower bound of SRLB
205 * @param upper_bound Upper bound of SRLB
206 *
207 * @return 0 on success, -1 otherwise
208 */
209int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound,
210 uint32_t upper_bound)
211{
212 struct isis_sr_db *srdb = &area->srdb;
213 struct listnode *node, *nnode;
214 struct sr_adjacency *sra;
d8391312
OD
215
216 sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
217 area->area_tag, lower_bound, upper_bound);
218
58fbcdf2
OD
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;
224 return 0;
225 }
226
227 /* LM is ready, start by deleting the old SRLB */
d8391312
OD
228 sr_local_block_delete(area);
229
230 srdb->config.srlb_lower_bound = lower_bound;
231 srdb->config.srlb_upper_bound = upper_bound;
232
58fbcdf2
OD
233 if (srdb->enabled) {
234 /* Initialize new SRLB */
235 if (sr_local_block_init(area) != 0)
236 return -1;
d8391312 237
58fbcdf2
OD
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);
d8391312 241
58fbcdf2
OD
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. */
246 isis_sr_start(area);
247 }
d8391312
OD
248
249 return 0;
250}
251
f2333421
OD
252/**
253 * Add new Prefix-SID configuration to the SRDB.
254 *
255 * @param area IS-IS area
256 * @param prefix Prefix to be added
257 *
258 * @return Newly added Prefix-SID configuration structure
259 */
26f6acaf
RW
260struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
261 const struct prefix *prefix)
262{
263 struct sr_prefix_cfg *pcfg;
264 struct interface *ifp;
265
b407c77a
OD
266 sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
267
26f6acaf
RW
268 pcfg = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*pcfg));
269 pcfg->prefix = *prefix;
270 pcfg->area = area;
271
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);
277
278 /* Set the N-flag when appropriate. */
279 ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
b1d80d43 280 if (ifp && sr_prefix_is_node_sid(ifp, prefix))
26f6acaf
RW
281 pcfg->node_sid = true;
282
283 /* Save prefix-sid configuration. */
cab10e86 284 srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
26f6acaf
RW
285
286 return pcfg;
287}
288
f2333421
OD
289/**
290 * Removal of locally configured Prefix-SID.
291 *
292 * @param pcfg Configured Prefix-SID
293 */
26f6acaf
RW
294void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
295{
b407c77a
OD
296 struct isis_area *area = pcfg->area;
297
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",
301 pcfg->sid);
26f6acaf 302
cab10e86 303 srdb_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
26f6acaf
RW
304 XFREE(MTYPE_ISIS_SR_INFO, pcfg);
305}
306
f2333421
OD
307/**
308 * Lookup for Prefix-SID in the local configuration.
309 *
310 * @param area IS-IS area
311 * @param prefix Prefix to lookup
312 *
313 * @return Configured Prefix-SID structure if found, NULL otherwise
314 */
26f6acaf
RW
315struct sr_prefix_cfg *isis_sr_cfg_prefix_find(struct isis_area *area,
316 union prefixconstptr prefix)
317{
318 struct sr_prefix_cfg pcfg = {};
319
320 prefix_copy(&pcfg.prefix, prefix.p);
cab10e86 321 return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
26f6acaf
RW
322}
323
f2333421
OD
324/**
325 * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
326 *
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
330 */
26f6acaf
RW
331void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
332 struct isis_prefix_sid *psid)
333{
334 /* Set SID algorithm. */
335 psid->algorithm = SR_ALGORITHM_SPF;
336
337 /* Set SID flags. */
338 psid->flags = 0;
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);
343 break;
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);
347 break;
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);
351 break;
352 }
353 if (external)
354 SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED);
355 if (pcfg->node_sid)
356 SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);
357
358 /* Set SID value. */
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);
363 }
364}
365
f2333421 366/* --- Segment Routing Prefix Management functions -------------------------- */
26f6acaf 367
f2333421
OD
368/**
369 * Add Segment Routing Prefix to a given Segment Routing Node.
370 *
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
376 *
377 * @return New Segment Routing Prefix structure
378 */
b1d80d43
OD
379static struct sr_prefix *sr_prefix_add(struct isis_area *area,
380 struct sr_node *srn,
381 union prefixconstptr prefix, bool local,
382 const struct isis_prefix_sid *psid)
26f6acaf
RW
383{
384 struct sr_prefix *srp;
385
386 srp = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srp));
387 prefix_copy(&srp->prefix, prefix.p);
388 srp->sid = *psid;
b1d80d43 389 srp->input_label = MPLS_INVALID_LABEL;
26f6acaf
RW
390 if (local) {
391 srp->type = ISIS_SR_PREFIX_LOCAL;
392 isis_sr_nexthop_reset(&srp->u.local.info);
393 } else {
394 srp->type = ISIS_SR_PREFIX_REMOTE;
395 srp->u.remote.rinfo = NULL;
396 }
397 srp->srn = srn;
cab10e86 398 srdb_node_prefix_add(&srn->prefix_sids, srp);
26f6acaf 399 /* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
cab10e86 400 srdb_area_prefix_add(&area->srdb.prefix_sids[srn->level - 1], srp);
26f6acaf 401
b407c77a
OD
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));
405
26f6acaf
RW
406 return srp;
407}
408
f2333421
OD
409/**
410 * Remove given Segment Prefix from given Segment Routing Node.
411 * Prefix-SID is un-installed first.
412 *
413 * @param area IS-IS area
414 * @param srn Segment Routing Node
415 * @param srp Segment Routing Prefix
416 */
b1d80d43
OD
417static void sr_prefix_del(struct isis_area *area, struct sr_node *srn,
418 struct sr_prefix *srp)
26f6acaf 419{
b407c77a
OD
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));
423
b1d80d43 424 sr_prefix_uninstall(srp);
cab10e86
OD
425 srdb_node_prefix_del(&srn->prefix_sids, srp);
426 srdb_area_prefix_del(&area->srdb.prefix_sids[srn->level - 1], srp);
26f6acaf
RW
427 XFREE(MTYPE_ISIS_SR_INFO, srp);
428}
429
f2333421
OD
430/**
431 * Find Segment Routing Prefix by Area.
432 *
433 * @param area IS-IS area
434 * @param level IS-IS level
435 * @param prefix Prefix to lookup
436 *
437 * @return Segment Routing Prefix structure if found, NULL otherwise
438 */
b1d80d43
OD
439static struct sr_prefix *sr_prefix_find_by_area(struct isis_area *area,
440 int level,
441 union prefixconstptr prefix)
26f6acaf
RW
442{
443 struct sr_prefix srp = {};
444
445 prefix_copy(&srp.prefix, prefix.p);
f2333421 446 return srdb_area_prefix_find(&area->srdb.prefix_sids[level - 1], &srp);
26f6acaf
RW
447}
448
f2333421
OD
449/**
450 * Find Segment Routing Prefix by Segment Routing Node.
451 *
452 * @param srn Segment Routing Node
453 * @param prefix Prefix to lookup
454 *
455 * @return Segment Routing Prefix structure if found, NULL otherwise
456 */
b1d80d43
OD
457static struct sr_prefix *sr_prefix_find_by_node(struct sr_node *srn,
458 union prefixconstptr prefix)
26f6acaf
RW
459{
460 struct sr_prefix srp = {};
461
462 prefix_copy(&srp.prefix, prefix.p);
cab10e86 463 return srdb_node_prefix_find(&srn->prefix_sids, &srp);
26f6acaf
RW
464}
465
f2333421
OD
466/* --- Segment Routing Node Management functions ---------------------------- */
467
468/**
469 * Add Segment Routing Node to the Segment Routing Data Base.
470 *
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
475 *
476 * @return New Segment Routing Node structure
477 */
b1d80d43 478static struct sr_node *sr_node_add(struct isis_area *area, int level,
d8391312 479 const uint8_t *sysid)
26f6acaf
RW
480{
481 struct sr_node *srn;
482
483 srn = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srn));
484 srn->level = level;
485 memcpy(srn->sysid, sysid, ISIS_SYS_ID_LEN);
26f6acaf 486 srn->area = area;
cab10e86
OD
487 srdb_node_prefix_init(&srn->prefix_sids);
488 srdb_node_add(&area->srdb.sr_nodes[level - 1], srn);
26f6acaf 489
b407c77a
OD
490 sr_debug(" |- Added new SR Node %s", sysid_print(srn->sysid));
491
26f6acaf
RW
492 return srn;
493}
494
b1d80d43 495static void sr_node_del(struct isis_area *area, int level, struct sr_node *srn)
f2333421
OD
496/**
497 * Remove Segment Routing Node from the Segment Routing Data Base.
498 * All Prefix-SID attached to this Segment Routing Node are removed first.
499 *
500 * @param area IS-IS area
501 * @param level IS-IS level
502 * @param srn Segment Routing Node to be deleted
503 */
26f6acaf 504{
b407c77a
OD
505
506 sr_debug(" |- Delete SR Node %s", sysid_print(srn->sysid));
507
26f6acaf 508 /* Remove and uninstall Prefix-SIDs. */
cab10e86 509 while (srdb_node_prefix_count(&srn->prefix_sids) > 0) {
26f6acaf
RW
510 struct sr_prefix *srp;
511
cab10e86 512 srp = srdb_node_prefix_first(&srn->prefix_sids);
b1d80d43 513 sr_prefix_del(area, srn, srp);
26f6acaf
RW
514 }
515
cab10e86 516 srdb_node_del(&area->srdb.sr_nodes[level - 1], srn);
26f6acaf
RW
517 XFREE(MTYPE_ISIS_SR_INFO, srn);
518}
519
f2333421
OD
520/**
521 * Find Segment Routing Node in the Segment Routing Data Base per system ID.
522 *
523 * @param area IS-IS area
524 * @param level IS-IS level
525 * @param sysid Node System ID to lookup
526 *
527 * @return Segment Routing Node structure if found, NULL otherwise
528 */
b1d80d43
OD
529static struct sr_node *sr_node_find(struct isis_area *area, int level,
530 const uint8_t *sysid)
26f6acaf
RW
531{
532 struct sr_node srn = {};
533
534 memcpy(srn.sysid, sysid, ISIS_SYS_ID_LEN);
cab10e86 535 return srdb_node_find(&area->srdb.sr_nodes[level - 1], &srn);
26f6acaf
RW
536}
537
f2333421
OD
538/**
539 * Update Segment Routing Node following an SRGB update. This function
540 * is called when a neighbor SR Node has updated its SRGB.
541 *
542 * @param area IS-IS area
543 * @param level IS-IS level
544 * @param sysid Segment Routing Node system ID
545 */
b1d80d43
OD
546static void sr_node_srgb_update(struct isis_area *area, int level,
547 uint8_t *sysid)
26f6acaf
RW
548{
549 struct sr_prefix *srp;
550
b407c77a
OD
551 sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
552 area->area_tag);
553
b1d80d43 554 frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
26f6acaf
RW
555 struct listnode *node;
556 struct isis_nexthop *nh;
557
558 if (srp->type == ISIS_SR_PREFIX_LOCAL)
559 continue;
560
561 if (srp->u.remote.rinfo == NULL)
562 continue;
563
564 for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
565 nh)) {
566 if (memcmp(nh->sysid, sysid, ISIS_SYS_ID_LEN) != 0)
567 continue;
568
569 /*
c3f7b406
OD
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).
26f6acaf 574 */
b1d80d43 575 sr_prefix_reinstall(srp, true);
26f6acaf
RW
576 break;
577 }
578 }
579}
580
f2333421
OD
581/* --- Segment Routing Nexthop information Management functions ------------- */
582
583/**
584 * Update Segment Routing Nexthop.
585 *
586 * @param srnh Segment Routing next hop
587 * @param label Output MPLS label
588 */
26f6acaf
RW
589void isis_sr_nexthop_update(struct sr_nexthop_info *srnh, mpls_label_t label)
590{
591 srnh->label = label;
592 if (srnh->uptime == 0)
593 srnh->uptime = time(NULL);
594}
595
f2333421
OD
596/**
597 * Reset Segment Routing Nexthop.
598 *
599 * @param srnh Segment Routing Nexthop
600 */
26f6acaf
RW
601void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh)
602{
603 srnh->label = MPLS_INVALID_LABEL;
604 srnh->uptime = 0;
605}
606
f2333421 607/* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
26f6acaf 608
f2333421
OD
609/**
610 * Lookup IS-IS route in the Shortest Path Tree.
611 *
612 * @param area IS-IS area
613 * @param tree_id Shortest Path Tree identifier
614 * @param srp Segment Routing Prefix to lookup
615 *
616 * @return Route Information for this prefix if found, NULL otherwise
617 */
b1d80d43
OD
618static struct isis_route_info *sr_prefix_lookup_route(struct isis_area *area,
619 enum spf_tree_id tree_id,
620 struct sr_prefix *srp)
26f6acaf
RW
621{
622 struct route_node *rn;
623 int level = srp->srn->level;
624
625 rn = route_node_lookup(area->spftree[tree_id][level - 1]->route_table,
626 &srp->prefix);
627 if (rn) {
628 route_unlock_node(rn);
629 if (rn->info)
630 return rn->info;
631 }
632
633 return NULL;
634}
635
f2333421
OD
636/**
637 * Compute input label for the given Prefix-SID.
638 *
639 * @param srp Segment Routing Prefix
640 *
641 * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
642 */
b1d80d43 643static mpls_label_t sr_prefix_in_label(const struct sr_prefix *srp)
26f6acaf
RW
644{
645 const struct sr_node *srn = srp->srn;
646 struct isis_area *area = srn->area;
647
f2333421 648 /* Return SID value as MPLS label if it is an Absolute SID */
26f6acaf
RW
649 if (CHECK_FLAG(srp->sid.flags,
650 ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
651 return srp->sid.value;
652
f2333421 653 /* Check that SID index falls inside the SRGB */
26f6acaf
RW
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;
660 }
661
f2333421 662 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
26f6acaf
RW
663 return (area->srdb.config.srgb_lower_bound + srp->sid.value);
664}
665
f2333421
OD
666/**
667 * Compute output label for the given Prefix-SID.
668 *
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
672 *
673 * @return MPLS label or MPLS_INVALID_LABEL in case of error
674 */
b1d80d43
OD
675static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
676 const struct sr_node *srn_nexthop,
677 const uint8_t *sysid)
26f6acaf
RW
678{
679 const struct sr_node *srn = srp->srn;
680
f2333421 681 /* Check if the nexthop SR Node is the last hop? */
26f6acaf 682 if (memcmp(sysid, srn->sysid, ISIS_SYS_ID_LEN) == 0) {
f2333421 683 /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
26f6acaf
RW
684 if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP))
685 return MPLS_LABEL_IMPLICIT_NULL;
686
f2333421 687 /* SR-Node requests Implicit NULL Label */
26f6acaf
RW
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;
691 else
692 return MPLS_LABEL_IPV6_EXPLICIT_NULL;
693 }
694 /* Fallthrough */
695 }
696
f2333421 697 /* Return SID value as MPLS label if it is an Absolute SID */
26f6acaf
RW
698 if (CHECK_FLAG(srp->sid.flags,
699 ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
700 /*
701 * V/L SIDs have local significance, so only adjacent routers
f2333421 702 * can use them (RFC8667 section #2.1.1.1)
26f6acaf
RW
703 */
704 if (srp->srn != srn_nexthop)
705 return MPLS_INVALID_LABEL;
706 return srp->sid.value;
707 }
708
f2333421 709 /* Check that SID index falls inside the SRGB */
26f6acaf
RW
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;
715 }
716
f2333421 717 /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
26f6acaf
RW
718 return (srn_nexthop->cap.srgb.lower_bound + srp->sid.value);
719}
720
f2333421
OD
721/**
722 * Process local Prefix-SID and install it if possible. Input label is
723 * computed before installing it in LFIB.
724 *
725 * @param srp Segment Routing Prefix
726 *
727 * @return 0 on success, -1 otherwise
728 */
b1d80d43 729static int sr_prefix_install_local(struct sr_prefix *srp)
26f6acaf 730{
b1d80d43 731 mpls_label_t input_label;
b407c77a 732 const struct sr_node *srn = srp->srn;
26f6acaf
RW
733
734 /*
f2333421 735 * No need to install Label for local Prefix-SID unless the
26f6acaf
RW
736 * no-PHP option is configured.
737 */
738 if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP)
739 || CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL))
740 return -1;
741
b407c77a
OD
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));
26f6acaf 745
f2333421 746 /* Compute input label and check that is valid. */
b1d80d43
OD
747 input_label = sr_prefix_in_label(srp);
748 if (input_label == MPLS_INVALID_LABEL)
26f6acaf
RW
749 return -1;
750
751 /* Update internal state. */
b1d80d43 752 srp->input_label = input_label;
26f6acaf
RW
753 isis_sr_nexthop_update(&srp->u.local.info, MPLS_LABEL_IMPLICIT_NULL);
754
755 /* Install Prefix-SID in the forwarding plane. */
c3f7b406 756 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
26f6acaf
RW
757
758 return 0;
759}
760
f2333421
OD
761/**
762 * Process remote Prefix-SID and install it if possible. Input and Output
763 * labels are computed before installing them in LFIB.
764 *
765 * @param srp Segment Routing Prefix
766 *
767 * @return 0 on success, -1 otherwise
768 */
b1d80d43 769static int sr_prefix_install_remote(struct sr_prefix *srp)
26f6acaf
RW
770{
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;
b1d80d43 776 mpls_label_t input_label;
26f6acaf
RW
777 size_t nexthop_num = 0;
778
f2333421 779 /* Lookup to associated IS-IS route. */
26f6acaf 780 tree_id = (srp->prefix.family == AF_INET) ? SPFTREE_IPV4 : SPFTREE_IPV6;
b1d80d43 781 srp->u.remote.rinfo = sr_prefix_lookup_route(area, tree_id, srp);
26f6acaf
RW
782 if (!srp->u.remote.rinfo)
783 /* SPF hasn't converged for this route yet. */
784 return -1;
785
f2333421 786 /* Compute input label and check that is valid. */
b1d80d43
OD
787 input_label = sr_prefix_in_label(srp);
788 if (input_label == MPLS_INVALID_LABEL)
26f6acaf
RW
789 return -1;
790
b407c77a
OD
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));
794
f2333421 795 /* Process all SPF nexthops */
26f6acaf
RW
796 for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
797 nexthop)) {
798 struct sr_node *srn_nexthop;
b1d80d43 799 mpls_label_t output_label;
26f6acaf
RW
800
801 /* Check if the nexthop advertised a SRGB. */
b1d80d43 802 srn_nexthop = sr_node_find(area, srn->level, nexthop->sysid);
26f6acaf
RW
803 if (!srn_nexthop)
804 goto next;
805
806 /*
807 * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
808 * IPv6 packets.
809 */
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)))
814 goto next;
815
f2333421 816 /* Compute output label and check if it is valid */
b407c77a
OD
817 output_label =
818 sr_prefix_out_label(srp, srn_nexthop, nexthop->sysid);
b1d80d43 819 if (output_label == MPLS_INVALID_LABEL)
26f6acaf
RW
820 goto next;
821
e740f9c1 822 if (IS_DEBUG_SR) {
26f6acaf
RW
823 static char buf[INET6_ADDRSTRLEN];
824
825 inet_ntop(nexthop->family, &nexthop->ip, buf,
826 sizeof(buf));
b407c77a
OD
827 zlog_debug(" |- nexthop %s label %u", buf,
828 output_label);
26f6acaf
RW
829 }
830
b1d80d43 831 isis_sr_nexthop_update(&nexthop->sr, output_label);
26f6acaf
RW
832 nexthop_num++;
833 continue;
834 next:
835 isis_sr_nexthop_reset(&nexthop->sr);
836 }
f2333421
OD
837
838 /* Check that we found at least one valid nexthop */
26f6acaf 839 if (nexthop_num == 0) {
b407c77a 840 sr_debug(" |- no valid nexthops");
26f6acaf
RW
841 return -1;
842 }
843
844 /* Update internal state. */
b1d80d43 845 srp->input_label = input_label;
26f6acaf
RW
846
847 /* Install Prefix-SID in the forwarding plane. */
c3f7b406 848 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
26f6acaf
RW
849
850 return 0;
851}
852
f2333421
OD
853/**
854 * Process local or remote Prefix-SID and install it if possible.
855 *
856 * @param srp Segment Routing Prefix
857 */
b1d80d43 858static void sr_prefix_install(struct sr_prefix *srp)
26f6acaf
RW
859{
860 const struct sr_node *srn = srp->srn;
861 struct isis_area *area = srn->area;
862 int ret;
863
b407c77a
OD
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",
866 srp->sid.value);
867
26f6acaf
RW
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;
871
872 switch (srn->level) {
873 case ISIS_LEVEL1:
b1d80d43
OD
874 srp_l2 = sr_prefix_find_by_area(area, ISIS_LEVEL2,
875 &srp->prefix);
26f6acaf 876 if (srp_l2)
b1d80d43 877 sr_prefix_uninstall(srp_l2);
26f6acaf
RW
878 break;
879 case ISIS_LEVEL2:
b1d80d43
OD
880 srp_l1 = sr_prefix_find_by_area(area, ISIS_LEVEL1,
881 &srp->prefix);
26f6acaf
RW
882 if (srp_l1)
883 return;
884 break;
885 default:
886 break;
887 }
888 }
889
f2333421 890 /* Install corresponding LFIB entry */
26f6acaf 891 if (srp->type == ISIS_SR_PREFIX_LOCAL)
b1d80d43 892 ret = sr_prefix_install_local(srp);
26f6acaf 893 else
b1d80d43 894 ret = sr_prefix_install_remote(srp);
26f6acaf 895 if (ret != 0)
b1d80d43 896 sr_prefix_uninstall(srp);
26f6acaf
RW
897}
898
f2333421
OD
899/**
900 * Uninstall local or remote Prefix-SID.
901 *
902 * @param srp Segment Routing Prefix
903 */
b1d80d43 904static void sr_prefix_uninstall(struct sr_prefix *srp)
26f6acaf 905{
26f6acaf
RW
906 struct listnode *node;
907 struct isis_nexthop *nexthop;
908
f2333421 909 /* Check that Input Label is valid */
b1d80d43 910 if (srp->input_label == MPLS_INVALID_LABEL)
26f6acaf
RW
911 return;
912
b407c77a
OD
913 sr_debug("ISIS-Sr: Un-install Prefix-SID %pFX %s %u", &srp->prefix,
914 IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
915 srp->sid.value);
26f6acaf
RW
916
917 /* Uninstall Prefix-SID from the forwarding plane. */
c3f7b406 918 isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE, srp);
26f6acaf
RW
919
920 /* Reset internal state. */
b1d80d43 921 srp->input_label = MPLS_INVALID_LABEL;
26f6acaf
RW
922 switch (srp->type) {
923 case ISIS_SR_PREFIX_LOCAL:
924 isis_sr_nexthop_reset(&srp->u.local.info);
925 break;
926 case ISIS_SR_PREFIX_REMOTE:
927 if (srp->u.remote.rinfo) {
928 for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops,
929 node, nexthop))
930 isis_sr_nexthop_reset(&nexthop->sr);
931 }
932 break;
933 }
934}
935
f2333421
OD
936/**
937 * Reinstall local or remote Prefix-SID.
938 *
939 * @param srp Segment Routing Prefix
940 */
c3f7b406
OD
941static inline void sr_prefix_reinstall(struct sr_prefix *srp,
942 bool make_before_break)
26f6acaf
RW
943{
944 /*
c3f7b406 945 * Make Before Break can be used only when we know for sure that
26f6acaf
RW
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
948 * reinstalling it.
949 */
c3f7b406 950 if (!make_before_break)
b1d80d43 951 sr_prefix_uninstall(srp);
26f6acaf 952
f2333421 953 /* New input label is computed in sr_prefix_install() function */
b1d80d43 954 sr_prefix_install(srp);
26f6acaf
RW
955}
956
f2333421 957/* --- IS-IS LSP Parse functions -------------------------------------------- */
26f6acaf 958
d8391312
OD
959/**
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.
962 *
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
966 */
967static int router_cap_cmp(const struct isis_router_cap *r1,
968 const struct isis_router_cap *r2)
969{
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])
974 return 0;
975 else
976 return -1;
977}
978
f2333421
OD
979/**
980 * Parse all SR-related information from the given Router Capabilities TLV.
981 *
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
986 *
987 * @return Segment Routing Node structure for this System ID
988 */
26f6acaf 989static struct sr_node *
b1d80d43
OD
990parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid,
991 const struct isis_router_cap *router_cap)
26f6acaf
RW
992{
993 struct sr_node *srn;
994
995 if (!router_cap || router_cap->srgb.range_size == 0)
996 return NULL;
997
b407c77a
OD
998 sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area->area_tag);
999
b1d80d43 1000 srn = sr_node_find(area, level, sysid);
26f6acaf 1001 if (srn) {
d8391312 1002 if (router_cap_cmp(&srn->cap, router_cap) != 0) {
cab10e86 1003 srn->state = SRDB_STATE_MODIFIED;
26f6acaf 1004 } else
cab10e86 1005 srn->state = SRDB_STATE_UNCHANGED;
b407c77a
OD
1006 sr_debug(" |- Found %s SR Node %s",
1007 srn->state == SRDB_STATE_MODIFIED ? "Modified"
1008 : "Unchanged",
1009 sysid_print(srn->sysid));
26f6acaf 1010 } else {
d8391312 1011 srn = sr_node_add(area, level, sysid);
cab10e86 1012 srn->state = SRDB_STATE_NEW;
26f6acaf
RW
1013 }
1014
d8391312
OD
1015 /*
1016 * Update Router Capabilities in any case as SRLB or MSD
1017 * modification are not take into account for comparison.
1018 */
1019 srn->cap = *router_cap;
1020
26f6acaf
RW
1021 return srn;
1022}
1023
f2333421
OD
1024/**
1025 * Parse list of Prefix-SID Sub-TLVs.
1026 *
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
1031 */
b1d80d43
OD
1032static void parse_prefix_sid_subtlvs(struct sr_node *srn,
1033 union prefixconstptr prefix, bool local,
1034 struct isis_item_list *prefix_sids)
26f6acaf
RW
1035{
1036 struct isis_area *area = srn->area;
1037 struct isis_item *i;
1038
b407c77a
OD
1039 sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area->area_tag);
1040
f2333421 1041 /* Parse list of Prefix SID subTLVs */
26f6acaf
RW
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;
1045
f2333421 1046 /* Only SPF algorithm is supported right now */
26f6acaf
RW
1047 if (psid->algorithm != SR_ALGORITHM_SPF)
1048 continue;
1049
f2333421 1050 /* Compute corresponding Segment Routing Prefix */
b1d80d43 1051 srp = sr_prefix_find_by_node(srn, prefix);
26f6acaf
RW
1052 if (srp) {
1053 if (srp->sid.flags != psid->flags
1054 || srp->sid.algorithm != psid->algorithm
1055 || srp->sid.value != psid->value) {
1056 srp->sid = *psid;
cab10e86 1057 srp->state = SRDB_STATE_MODIFIED;
0a5b7077 1058 } else if (srp->state == SRDB_STATE_VALIDATED)
cab10e86 1059 srp->state = SRDB_STATE_UNCHANGED;
b407c77a
OD
1060 sr_debug(" |- Found %s Prefix-SID %pFX",
1061 srp->state == SRDB_STATE_MODIFIED
1062 ? "Modified"
1063 : "Unchanged",
1064 &srp->prefix);
1065
26f6acaf 1066 } else {
b1d80d43 1067 srp = sr_prefix_add(area, srn, prefix, local, psid);
cab10e86 1068 srp->state = SRDB_STATE_NEW;
26f6acaf
RW
1069 }
1070 /*
1071 * Stop the Prefix-SID iteration since we only support the SPF
1072 * algorithm for now.
1073 */
1074 break;
1075 }
1076}
1077
f2333421
OD
1078/**
1079 * Parse all SR-related information from the given LSP.
1080 *
1081 * @param area IS-IS area
1082 * @param level IS-IS level
1083 * @param srn Segment Routing Node
1084 * @param lsp IS-IS LSP
1085 */
b1d80d43
OD
1086static void parse_lsp(struct isis_area *area, int level, struct sr_node **srn,
1087 struct isis_lsp *lsp)
26f6acaf
RW
1088{
1089 struct isis_item_list *items;
1090 struct isis_item *i;
1091 bool local = lsp->own_lsp;
1092
f2333421 1093 /* Check LSP sequence number */
26f6acaf
RW
1094 if (lsp->hdr.seqno == 0) {
1095 zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
1096 return;
1097 }
1098
b407c77a
OD
1099 sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area->area_tag,
1100 sysid_print(lsp->hdr.lsp_id));
1101
26f6acaf
RW
1102 /* Parse the Router Capability TLV. */
1103 if (*srn == NULL) {
b407c77a
OD
1104 *srn = parse_router_cap_tlv(area, level, lsp->hdr.lsp_id,
1105 lsp->tlvs->router_cap);
26f6acaf
RW
1106 if (!*srn)
1107 return;
1108 }
1109
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;
1114
1115 ir = (struct isis_extended_ip_reach *)i;
1116 if (!ir->subtlvs)
1117 continue;
1118
b1d80d43
OD
1119 parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
1120 &ir->subtlvs->prefix_sids);
26f6acaf
RW
1121 }
1122
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;
1128
1129 ir = (struct isis_ipv6_reach *)i;
1130 if (!ir->subtlvs)
1131 continue;
1132
b1d80d43
OD
1133 parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
1134 &ir->subtlvs->prefix_sids);
26f6acaf
RW
1135 }
1136}
1137
f2333421
OD
1138/**
1139 * Parse all SR-related information from the entire LSPDB.
1140 *
1141 * @param area IS-IS area
1142 */
b1d80d43 1143static void parse_lspdb(struct isis_area *area)
26f6acaf
RW
1144{
1145 struct isis_lsp *lsp;
1146
b407c77a
OD
1147 sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area->area_tag);
1148
f2333421 1149 /* Process all LSP from Level 1 & 2 */
26f6acaf
RW
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;
1155
f2333421 1156 /* Skip Pseudo ID LSP and LSP without TLVs */
26f6acaf
RW
1157 if (LSP_PSEUDO_ID(lsp->hdr.lsp_id))
1158 continue;
1159 if (!lsp->tlvs)
1160 continue;
1161
f2333421 1162 /* Parse LSP, then fragment */
b1d80d43 1163 parse_lsp(area, level, &srn, lsp);
26f6acaf 1164 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
b1d80d43 1165 parse_lsp(area, level, &srn, frag);
26f6acaf
RW
1166 }
1167 }
1168}
1169
f2333421
OD
1170/**
1171 * Process any new/deleted/modified Prefix-SID in the LSPDB.
1172 *
1173 * @param srn Segment Routing Node
1174 * @param srp Segment Routing Prefix
1175 */
b1d80d43 1176static void process_prefix_changes(struct sr_node *srn, struct sr_prefix *srp)
26f6acaf
RW
1177{
1178 struct isis_area *area = srn->area;
1179
26f6acaf 1180 /* Install/reinstall/uninstall Prefix-SID if necessary. */
cab10e86
OD
1181 switch (srp->state) {
1182 case SRDB_STATE_NEW:
b407c77a
OD
1183 sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
1184 area->area_tag, &srp->prefix, sysid_print(srn->sysid));
b1d80d43 1185 sr_prefix_install(srp);
cab10e86
OD
1186 break;
1187 case SRDB_STATE_MODIFIED:
b407c77a
OD
1188 sr_debug(
1189 "ISIS-Sr (%s): Modified Prefix-SID %pFX for SR node %s",
1190 area->area_tag, &srp->prefix, sysid_print(srn->sysid));
b1d80d43 1191 sr_prefix_reinstall(srp, false);
cab10e86
OD
1192 break;
1193 case SRDB_STATE_UNCHANGED:
1194 break;
1195 default:
b407c77a
OD
1196 sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
1197 area->area_tag, &srp->prefix, sysid_print(srn->sysid));
b1d80d43 1198 sr_prefix_del(area, srn, srp);
26f6acaf
RW
1199 return;
1200 }
1201
f2333421 1202 /* Validate SRDB State for next LSPDB parsing */
cab10e86 1203 srp->state = SRDB_STATE_VALIDATED;
26f6acaf
RW
1204}
1205
f2333421
OD
1206/**
1207 * Process any new/deleted/modified SRGB in the LSPDB.
1208 *
1209 * @param area IS-IS area
1210 * @param level IS-IS level
1211 * @param srn Segment Routing Node
1212 */
b1d80d43
OD
1213static void process_node_changes(struct isis_area *area, int level,
1214 struct sr_node *srn)
26f6acaf
RW
1215{
1216 struct sr_prefix *srp;
1217 uint8_t sysid[ISIS_SYS_ID_LEN];
1218 bool adjacent;
1219
1220 memcpy(sysid, srn->sysid, sizeof(sysid));
1221
26f6acaf 1222 /*
f2333421
OD
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.
26f6acaf
RW
1225 */
1226 adjacent = isis_adj_exists(area, level, sysid);
cab10e86
OD
1227 switch (srn->state) {
1228 case SRDB_STATE_NEW:
1229 case SRDB_STATE_MODIFIED:
b407c77a
OD
1230 sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
1231 area->area_tag, sysid_print(srn->sysid));
26f6acaf 1232 if (adjacent)
b407c77a 1233 sr_node_srgb_update(area, level, sysid);
cab10e86
OD
1234 break;
1235 case SRDB_STATE_UNCHANGED:
1236 break;
1237 default:
f2333421 1238 /* SR capabilities have been removed. Delete SR-Node */
b407c77a
OD
1239 sr_debug("ISIS-Sr (%s): Remove SR node %s", area->area_tag,
1240 sysid_print(srn->sysid));
26f6acaf 1241
f2333421
OD
1242 sr_node_del(area, level, srn);
1243 /* and Update remaining Prefix-SID from all remaining SR Node */
26f6acaf 1244 if (adjacent)
b1d80d43 1245 sr_node_srgb_update(area, level, sysid);
26f6acaf
RW
1246 return;
1247 }
1248
f2333421 1249 /* Validate SRDB State for next LSPDB parsing */
cab10e86 1250 srn->state = SRDB_STATE_VALIDATED;
26f6acaf 1251
f2333421 1252 /* Finally, process all Prefix-SID of this SR Node */
cab10e86 1253 frr_each_safe (srdb_node_prefix, &srn->prefix_sids, srp)
b1d80d43 1254 process_prefix_changes(srn, srp);
26f6acaf
RW
1255}
1256
f2333421
OD
1257/**
1258 * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
1259 *
1260 * @param area IS-IS area
1261 */
26f6acaf
RW
1262void isis_area_verify_sr(struct isis_area *area)
1263{
1264 struct sr_node *srn;
1265
1266 if (!area->srdb.enabled)
1267 return;
1268
1269 /* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
b1d80d43 1270 parse_lspdb(area);
26f6acaf
RW
1271
1272 /* Process possible SR-related changes in the LDPSB. */
1273 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
b1d80d43
OD
1274 frr_each_safe (srdb_node, &area->srdb.sr_nodes[level - 1], srn)
1275 process_node_changes(area, level, srn);
26f6acaf
RW
1276 }
1277}
1278
f2333421 1279/**
26f6acaf
RW
1280 * Once a route is updated in the SPT, reinstall or uninstall its corresponding
1281 * Prefix-SID (if any).
f2333421
OD
1282 *
1283 * @param area IS-IS area
1284 * @param prefix Prefix to be updated
1285 * @param route_info New Route Information
1286 *
1287 * @return 0
26f6acaf 1288 */
b1d80d43
OD
1289static int sr_route_update(struct isis_area *area, struct prefix *prefix,
1290 struct isis_route_info *route_info)
26f6acaf
RW
1291{
1292 struct sr_prefix *srp;
1293
1294 if (!area->srdb.enabled)
1295 return 0;
1296
b407c77a
OD
1297 sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area->area_tag,
1298 prefix);
1299
f2333421 1300 /* Lookup to Segment Routing Prefix for this prefix */
26f6acaf
RW
1301 switch (area->is_type) {
1302 case IS_LEVEL_1:
b1d80d43 1303 srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
26f6acaf
RW
1304 break;
1305 case IS_LEVEL_2:
b1d80d43 1306 srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
26f6acaf
RW
1307 break;
1308 case IS_LEVEL_1_AND_2:
b1d80d43 1309 srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
26f6acaf 1310 if (!srp)
b1d80d43 1311 srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
26f6acaf
RW
1312 break;
1313 default:
1314 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown area level",
1315 __func__);
1316 exit(1);
1317 }
1318
f2333421 1319 /* Skip NULL or local Segment Routing Prefix */
26f6acaf
RW
1320 if (!srp || srp->type == ISIS_SR_PREFIX_LOCAL)
1321 return 0;
1322
f2333421 1323 /* Install or unintall Prefix-SID if route is Active or not */
26f6acaf 1324 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
c3f7b406
OD
1325 /*
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).
1329 */
b1d80d43 1330 sr_prefix_reinstall(srp, true);
26f6acaf
RW
1331 srp->u.remote.rinfo = route_info;
1332 } else {
b1d80d43 1333 sr_prefix_uninstall(srp);
26f6acaf
RW
1334 srp->u.remote.rinfo = NULL;
1335 }
1336
1337 return 0;
1338}
1339
d8391312
OD
1340/* --- Segment Routing Local Block management functions --------------------- */
1341
1342/**
1343 * Initialize Segment Routing Local Block from SRDB configuration and reserve
1344 * block of bits to manage label allocation.
1345 *
1346 * @param area IS-IS area
1347 */
58fbcdf2 1348static int sr_local_block_init(struct isis_area *area)
d8391312
OD
1349{
1350 struct isis_sr_db *srdb = &area->srdb;
1351 struct sr_local_block *srlb = &srdb->srlb;
1352
58fbcdf2
OD
1353 /* Check if SRLB is not already configured */
1354 if (srlb->active)
1355 return 0;
1356
d8391312
OD
1357 /*
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.
1360 */
1361 if (isis_zebra_request_label_range(
1362 srdb->config.srlb_lower_bound,
1363 srdb->config.srlb_upper_bound
58fbcdf2
OD
1364 - srdb->config.srlb_lower_bound + 1)) {
1365 srlb->active = false;
1366 return -1;
1367 }
d8391312
OD
1368
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);
1371
1372 /* Initialize the SRLB */
1373 srlb->start = srdb->config.srlb_lower_bound;
1374 srlb->end = srdb->config.srlb_upper_bound;
1375 srlb->current = 0;
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)
1379 srlb->max_block++;
1380 srlb->used_mark = XCALLOC(MTYPE_ISIS_SR_INFO,
1381 srlb->max_block * SRLB_BLOCK_SIZE);
58fbcdf2
OD
1382 srlb->active = true;
1383
1384 return 0;
d8391312
OD
1385}
1386
1387/**
1388 * Remove Segment Routing Local Block.
1389 *
1390 * @param area IS-IS area
1391 */
1392static void sr_local_block_delete(struct isis_area *area)
1393{
1394 struct isis_sr_db *srdb = &area->srdb;
1395 struct sr_local_block *srlb = &srdb->srlb;
1396
58fbcdf2
OD
1397 /* Check if SRLB is not already delete */
1398 if (!srlb->active)
1399 return;
1400
d8391312
OD
1401 sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area->area_tag,
1402 srlb->start, srlb->end);
1403
1404 /* First release the label block */
1405 isis_zebra_release_label_range(srdb->config.srlb_lower_bound,
1406 srdb->config.srlb_upper_bound);
1407
1408 /* Then reset SRLB structure */
1409 if (srlb->used_mark != NULL)
1410 XFREE(MTYPE_ISIS_SR_INFO, srlb->used_mark);
58fbcdf2 1411 srlb->active = false;
d8391312
OD
1412}
1413
1414/**
1415 * Request a label from the Segment Routing Local Block.
1416 *
1417 * @param srlb Segment Routing Local Block
1418 *
1419 * @return First available label on success or MPLS_INVALID_LABEL if the
1420 * block of labels is full
1421 */
1422static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb)
1423{
1424
1425 mpls_label_t label;
1426 uint32_t index;
1427 uint32_t pos;
1428
1429 /* Check if we ran out of available labels */
1430 if (srlb->current >= srlb->end)
1431 return MPLS_INVALID_LABEL;
1432
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;
1438
1439 /* Jump to the next free position */
1440 srlb->current++;
1441 pos = srlb->current % SRLB_BLOCK_SIZE;
1442 while (srlb->current < srlb->end) {
1443 if (pos == 0)
1444 index++;
1445 if (!((1ULL << pos) & srlb->used_mark[index]))
1446 break;
1447 else {
1448 srlb->current++;
1449 pos = srlb->current % SRLB_BLOCK_SIZE;
1450 }
1451 }
1452
1453 return label;
1454}
1455
1456/**
1457 * Release label in the Segment Routing Local Block.
1458 *
1459 * @param srlb Segment Routing Local Block
1460 * @param label Label to be release
1461 *
1462 * @return 0 on success or -1 if label falls outside SRLB
1463 */
1464static int sr_local_block_release_label(struct sr_local_block *srlb,
1465 mpls_label_t label)
1466{
1467 uint32_t index;
1468 uint32_t pos;
1469
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);
1475 return -1;
1476 }
1477
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])) {
1486 srlb->current =
1487 index * SRLB_BLOCK_SIZE + pos;
1488 break;
1489 }
1490 break;
1491 }
1492 }
1493
1494 return 0;
1495}
1496
f2333421 1497/* --- Segment Routing Adjacency-SID management functions ------------------- */
26f6acaf 1498
f2333421
OD
1499/**
1500 * Add new local Adjacency-SID.
1501 *
1502 * @param adj IS-IS Adjacency
1503 * @param family Inet Family (IPv4 or IPv6)
1504 * @param backup True to initialize backup Adjacency SID
1505 */
b1d80d43
OD
1506static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
1507 bool backup)
26f6acaf
RW
1508{
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 = {};
1515 uint8_t flags;
b1d80d43 1516 mpls_label_t input_label;
26f6acaf 1517
b407c77a
OD
1518 sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area->area_tag,
1519 backup ? "Backup" : "Primary");
1520
f2333421 1521 /* Determine nexthop IP address */
26f6acaf
RW
1522 switch (family) {
1523 case AF_INET:
1524 if (!circuit->ip_router)
1525 return;
1526
1527 nexthop.ipv4 = adj->ipv4_addresses[0];
1528 break;
1529 case AF_INET6:
1530 if (!circuit->ipv6_router)
1531 return;
1532
1533 nexthop.ipv6 = adj->ipv6_addresses[0];
1534 break;
1535 default:
1536 flog_err(EC_LIB_DEVELOPMENT,
1537 "%s: unexpected address-family: %u", __func__, family);
1538 exit(1);
1539 }
1540
f2333421 1541 /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
26f6acaf
RW
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);
1545 if (backup)
1546 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG);
1547
d8391312
OD
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)
1551 return;
1552
26f6acaf
RW
1553 if (circuit->ext == NULL)
1554 circuit->ext = isis_alloc_ext_subtlvs();
1555
26f6acaf
RW
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;
b1d80d43 1560 sra->nexthop.label = input_label;
26f6acaf 1561 switch (circuit->circ_type) {
f2333421 1562 /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
26f6acaf
RW
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));
b1d80d43 1570 ladj_sid->sid = input_label;
26f6acaf
RW
1571 isis_tlvs_add_lan_adj_sid(circuit->ext, ladj_sid);
1572 sra->u.ladj_sid = ladj_sid;
1573 break;
f2333421 1574 /* Adjacency-SID for Point to Point interface section #2.2.1 */
26f6acaf
RW
1575 case CIRCUIT_T_P2P:
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;
b1d80d43 1580 adj_sid->sid = input_label;
26f6acaf
RW
1581 isis_tlvs_add_adj_sid(circuit->ext, adj_sid);
1582 sra->u.adj_sid = adj_sid;
1583 break;
1584 default:
1585 flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
1586 __func__, circuit->circ_type);
1587 exit(1);
1588 }
f2333421
OD
1589
1590 /* Add Adjacency-SID in SRDB */
26f6acaf
RW
1591 sra->adj = adj;
1592 listnode_add(area->srdb.adj_sids, sra);
1593 listnode_add(adj->adj_sids, sra);
1594
c3f7b406 1595 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
26f6acaf
RW
1596}
1597
f2333421
OD
1598/**
1599 * Add Primary and Backup local Adjacency SID.
1600 *
1601 * @param adj IS-IS Adjacency
1602 * @param family Inet Family (IPv4 or IPv6)
1603 */
b1d80d43 1604static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
26f6acaf 1605{
b1d80d43
OD
1606 sr_adj_sid_add_single(adj, family, false);
1607 sr_adj_sid_add_single(adj, family, true);
26f6acaf
RW
1608}
1609
d8391312
OD
1610static void sr_adj_sid_update(struct sr_adjacency *sra,
1611 struct sr_local_block *srlb)
1612{
1613 struct isis_circuit *circuit = sra->adj->circuit;
1614
1615 /* First remove the old MPLS Label */
1616 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
1617
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)
1621 return;
1622
1623 switch (circuit->circ_type) {
1624 case CIRCUIT_T_BROADCAST:
1625 sra->u.ladj_sid->sid = sra->nexthop.label;
1626 break;
1627 case CIRCUIT_T_P2P:
1628 sra->u.adj_sid->sid = sra->nexthop.label;
1629 break;
1630 default:
1631 flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
1632 __func__, circuit->circ_type);
1633 break;
1634 }
1635
1636 /* Finally configure the new MPLS Label */
1637 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
1638}
1639
f2333421
OD
1640/**
1641 * Delete local Adj-SID.
1642 *
1643 * @param sra Segment Routing Adjacency
1644 */
b1d80d43 1645static void sr_adj_sid_del(struct sr_adjacency *sra)
26f6acaf
RW
1646{
1647 struct isis_circuit *circuit = sra->adj->circuit;
1648 struct isis_area *area = circuit->area;
1649
b407c77a 1650 sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area->area_tag);
26f6acaf 1651
c3f7b406 1652 isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
26f6acaf 1653
f2333421 1654 /* Release dynamic label and remove subTLVs */
26f6acaf
RW
1655 switch (circuit->circ_type) {
1656 case CIRCUIT_T_BROADCAST:
d8391312
OD
1657 sr_local_block_release_label(&area->srdb.srlb,
1658 sra->u.ladj_sid->sid);
26f6acaf
RW
1659 isis_tlvs_del_lan_adj_sid(circuit->ext, sra->u.ladj_sid);
1660 break;
1661 case CIRCUIT_T_P2P:
d8391312
OD
1662 sr_local_block_release_label(&area->srdb.srlb,
1663 sra->u.adj_sid->sid);
26f6acaf
RW
1664 isis_tlvs_del_adj_sid(circuit->ext, sra->u.adj_sid);
1665 break;
1666 default:
1667 flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
1668 __func__, circuit->circ_type);
1669 exit(1);
1670 }
1671
f2333421 1672 /* Remove Adjacency-SID from the SRDB */
26f6acaf
RW
1673 listnode_delete(area->srdb.adj_sids, sra);
1674 listnode_delete(sra->adj->adj_sids, sra);
1675 XFREE(MTYPE_ISIS_SR_INFO, sra);
1676}
1677
f2333421
OD
1678/**
1679 * Remove all Adjacency-SIDs associated to an adjacency that is going down.
1680 *
1681 * @param adj IS-IS Adjacency
1682 *
1683 * @return 0
1684 */
b1d80d43 1685static int sr_adj_state_change(struct isis_adjacency *adj)
26f6acaf
RW
1686{
1687 struct sr_adjacency *sra;
1688 struct listnode *node, *nnode;
1689
1690 if (!adj->circuit->area->srdb.enabled)
1691 return 0;
1692
1693 if (adj->adj_state == ISIS_ADJ_UP)
1694 return 0;
1695
1696 for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
b1d80d43 1697 sr_adj_sid_del(sra);
26f6acaf
RW
1698
1699 return 0;
1700}
1701
f2333421
OD
1702/**
1703 * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
1704 * IPv6 address to corresponding Adjacency-SID accordingly.
1705 *
1706 * @param adj IS-IS Adjacency
1707 * @param family Inet Family (IPv4 or IPv6)
1708 *
1709 * @return 0
26f6acaf 1710 */
b1d80d43 1711static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
26f6acaf
RW
1712{
1713 if (!adj->circuit->area->srdb.enabled)
1714 return 0;
1715
b1d80d43 1716 sr_adj_sid_add(adj, family);
26f6acaf
RW
1717
1718 return 0;
1719}
1720
f2333421
OD
1721/**
1722 * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
1723 * delete the corresponding Adjacency-SID(s) accordingly.
1724 *
1725 * @param adj IS-IS Adjacency
1726 * @param family Inet Family (IPv4 or IPv6)
1727 *
1728 * @return 0
26f6acaf 1729 */
b1d80d43 1730static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
26f6acaf
RW
1731{
1732 struct sr_adjacency *sra;
1733 struct listnode *node, *nnode;
1734
1735 if (!adj->circuit->area->srdb.enabled)
1736 return 0;
1737
1738 for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
1739 if (sra->nexthop.family == family)
b1d80d43 1740 sr_adj_sid_del(sra);
26f6acaf
RW
1741
1742 return 0;
1743}
1744
f2333421
OD
1745/**
1746 * Activate local Prefix-SID when loopback interface goes up for IS-IS.
1747 *
1748 * @param ifp Loopback Interface
1749 *
1750 * @return 0
1751 */
b1d80d43 1752static int sr_if_new_hook(struct interface *ifp)
26f6acaf
RW
1753{
1754 struct isis_circuit *circuit;
1755 struct isis_area *area;
1756 struct connected *connected;
1757 struct listnode *node;
1758
f2333421 1759 /* Get corresponding circuit */
26f6acaf
RW
1760 circuit = circuit_scan_by_ifp(ifp);
1761 if (!circuit)
1762 return 0;
1763
1764 area = circuit->area;
1765 if (!area)
1766 return 0;
1767
1768 /*
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.
1772 */
1773 FOR_ALL_INTERFACES_ADDRESSES (ifp, connected, node) {
1774 struct sr_prefix_cfg *pcfg;
1775
1776 pcfg = isis_sr_cfg_prefix_find(area, connected->address);
1777 if (!pcfg)
1778 continue;
1779
b1d80d43 1780 if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)
26f6acaf
RW
1781 && !pcfg->node_sid) {
1782 pcfg->node_sid = true;
1783 lsp_regenerate_schedule(area, area->is_type, 0);
1784 }
1785 }
1786
1787 return 0;
1788}
1789
f2333421 1790/* --- Segment Routing Show information functions --------------------------- */
26f6acaf 1791
c0083e53
OD
1792/**
1793 * Show LFIB operation in human readable format.
1794 *
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
1799 *
1800 * @return String containing LFIB operation in human readable format
1801 */
1802static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
1803 mpls_label_t label_out)
1804{
1805 if (size < 24)
1806 return NULL;
1807
1808 if (label_in == MPLS_INVALID_LABEL) {
1809 snprintf(buf, size, "no-op.");
1810 return buf;
1811 }
1812
1813 switch (label_out) {
1814 case MPLS_LABEL_IMPLICIT_NULL:
1815 snprintf(buf, size, "Pop(%u)", label_in);
1816 break;
1817 case MPLS_LABEL_IPV4_EXPLICIT_NULL:
1818 case MPLS_LABEL_IPV6_EXPLICIT_NULL:
1819 snprintf(buf, size, "Swap(%u, null)", label_in);
1820 break;
1821 case MPLS_INVALID_LABEL:
1822 snprintf(buf, size, "no-op.");
1823 break;
1824 default:
1825 snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
1826 break;
1827 }
1828 return buf;
1829}
1830
f2333421
OD
1831/**
1832 * Show Local Prefix-SID.
1833 *
1834 * @param vty VTY output
1835 * @param tt Table format
1836 * @param area IS-IS area
1837 * @param srp Segment Routing Prefix
1838 */
b1d80d43
OD
1839static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
1840 const struct isis_area *area,
1841 const struct sr_prefix *srp)
26f6acaf
RW
1842{
1843 const struct sr_nexthop_info *srnh = &srp->u.local.info;
1844 char buf_prefix[BUFSIZ];
c0083e53
OD
1845 char buf_oper[BUFSIZ];
1846 char buf_iface[BUFSIZ];
26f6acaf
RW
1847 char buf_uptime[BUFSIZ];
1848
26f6acaf 1849 if (srnh->label != MPLS_INVALID_LABEL) {
c0083e53
OD
1850 struct interface *ifp;
1851 ifp = if_lookup_prefix(&srp->prefix, VRF_DEFAULT);
1852 if (ifp)
1853 strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
1854 else
1855 snprintf(buf_iface, sizeof(buf_iface), "-");
26f6acaf
RW
1856 log_uptime(srnh->uptime, buf_uptime, sizeof(buf_uptime));
1857 } else {
c0083e53 1858 snprintf(buf_iface, sizeof(buf_iface), "-");
26f6acaf
RW
1859 snprintf(buf_uptime, sizeof(buf_uptime), "-");
1860 }
c0083e53
OD
1861 sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
1862 MPLS_LABEL_IMPLICIT_NULL);
26f6acaf 1863
c0083e53 1864 ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
26f6acaf 1865 prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
c0083e53 1866 srp->sid.value, buf_oper, buf_iface, buf_uptime);
26f6acaf
RW
1867}
1868
f2333421
OD
1869/**
1870 * Show Remote Prefix-SID.
1871 *
1872 * @param vty VTY output
1873 * @param tt Table format
1874 * @param area IS-IS area
1875 * @param srp Segment Routing Prefix
1876 */
b1d80d43
OD
1877static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
1878 const struct isis_area *area,
1879 const struct sr_prefix *srp)
26f6acaf
RW
1880{
1881 struct isis_nexthop *nexthop;
1882 struct listnode *node;
1883 char buf_prefix[BUFSIZ];
c0083e53 1884 char buf_oper[BUFSIZ];
26f6acaf
RW
1885 char buf_nhop[BUFSIZ];
1886 char buf_iface[BUFSIZ];
26f6acaf
RW
1887 char buf_uptime[BUFSIZ];
1888 bool first = true;
1889
1890 (void)prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix));
26f6acaf
RW
1891
1892 if (!srp->u.remote.rinfo) {
1893 ttable_add_row(tt, "%s|%u|%s|-|-|-", buf_prefix, srp->sid.value,
c0083e53
OD
1894 sr_op2str(buf_oper, sizeof(buf_oper),
1895 srp->input_label,
1896 MPLS_LABEL_IMPLICIT_NULL));
26f6acaf
RW
1897 return;
1898 }
1899
1900 for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
1901 nexthop)) {
1902 struct interface *ifp;
1903
1904 inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
1905 sizeof(buf_nhop));
1906 ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
1907 if (ifp)
1908 strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
1909 else
1910 snprintf(buf_iface, sizeof(buf_iface), "ifindex %u",
1911 nexthop->ifindex);
c0083e53 1912 if (nexthop->sr.label == MPLS_INVALID_LABEL)
26f6acaf 1913 snprintf(buf_uptime, sizeof(buf_uptime), "-");
c0083e53 1914 else
26f6acaf
RW
1915 log_uptime(nexthop->sr.uptime, buf_uptime,
1916 sizeof(buf_uptime));
c0083e53
OD
1917 sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
1918 nexthop->sr.label);
26f6acaf
RW
1919
1920 if (first)
c0083e53
OD
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);
26f6acaf 1924 else
c0083e53
OD
1925 ttable_add_row(tt, "|||%s|%s|%s|%s", buf_oper, buf_nhop,
1926 buf_iface, buf_uptime);
26f6acaf
RW
1927 first = false;
1928 }
1929}
1930
f2333421
OD
1931/**
1932 * Show Prefix-SIDs.
1933 *
1934 * @param vty VTY output
1935 * @param area IS-IS area
1936 * @param level IS-IS level
1937 */
b1d80d43 1938static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
26f6acaf
RW
1939{
1940 struct sr_prefix *srp;
1941 struct ttable *tt;
1942
cab10e86 1943 if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
26f6acaf
RW
1944 return;
1945
1946 vty_out(vty, " IS-IS %s Prefix-SIDs:\n\n", circuit_t2string(level));
1947
1948 /* Prepare table. */
1949 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
c0083e53 1950 ttable_add_row(tt, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
26f6acaf
RW
1951 tt->style.cell.rpad = 2;
1952 tt->style.corner = '+';
1953 ttable_restyle(tt);
1954 ttable_rowseps(tt, 0, BOTTOM, true, '-');
1955
f2333421 1956 /* Process all Prefix-SID from the SRDB */
b1d80d43 1957 frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
26f6acaf
RW
1958 switch (srp->type) {
1959 case ISIS_SR_PREFIX_LOCAL:
b1d80d43 1960 show_prefix_sid_local(vty, tt, area, srp);
26f6acaf
RW
1961 break;
1962 case ISIS_SR_PREFIX_REMOTE:
b1d80d43 1963 show_prefix_sid_remote(vty, tt, area, srp);
26f6acaf
RW
1964 break;
1965 }
1966 }
1967
1968 /* Dump the generated table. */
1969 if (tt->nrows > 1) {
1970 char *table;
1971
1972 table = ttable_dump(tt, "\n");
1973 vty_out(vty, "%s\n", table);
1974 XFREE(MTYPE_TMP, table);
1975 }
1976 ttable_del(tt);
1977}
1978
f2333421 1979/**
c0083e53 1980 * Declaration of new show commands.
f2333421 1981 */
26f6acaf
RW
1982DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
1983 "show isis segment-routing prefix-sids",
1984 SHOW_STR PROTO_HELP
1985 "Segment-Routing\n"
1986 "Segment-Routing Prefix-SIDs\n")
1987{
1988 struct listnode *node;
1989 struct isis_area *area;
1990
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");
1994
1995 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
b1d80d43 1996 show_prefix_sids(vty, area, level);
26f6acaf
RW
1997 }
1998
1999 return CMD_SUCCESS;
2000}
2001
c0083e53
OD
2002/**
2003 * Show Segment Routing Node.
2004 *
2005 * @param vty VTY output
2006 * @param area IS-IS area
2007 * @param level IS-IS level
2008 */
2009static void show_node(struct vty *vty, struct isis_area *area, int level)
2010{
2011 struct sr_node *srn;
2012 struct ttable *tt;
2013
2014 if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
2015 return;
2016
2017 vty_out(vty, " IS-IS %s SR-Node:\n\n", circuit_t2string(level));
2018
2019 /* Prepare table. */
2020 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
d8391312 2021 ttable_add_row(tt, "System ID|SRGB|SRLB|Algorithm|MSD");
c0083e53
OD
2022 tt->style.cell.rpad = 2;
2023 tt->style.corner = '+';
2024 ttable_restyle(tt);
2025 ttable_rowseps(tt, 0, BOTTOM, true, '-');
2026
2027 /* Process all SR-Node from the SRDB */
2028 frr_each (srdb_node, &area->srdb.sr_nodes[level - 1], srn) {
d8391312
OD
2029 ttable_add_row(
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
2034 - 1,
2035 srn->cap.srlb.lower_bound,
2036 srn->cap.srlb.lower_bound + srn->cap.srlb.range_size
2037 - 1,
2038 srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF",
2039 srn->cap.msd);
c0083e53
OD
2040 }
2041
2042 /* Dump the generated table. */
2043 if (tt->nrows > 1) {
2044 char *table;
2045
2046 table = ttable_dump(tt, "\n");
2047 vty_out(vty, "%s\n", table);
2048 XFREE(MTYPE_TMP, table);
2049 }
2050 ttable_del(tt);
2051}
2052
2053DEFUN(show_sr_node, show_sr_node_cmd,
2054 "show isis segment-routing node",
2055 SHOW_STR PROTO_HELP
2056 "Segment-Routing\n"
2057 "Segment-Routing node\n")
2058{
2059 struct listnode *node;
2060 struct isis_area *area;
2061
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");
2065
2066 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
2067 show_node(vty, area, level);
2068 }
2069
2070 return CMD_SUCCESS;
2071}
2072
2073
f2333421 2074/* --- IS-IS Segment Routing Management function ---------------------------- */
26f6acaf 2075
58fbcdf2
OD
2076/**
2077 * Thread function to re-attempt connection to the Label Manager and thus be
2078 * able to start Segment Routing.
2079 *
2080 * @param start Thread structure that contains area as argument
2081 *
2082 * @return 1 on success
2083 */
2084static int sr_start_label_manager(struct thread *start)
2085{
2086 struct isis_area *area;
2087
2088 area = THREAD_ARG(start);
2089
2090 /* re-attempt to start SR & Label Manager connection */
2091 isis_sr_start(area);
2092
2093 return 1;
2094}
2095
f2333421
OD
2096/**
2097 * Enable SR on the given IS-IS area.
2098 *
2099 * @param area IS-IS area
2100 *
2101 * @return 0 on success, -1 otherwise
2102 */
26f6acaf
RW
2103int isis_sr_start(struct isis_area *area)
2104{
2105 struct isis_sr_db *srdb = &area->srdb;
2106 struct isis_circuit *circuit;
2107 struct listnode *node;
2108
58fbcdf2
OD
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);
2115 return -1;
2116 }
2117
2118 /* Label Manager is ready, initialize the SRLB */
2119 if (sr_local_block_init(area) < 0)
d8391312
OD
2120 return -1;
2121
26f6acaf 2122 /*
58fbcdf2
OD
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.
26f6acaf 2126 */
58fbcdf2
OD
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)
2132 < 0) {
2133 srdb->srgb_active = false;
2134 return -1;
2135 } else
2136 srdb->srgb_active = true;
2137 }
26f6acaf 2138
b407c77a
OD
2139 sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
2140 area->area_tag);
26f6acaf 2141
f2333421 2142 /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
26f6acaf
RW
2143 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
2144 struct isis_adjacency *adj;
2145 struct listnode *anode;
2146
2147 switch (circuit->circ_type) {
2148 case CIRCUIT_T_BROADCAST:
2149 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
2150 level++) {
2151 for (ALL_LIST_ELEMENTS_RO(
2152 circuit->u.bc.adjdb[level - 1],
2153 anode, adj)) {
2154 if (adj->ipv4_address_count > 0)
b1d80d43 2155 sr_adj_sid_add(adj, AF_INET);
26f6acaf 2156 if (adj->ipv6_address_count > 0)
b1d80d43 2157 sr_adj_sid_add(adj, AF_INET6);
26f6acaf
RW
2158 }
2159 }
2160 break;
2161 case CIRCUIT_T_P2P:
2162 adj = circuit->u.p2p.neighbor;
2163 if (adj && adj->ipv4_address_count > 0)
b1d80d43 2164 sr_adj_sid_add(adj, AF_INET);
26f6acaf 2165 if (adj && adj->ipv6_address_count > 0)
b1d80d43 2166 sr_adj_sid_add(adj, AF_INET6);
26f6acaf
RW
2167 break;
2168 default:
2169 break;
2170 }
2171 }
2172
58fbcdf2
OD
2173 area->srdb.enabled = true;
2174
f2333421 2175 /* Regenerate LSPs to advertise Segment Routing capabilities. */
26f6acaf
RW
2176 lsp_regenerate_schedule(area, area->is_type, 0);
2177
2178 return 0;
2179}
2180
f2333421
OD
2181/**
2182 * Disable SR on the given IS-IS area.
2183 *
2184 * @param area IS-IS area
2185 */
26f6acaf
RW
2186void isis_sr_stop(struct isis_area *area)
2187{
2188 struct isis_sr_db *srdb = &area->srdb;
2189 struct sr_adjacency *sra;
2190 struct listnode *node, *nnode;
2191
b407c77a
OD
2192 sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
2193 area->area_tag);
26f6acaf 2194
58fbcdf2
OD
2195 /* Disable any re-attempt to connect to Label Manager */
2196 THREAD_TIMER_OFF(srdb->t_start_lm);
2197
f2333421 2198 /* Uninstall all local Adjacency-SIDs. */
26f6acaf 2199 for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
b1d80d43 2200 sr_adj_sid_del(sra);
26f6acaf 2201
f2333421 2202 /* Uninstall all Prefix-SIDs from all SR Node. */
26f6acaf 2203 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
cab10e86 2204 while (srdb_node_count(&srdb->sr_nodes[level - 1]) > 0) {
26f6acaf
RW
2205 struct sr_node *srn;
2206
cab10e86 2207 srn = srdb_node_first(&srdb->sr_nodes[level - 1]);
b1d80d43 2208 sr_node_del(area, level, srn);
26f6acaf
RW
2209 }
2210 }
2211
58fbcdf2
OD
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;
2217 }
26f6acaf 2218
d8391312
OD
2219 /* Delete SRLB */
2220 sr_local_block_delete(area);
2221
58fbcdf2
OD
2222 area->srdb.enabled = false;
2223
f2333421 2224 /* Regenerate LSPs to advertise that the Node is no more SR enable. */
26f6acaf
RW
2225 lsp_regenerate_schedule(area, area->is_type, 0);
2226}
2227
f2333421
OD
2228/**
2229 * IS-IS Segment Routing initialization for given area.
2230 *
2231 * @param area IS-IS area
2232 */
26f6acaf
RW
2233void isis_sr_area_init(struct isis_area *area)
2234{
2235 struct isis_sr_db *srdb = &area->srdb;
2236
b407c77a
OD
2237 sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
2238 area->area_tag);
2239
f2333421 2240 /* Initialize Segment Routing Data Base */
26f6acaf 2241 memset(srdb, 0, sizeof(*srdb));
26f6acaf
RW
2242 srdb->adj_sids = list_new();
2243
2244 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
cab10e86
OD
2245 srdb_node_init(&srdb->sr_nodes[level - 1]);
2246 srdb_area_prefix_init(&srdb->prefix_sids[level - 1]);
26f6acaf
RW
2247 }
2248
2249 /* Pull defaults from the YANG module. */
2250#ifndef FABRICD
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);
d8391312
OD
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);
26f6acaf
RW
2260#else
2261 srdb->config.enabled = false;
2262 srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND;
2263 srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND;
d8391312
OD
2264 srdb->config.srlb_lower_bound = SRLB_LOWER_BOUND;
2265 srdb->config.srlb_upper_bound = SRLB_UPPER_BOUND;
26f6acaf
RW
2266#endif
2267 srdb->config.msd = 0;
cab10e86 2268 srdb_prefix_cfg_init(&srdb->config.prefix_sids);
26f6acaf
RW
2269}
2270
f2333421
OD
2271/**
2272 * Terminate IS-IS Segment Routing for the given area.
2273 *
2274 * @param area IS-IS area
2275 */
26f6acaf
RW
2276void isis_sr_area_term(struct isis_area *area)
2277{
2278 struct isis_sr_db *srdb = &area->srdb;
2279
2280 /* Stop Segment Routing */
2281 if (area->srdb.enabled)
2282 isis_sr_stop(area);
2283
2284 /* Clear Prefix-SID configuration. */
cab10e86 2285 while (srdb_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
26f6acaf
RW
2286 struct sr_prefix_cfg *pcfg;
2287
cab10e86 2288 pcfg = srdb_prefix_cfg_first(&srdb->config.prefix_sids);
26f6acaf
RW
2289 isis_sr_cfg_prefix_del(pcfg);
2290 }
2291}
2292
f2333421
OD
2293/**
2294 * IS-IS Segment Routing global initialization.
2295 */
26f6acaf
RW
2296void isis_sr_init(void)
2297{
2298 install_element(VIEW_NODE, &show_sr_prefix_sids_cmd);
c0083e53 2299 install_element(VIEW_NODE, &show_sr_node_cmd);
26f6acaf
RW
2300
2301 /* Register hooks. */
b1d80d43
OD
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);
26f6acaf
RW
2307}
2308
f2333421
OD
2309/**
2310 * IS-IS Segment Routing global terminate.
2311 */
26f6acaf
RW
2312void isis_sr_term(void)
2313{
2314 /* Unregister hooks. */
b1d80d43
OD
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);
26f6acaf 2320}