1 /*
2  * This is an implementation of Segment Routing for IS-IS as per RFC 8667
3  *
4  * Copyright (C) 2019 Orange http://www.orange.com
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 
50 /* Local variables and functions */
51 DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
52 
53 static void sr_prefix_uninstall(struct sr_prefix *srp);
54 static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
55 static void sr_local_block_delete(struct isis_area *area);
56 static int sr_local_block_init(struct isis_area *area);
57 static void sr_adj_sid_update(struct sr_adjacency *sra,
58 			      struct sr_local_block *srlb);
59 
60 /* --- RB-Tree Management functions ----------------------------------------- */
61 
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  */
sr_prefix_sid_compare(const struct sr_prefix * a,const struct sr_prefix * b)70 static 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 }
DECLARE_RBTREE_UNIQ(srdb_node_prefix,struct sr_prefix,node_entry,sr_prefix_sid_compare)75 DECLARE_RBTREE_UNIQ(srdb_node_prefix, struct sr_prefix, node_entry,
76 		    sr_prefix_sid_compare)
77 DECLARE_RBTREE_UNIQ(srdb_area_prefix, struct sr_prefix, area_entry,
78 		    sr_prefix_sid_compare)
79 
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  */
88 static 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 }
DECLARE_RBTREE_UNIQ(srdb_prefix_cfg,struct sr_prefix_cfg,entry,sr_prefix_sid_cfg_compare)93 DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
94 		    sr_prefix_sid_cfg_compare)
95 
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  */
104 static 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 }
DECLARE_RBTREE_UNIQ(srdb_node,struct sr_node,entry,sr_node_compare)109 DECLARE_RBTREE_UNIQ(srdb_node, struct sr_node, entry, sr_node_compare)
110 
111 /* --- Functions used for Yang model and CLI to configure Segment Routing --- */
112 
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  */
121 static bool sr_prefix_is_node_sid(const struct interface *ifp,
122 				  const struct prefix *prefix)
123 {
124 	return (if_is_loopback(ifp) && is_host_route(prefix));
125 }
126 
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  */
isis_sr_cfg_srgb_update(struct isis_area * area,uint32_t lower_bound,uint32_t upper_bound)137 int 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 
142 	sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
143 		 area->area_tag, lower_bound, upper_bound);
144 
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,
156 					       srdb->config.srgb_upper_bound);
157 	        srdb->srgb_active = false;
158 	}
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 
166 		/* then request new SRGB if SR is enabled. */
167 		if (isis_zebra_request_label_range(
168 			    srdb->config.srgb_lower_bound,
169 			    srdb->config.srgb_upper_bound
170 				    - srdb->config.srgb_lower_bound + 1) < 0) {
171 			srdb->srgb_active = false;
172 			return -1;
173 		} else
174 			srdb->srgb_active = true;
175 
176 
177 		sr_debug("  |- Got new SRGB [%u/%u]",
178 			 srdb->config.srgb_lower_bound,
179 			 srdb->config.srgb_upper_bound);
180 
181 		/* Reinstall local Prefix-SIDs to update their input labels. */
182 		for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
183 			frr_each (srdb_area_prefix,
184 				  &area->srdb.prefix_sids[level - 1], srp) {
185 				sr_prefix_reinstall(srp, false);
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. */
192 		isis_sr_start(area);
193 	}
194 
195 	return 0;
196 }
197 
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  */
isis_sr_cfg_srlb_update(struct isis_area * area,uint32_t lower_bound,uint32_t upper_bound)209 int 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;
214 	struct sr_adjacency *sra;
215 
216 	sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
217 		 area->area_tag, lower_bound, upper_bound);
218 
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 */
228 	sr_local_block_delete(area);
229 
230 	srdb->config.srlb_lower_bound = lower_bound;
231 	srdb->config.srlb_upper_bound = upper_bound;
232 
233 	if (srdb->enabled) {
234 		/* Initialize new SRLB */
235 		if (sr_local_block_init(area) != 0)
236 			return -1;
237 
238 		/* Reinstall local Adjacency-SIDs with new labels. */
239 		for (ALL_LIST_ELEMENTS_RO(area->srdb.adj_sids, node, sra))
240 			sr_adj_sid_update(sra, &srdb->srlb);
241 
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 	}
248 
249 	return 0;
250 }
251 
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  */
isis_sr_cfg_prefix_add(struct isis_area * area,const struct prefix * prefix)260 struct 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 
266 	sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
267 
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);
280 	if (ifp && sr_prefix_is_node_sid(ifp, prefix))
281 		pcfg->node_sid = true;
282 
283 	/* Save prefix-sid configuration. */
284 	srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
285 
286 	return pcfg;
287 }
288 
289 /**
290  * Removal of locally configured Prefix-SID.
291  *
292  * @param pcfg	Configured Prefix-SID
293  */
isis_sr_cfg_prefix_del(struct sr_prefix_cfg * pcfg)294 void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
295 {
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);
302 
303 	srdb_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
304 	XFREE(MTYPE_ISIS_SR_INFO, pcfg);
305 }
306 
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  */
isis_sr_cfg_prefix_find(struct isis_area * area,union prefixconstptr prefix)315 struct 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);
321 	return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
322 }
323 
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  */
isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg * pcfg,bool external,struct isis_prefix_sid * psid)331 void 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 
366 /* --- Segment Routing Prefix Management functions -------------------------- */
367 
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  */
sr_prefix_add(struct isis_area * area,struct sr_node * srn,union prefixconstptr prefix,bool local,const struct isis_prefix_sid * psid)379 static 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)
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;
389 	srp->input_label = MPLS_INVALID_LABEL;
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;
398 	srdb_node_prefix_add(&srn->prefix_sids, srp);
399 	/* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
400 	srdb_area_prefix_add(&area->srdb.prefix_sids[srn->level - 1], srp);
401 
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 
406 	return srp;
407 }
408 
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  */
sr_prefix_del(struct isis_area * area,struct sr_node * srn,struct sr_prefix * srp)417 static void sr_prefix_del(struct isis_area *area, struct sr_node *srn,
418 			  struct sr_prefix *srp)
419 {
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 
424 	sr_prefix_uninstall(srp);
425 	srdb_node_prefix_del(&srn->prefix_sids, srp);
426 	srdb_area_prefix_del(&area->srdb.prefix_sids[srn->level - 1], srp);
427 	XFREE(MTYPE_ISIS_SR_INFO, srp);
428 }
429 
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  */
sr_prefix_find_by_area(struct isis_area * area,int level,union prefixconstptr prefix)439 static struct sr_prefix *sr_prefix_find_by_area(struct isis_area *area,
440 						int level,
441 						union prefixconstptr prefix)
442 {
443 	struct sr_prefix srp = {};
444 
445 	prefix_copy(&srp.prefix, prefix.p);
446 	return srdb_area_prefix_find(&area->srdb.prefix_sids[level - 1], &srp);
447 }
448 
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  */
sr_prefix_find_by_node(struct sr_node * srn,union prefixconstptr prefix)457 static struct sr_prefix *sr_prefix_find_by_node(struct sr_node *srn,
458 						union prefixconstptr prefix)
459 {
460 	struct sr_prefix srp = {};
461 
462 	prefix_copy(&srp.prefix, prefix.p);
463 	return srdb_node_prefix_find(&srn->prefix_sids, &srp);
464 }
465 
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  */
sr_node_add(struct isis_area * area,int level,const uint8_t * sysid)478 static struct sr_node *sr_node_add(struct isis_area *area, int level,
479 				   const uint8_t *sysid)
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);
486 	srn->area = area;
487 	srdb_node_prefix_init(&srn->prefix_sids);
488 	srdb_node_add(&area->srdb.sr_nodes[level - 1], srn);
489 
490 	sr_debug("  |- Added new SR Node %s", sysid_print(srn->sysid));
491 
492 	return srn;
493 }
494 
sr_node_del(struct isis_area * area,int level,struct sr_node * srn)495 static void sr_node_del(struct isis_area *area, int level, struct sr_node *srn)
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  */
504 {
505 
506 	sr_debug("  |- Delete SR Node %s", sysid_print(srn->sysid));
507 
508 	/* Remove and uninstall Prefix-SIDs. */
509 	while (srdb_node_prefix_count(&srn->prefix_sids) > 0) {
510 		struct sr_prefix *srp;
511 
512 		srp = srdb_node_prefix_first(&srn->prefix_sids);
513 		sr_prefix_del(area, srn, srp);
514 	}
515 
516 	srdb_node_del(&area->srdb.sr_nodes[level - 1], srn);
517 	XFREE(MTYPE_ISIS_SR_INFO, srn);
518 }
519 
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  */
sr_node_find(struct isis_area * area,int level,const uint8_t * sysid)529 static struct sr_node *sr_node_find(struct isis_area *area, int level,
530 				    const uint8_t *sysid)
531 {
532 	struct sr_node srn = {};
533 
534 	memcpy(srn.sysid, sysid, ISIS_SYS_ID_LEN);
535 	return srdb_node_find(&area->srdb.sr_nodes[level - 1], &srn);
536 }
537 
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  */
sr_node_srgb_update(struct isis_area * area,int level,uint8_t * sysid)546 static void sr_node_srgb_update(struct isis_area *area, int level,
547 				uint8_t *sysid)
548 {
549 	struct sr_prefix *srp;
550 
551 	sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
552 		 area->area_tag);
553 
554 	frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
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 			/*
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).
574 			 */
575 			sr_prefix_reinstall(srp, true);
576 			break;
577 		}
578 	}
579 }
580 
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  */
isis_sr_nexthop_update(struct sr_nexthop_info * srnh,mpls_label_t label)589 void 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 
596 /**
597  * Reset Segment Routing Nexthop.
598  *
599  * @param srnh	Segment Routing Nexthop
600  */
isis_sr_nexthop_reset(struct sr_nexthop_info * srnh)601 void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh)
602 {
603 	srnh->label = MPLS_INVALID_LABEL;
604 	srnh->uptime = 0;
605 }
606 
607 /* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
608 
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  */
sr_prefix_lookup_route(struct isis_area * area,enum spf_tree_id tree_id,struct sr_prefix * srp)618 static struct isis_route_info *sr_prefix_lookup_route(struct isis_area *area,
619 						      enum spf_tree_id tree_id,
620 						      struct sr_prefix *srp)
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 
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  */
sr_prefix_in_label(const struct sr_prefix * srp)643 static mpls_label_t sr_prefix_in_label(const struct sr_prefix *srp)
644 {
645 	const struct sr_node *srn = srp->srn;
646 	struct isis_area *area = srn->area;
647 
648 	/* Return SID value as MPLS label if it is an Absolute SID */
649 	if (CHECK_FLAG(srp->sid.flags,
650 		       ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
651 		return srp->sid.value;
652 
653 	/* Check that SID index falls inside the SRGB */
654 	if (srp->sid.value >= (area->srdb.config.srgb_upper_bound
655 			       - area->srdb.config.srgb_lower_bound + 1)) {
656 		flog_warn(EC_ISIS_SID_OVERFLOW,
657 			  "%s: SID index %u falls outside local SRGB range",
658 			  __func__, srp->sid.value);
659 		return MPLS_INVALID_LABEL;
660 	}
661 
662 	/* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
663 	return (area->srdb.config.srgb_lower_bound + srp->sid.value);
664 }
665 
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  */
sr_prefix_out_label(const struct sr_prefix * srp,const struct sr_node * srn_nexthop,const uint8_t * sysid)675 static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
676 					const struct sr_node *srn_nexthop,
677 					const uint8_t *sysid)
678 {
679 	const struct sr_node *srn = srp->srn;
680 
681 	/* Check if the nexthop SR Node is the last hop? */
682 	if (memcmp(sysid, srn->sysid, ISIS_SYS_ID_LEN) == 0) {
683 		/* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
684 		if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP))
685 			return MPLS_LABEL_IMPLICIT_NULL;
686 
687 		/* SR-Node requests Implicit NULL Label */
688 		if (CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL)) {
689 			if (srp->prefix.family == AF_INET)
690 				return MPLS_LABEL_IPV4_EXPLICIT_NULL;
691 			else
692 				return MPLS_LABEL_IPV6_EXPLICIT_NULL;
693 		}
694 		/* Fallthrough */
695 	}
696 
697 	/* Return SID value as MPLS label if it is an Absolute SID */
698 	if (CHECK_FLAG(srp->sid.flags,
699 		       ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
700 		/*
701 		 * V/L SIDs have local significance, so only adjacent routers
702 		 * can use them (RFC8667 section #2.1.1.1)
703 		 */
704 		if (srp->srn != srn_nexthop)
705 			return MPLS_INVALID_LABEL;
706 		return srp->sid.value;
707 	}
708 
709 	/* Check that SID index falls inside the SRGB */
710 	if (srp->sid.value >= srn_nexthop->cap.srgb.range_size) {
711 		flog_warn(EC_ISIS_SID_OVERFLOW,
712 			  "%s: SID index %u falls outside remote SRGB range",
713 			  __func__, srp->sid.value);
714 		return MPLS_INVALID_LABEL;
715 	}
716 
717 	/* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
718 	return (srn_nexthop->cap.srgb.lower_bound + srp->sid.value);
719 }
720 
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  */
sr_prefix_install_local(struct sr_prefix * srp)729 static int sr_prefix_install_local(struct sr_prefix *srp)
730 {
731 	mpls_label_t input_label;
732 	const struct sr_node *srn = srp->srn;
733 
734 	/*
735 	 * No need to install Label for local Prefix-SID unless the
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 
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));
745 
746 	/* Compute input label and check that is valid. */
747 	input_label = sr_prefix_in_label(srp);
748 	if (input_label == MPLS_INVALID_LABEL)
749 		return -1;
750 
751 	/* Update internal state. */
752 	srp->input_label = input_label;
753 	isis_sr_nexthop_update(&srp->u.local.info, MPLS_LABEL_IMPLICIT_NULL);
754 
755 	/* Install Prefix-SID in the forwarding plane. */
756 	isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
757 
758 	return 0;
759 }
760 
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  */
sr_prefix_install_remote(struct sr_prefix * srp)769 static int sr_prefix_install_remote(struct sr_prefix *srp)
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;
776 	mpls_label_t input_label;
777 	size_t nexthop_num = 0;
778 
779 	/* Lookup to associated IS-IS route. */
780 	tree_id = (srp->prefix.family == AF_INET) ? SPFTREE_IPV4 : SPFTREE_IPV6;
781 	srp->u.remote.rinfo = sr_prefix_lookup_route(area, tree_id, srp);
782 	if (!srp->u.remote.rinfo)
783 		/* SPF hasn't converged for this route yet. */
784 		return -1;
785 
786 	/* Compute input label and check that is valid. */
787 	input_label = sr_prefix_in_label(srp);
788 	if (input_label == MPLS_INVALID_LABEL)
789 		return -1;
790 
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 
795 	/* Process all SPF nexthops */
796 	for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
797 				  nexthop)) {
798 		struct sr_node *srn_nexthop;
799 		mpls_label_t output_label;
800 
801 		/* Check if the nexthop advertised a SRGB. */
802 		srn_nexthop = sr_node_find(area, srn->level, nexthop->sysid);
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 
816 		/* Compute output label and check if it is valid */
817 		output_label =
818 			sr_prefix_out_label(srp, srn_nexthop, nexthop->sysid);
819 		if (output_label == MPLS_INVALID_LABEL)
820 			goto next;
821 
822 		if (IS_DEBUG_SR) {
823 			static char buf[INET6_ADDRSTRLEN];
824 
825 			inet_ntop(nexthop->family, &nexthop->ip, buf,
826 				  sizeof(buf));
827 			zlog_debug("    |- nexthop %s label %u", buf,
828 				   output_label);
829 		}
830 
831 		isis_sr_nexthop_update(&nexthop->sr, output_label);
832 		nexthop_num++;
833 		continue;
834 	next:
835 		isis_sr_nexthop_reset(&nexthop->sr);
836 	}
837 
838 	/* Check that we found at least one valid nexthop */
839 	if (nexthop_num == 0) {
840 		sr_debug("    |- no valid nexthops");
841 		return -1;
842 	}
843 
844 	/* Update internal state. */
845 	srp->input_label = input_label;
846 
847 	/* Install Prefix-SID in the forwarding plane. */
848 	isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
849 
850 	return 0;
851 }
852 
853 /**
854  * Process local or remote Prefix-SID and install it if possible.
855  *
856  * @param srp	Segment Routing Prefix
857  */
sr_prefix_install(struct sr_prefix * srp)858 static void sr_prefix_install(struct sr_prefix *srp)
859 {
860 	const struct sr_node *srn = srp->srn;
861 	struct isis_area *area = srn->area;
862 	int ret;
863 
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 
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:
874 			srp_l2 = sr_prefix_find_by_area(area, ISIS_LEVEL2,
875 							&srp->prefix);
876 			if (srp_l2)
877 				sr_prefix_uninstall(srp_l2);
878 			break;
879 		case ISIS_LEVEL2:
880 			srp_l1 = sr_prefix_find_by_area(area, ISIS_LEVEL1,
881 							&srp->prefix);
882 			if (srp_l1)
883 				return;
884 			break;
885 		default:
886 			break;
887 		}
888 	}
889 
890 	/* Install corresponding LFIB entry */
891 	if (srp->type == ISIS_SR_PREFIX_LOCAL)
892 		ret = sr_prefix_install_local(srp);
893 	else
894 		ret = sr_prefix_install_remote(srp);
895 	if (ret != 0)
896 		sr_prefix_uninstall(srp);
897 }
898 
899 /**
900  * Uninstall local or remote Prefix-SID.
901  *
902  * @param srp	Segment Routing Prefix
903  */
sr_prefix_uninstall(struct sr_prefix * srp)904 static void sr_prefix_uninstall(struct sr_prefix *srp)
905 {
906 	struct listnode *node;
907 	struct isis_nexthop *nexthop;
908 
909 	/* Check that Input Label is valid */
910 	if (srp->input_label == MPLS_INVALID_LABEL)
911 		return;
912 
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);
916 
917 	/* Uninstall Prefix-SID from the forwarding plane. */
918 	isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE, srp);
919 
920 	/* Reset internal state. */
921 	srp->input_label = MPLS_INVALID_LABEL;
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 
936 /**
937  * Reinstall local or remote Prefix-SID.
938  *
939  * @param srp	Segment Routing Prefix
940  */
sr_prefix_reinstall(struct sr_prefix * srp,bool make_before_break)941 static inline void sr_prefix_reinstall(struct sr_prefix *srp,
942 				       bool make_before_break)
943 {
944 	/*
945 	 * Make Before Break can be used only when we know for sure that
946 	 * the Prefix-SID input label hasn't changed. Otherwise we need to
947 	 * uninstall the Prefix-SID first using the old input label before
948 	 * reinstalling it.
949 	 */
950 	if (!make_before_break)
951 		sr_prefix_uninstall(srp);
952 
953 	/* New input label is computed in sr_prefix_install() function */
954 	sr_prefix_install(srp);
955 }
956 
957 /* --- IS-IS LSP Parse functions -------------------------------------------- */
958 
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  */
router_cap_cmp(const struct isis_router_cap * r1,const struct isis_router_cap * r2)967 static 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 
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  */
989 static struct sr_node *
parse_router_cap_tlv(struct isis_area * area,int level,const uint8_t * sysid,const struct isis_router_cap * router_cap)990 parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid,
991 		     const struct isis_router_cap *router_cap)
992 {
993 	struct sr_node *srn;
994 
995 	if (!router_cap || router_cap->srgb.range_size == 0)
996 		return NULL;
997 
998 	sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area->area_tag);
999 
1000 	srn = sr_node_find(area, level, sysid);
1001 	if (srn) {
1002 		if (router_cap_cmp(&srn->cap, router_cap) != 0) {
1003 			srn->state = SRDB_STATE_MODIFIED;
1004 		} else
1005 			srn->state = SRDB_STATE_UNCHANGED;
1006 		sr_debug("  |- Found %s SR Node %s",
1007 			 srn->state == SRDB_STATE_MODIFIED ? "Modified"
1008 							   : "Unchanged",
1009 			 sysid_print(srn->sysid));
1010 	} else {
1011 		srn = sr_node_add(area, level, sysid);
1012 		srn->state = SRDB_STATE_NEW;
1013 	}
1014 
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 
1021 	return srn;
1022 }
1023 
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  */
parse_prefix_sid_subtlvs(struct sr_node * srn,union prefixconstptr prefix,bool local,struct isis_item_list * prefix_sids)1032 static void parse_prefix_sid_subtlvs(struct sr_node *srn,
1033 				     union prefixconstptr prefix, bool local,
1034 				     struct isis_item_list *prefix_sids)
1035 {
1036 	struct isis_area *area = srn->area;
1037 	struct isis_item *i;
1038 
1039 	sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area->area_tag);
1040 
1041 	/* Parse list of Prefix SID subTLVs */
1042 	for (i = prefix_sids->head; i; i = i->next) {
1043 		struct isis_prefix_sid *psid = (struct isis_prefix_sid *)i;
1044 		struct sr_prefix *srp;
1045 
1046 		/* Only SPF algorithm is supported right now */
1047 		if (psid->algorithm != SR_ALGORITHM_SPF)
1048 			continue;
1049 
1050 		/* Compute corresponding Segment Routing Prefix */
1051 		srp = sr_prefix_find_by_node(srn, prefix);
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;
1057 				srp->state = SRDB_STATE_MODIFIED;
1058 			} else if (srp->state == SRDB_STATE_VALIDATED)
1059 				srp->state = SRDB_STATE_UNCHANGED;
1060 			sr_debug("  |- Found %s Prefix-SID %pFX",
1061 				 srp->state == SRDB_STATE_MODIFIED
1062 					 ? "Modified"
1063 					 : "Unchanged",
1064 				 &srp->prefix);
1065 
1066 		} else {
1067 			srp = sr_prefix_add(area, srn, prefix, local, psid);
1068 			srp->state = SRDB_STATE_NEW;
1069 		}
1070 		/*
1071 		 * Stop the Prefix-SID iteration since we only support the SPF
1072 		 * algorithm for now.
1073 		 */
1074 		break;
1075 	}
1076 }
1077 
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  */
parse_lsp(struct isis_area * area,int level,struct sr_node ** srn,struct isis_lsp * lsp)1086 static void parse_lsp(struct isis_area *area, int level, struct sr_node **srn,
1087 		      struct isis_lsp *lsp)
1088 {
1089 	struct isis_item_list *items;
1090 	struct isis_item *i;
1091 	bool local = lsp->own_lsp;
1092 
1093 	/* Check LSP sequence number */
1094 	if (lsp->hdr.seqno == 0) {
1095 		zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
1096 		return;
1097 	}
1098 
1099 	sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area->area_tag,
1100 		 sysid_print(lsp->hdr.lsp_id));
1101 
1102 	/* Parse the Router Capability TLV. */
1103 	if (*srn == NULL) {
1104 		*srn = parse_router_cap_tlv(area, level, lsp->hdr.lsp_id,
1105 					    lsp->tlvs->router_cap);
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 
1119 		parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
1120 					 &ir->subtlvs->prefix_sids);
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 
1133 		parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
1134 					 &ir->subtlvs->prefix_sids);
1135 	}
1136 }
1137 
1138 /**
1139  * Parse all SR-related information from the entire LSPDB.
1140  *
1141  * @param area	IS-IS area
1142  */
parse_lspdb(struct isis_area * area)1143 static void parse_lspdb(struct isis_area *area)
1144 {
1145 	struct isis_lsp *lsp;
1146 
1147 	sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area->area_tag);
1148 
1149 	/* Process all LSP from Level 1 & 2 */
1150 	for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
1151 		frr_each (lspdb, &area->lspdb[level - 1], lsp) {
1152 			struct isis_lsp *frag;
1153 			struct listnode *node;
1154 			struct sr_node *srn = NULL;
1155 
1156 			/* Skip Pseudo ID LSP and LSP without TLVs */
1157 			if (LSP_PSEUDO_ID(lsp->hdr.lsp_id))
1158 				continue;
1159 			if (!lsp->tlvs)
1160 				continue;
1161 
1162 			/* Parse LSP, then fragment */
1163 			parse_lsp(area, level, &srn, lsp);
1164 			for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
1165 				parse_lsp(area, level, &srn, frag);
1166 		}
1167 	}
1168 }
1169 
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  */
process_prefix_changes(struct sr_node * srn,struct sr_prefix * srp)1176 static void process_prefix_changes(struct sr_node *srn, struct sr_prefix *srp)
1177 {
1178 	struct isis_area *area = srn->area;
1179 
1180 	/* Install/reinstall/uninstall Prefix-SID if necessary. */
1181 	switch (srp->state) {
1182 	case SRDB_STATE_NEW:
1183 		sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
1184 			 area->area_tag, &srp->prefix, sysid_print(srn->sysid));
1185 		sr_prefix_install(srp);
1186 		break;
1187 	case SRDB_STATE_MODIFIED:
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));
1191 		sr_prefix_reinstall(srp, false);
1192 		break;
1193 	case SRDB_STATE_UNCHANGED:
1194 		break;
1195 	default:
1196 		sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
1197 			 area->area_tag, &srp->prefix, sysid_print(srn->sysid));
1198 		sr_prefix_del(area, srn, srp);
1199 		return;
1200 	}
1201 
1202 	/* Validate SRDB State for next LSPDB parsing */
1203 	srp->state = SRDB_STATE_VALIDATED;
1204 }
1205 
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  */
process_node_changes(struct isis_area * area,int level,struct sr_node * srn)1213 static void process_node_changes(struct isis_area *area, int level,
1214 				 struct sr_node *srn)
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 
1222 	/*
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.
1225 	 */
1226 	adjacent = !!isis_adj_find(area, level, sysid);
1227 	switch (srn->state) {
1228 	case SRDB_STATE_NEW:
1229 	case SRDB_STATE_MODIFIED:
1230 		sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
1231 			 area->area_tag, sysid_print(srn->sysid));
1232 		if (adjacent)
1233 			sr_node_srgb_update(area, level, sysid);
1234 		break;
1235 	case SRDB_STATE_UNCHANGED:
1236 		break;
1237 	default:
1238 		/* SR capabilities have been removed. Delete SR-Node */
1239 		sr_debug("ISIS-Sr (%s): Remove SR node %s", area->area_tag,
1240 			 sysid_print(srn->sysid));
1241 
1242 		sr_node_del(area, level, srn);
1243 		/* and Update remaining Prefix-SID from all remaining SR Node */
1244 		if (adjacent)
1245 			sr_node_srgb_update(area, level, sysid);
1246 		return;
1247 	}
1248 
1249 	/* Validate SRDB State for next LSPDB parsing */
1250 	srn->state = SRDB_STATE_VALIDATED;
1251 
1252 	/* Finally, process all Prefix-SID of this SR Node */
1253 	frr_each_safe (srdb_node_prefix, &srn->prefix_sids, srp)
1254 		process_prefix_changes(srn, srp);
1255 }
1256 
1257 /**
1258  * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
1259  *
1260  * @param area	IS-IS area
1261  */
isis_area_verify_sr(struct isis_area * area)1262 void 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. */
1270 	parse_lspdb(area);
1271 
1272 	/* Process possible SR-related changes in the LDPSB. */
1273 	for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
1274 		frr_each_safe (srdb_node, &area->srdb.sr_nodes[level - 1], srn)
1275 			process_node_changes(area, level, srn);
1276 	}
1277 }
1278 
1279 /**
1280  * Once a route is updated in the SPT, reinstall or uninstall its corresponding
1281  * Prefix-SID (if any).
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
1288  */
sr_route_update(struct isis_area * area,struct prefix * prefix,struct isis_route_info * route_info)1289 static int sr_route_update(struct isis_area *area, struct prefix *prefix,
1290 			   struct isis_route_info *route_info)
1291 {
1292 	struct sr_prefix *srp;
1293 
1294 	if (!area->srdb.enabled)
1295 		return 0;
1296 
1297 	sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area->area_tag,
1298 		 prefix);
1299 
1300 	/* Lookup to Segment Routing Prefix for this prefix */
1301 	switch (area->is_type) {
1302 	case IS_LEVEL_1:
1303 		srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
1304 		break;
1305 	case IS_LEVEL_2:
1306 		srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
1307 		break;
1308 	case IS_LEVEL_1_AND_2:
1309 		srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
1310 		if (!srp)
1311 			srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
1312 		break;
1313 	default:
1314 		flog_err(EC_LIB_DEVELOPMENT, "%s: unknown area level",
1315 			 __func__);
1316 		exit(1);
1317 	}
1318 
1319 	/* Skip NULL or local Segment Routing Prefix */
1320 	if (!srp || srp->type == ISIS_SR_PREFIX_LOCAL)
1321 		return 0;
1322 
1323 	/* Install or unintall Prefix-SID if route is Active or not */
1324 	if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
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 		 */
1330 		sr_prefix_reinstall(srp, true);
1331 		srp->u.remote.rinfo = route_info;
1332 	} else {
1333 		sr_prefix_uninstall(srp);
1334 		srp->u.remote.rinfo = NULL;
1335 	}
1336 
1337 	return 0;
1338 }
1339 
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  */
sr_local_block_init(struct isis_area * area)1348 static int sr_local_block_init(struct isis_area *area)
1349 {
1350 	struct isis_sr_db *srdb = &area->srdb;
1351 	struct sr_local_block *srlb = &srdb->srlb;
1352 
1353 	/* Check if SRLB is not already configured */
1354 	if (srlb->active)
1355 		return 0;
1356 
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
1364 			    - srdb->config.srlb_lower_bound + 1)) {
1365 		srlb->active = false;
1366 		return -1;
1367 	}
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);
1382 	srlb->active = true;
1383 
1384 	return 0;
1385 }
1386 
1387 /**
1388  * Remove Segment Routing Local Block.
1389  *
1390  * @param area	IS-IS area
1391  */
sr_local_block_delete(struct isis_area * area)1392 static 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 
1397 	/* Check if SRLB is not already delete */
1398 	if (!srlb->active)
1399 		return;
1400 
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);
1411 	srlb->active = false;
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  */
sr_local_block_request_label(struct sr_local_block * srlb)1422 static 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  */
sr_local_block_release_label(struct sr_local_block * srlb,mpls_label_t label)1464 static 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 
1497 /* --- Segment Routing Adjacency-SID management functions ------------------- */
1498 
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  */
sr_adj_sid_add_single(struct isis_adjacency * adj,int family,bool backup)1506 static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
1507 				  bool backup)
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;
1516 	mpls_label_t input_label;
1517 
1518 	sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area->area_tag,
1519 		 backup ? "Backup" : "Primary");
1520 
1521 	/* Determine nexthop IP address */
1522 	switch (family) {
1523 	case AF_INET:
1524 		if (!circuit->ip_router || !adj->ipv4_address_count)
1525 			return;
1526 
1527 		nexthop.ipv4 = adj->ipv4_addresses[0];
1528 		break;
1529 	case AF_INET6:
1530 		if (!circuit->ipv6_router || !adj->ipv6_address_count)
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 
1541 	/* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
1542 	flags = EXT_SUBTLV_LINK_ADJ_SID_VFLG | EXT_SUBTLV_LINK_ADJ_SID_LFLG;
1543 	if (family == AF_INET6)
1544 		SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG);
1545 	if (backup)
1546 		SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG);
1547 
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 
1553 	if (circuit->ext == NULL)
1554 		circuit->ext = isis_alloc_ext_subtlvs();
1555 
1556 	sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
1557 	sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
1558 	sra->nexthop.family = family;
1559 	sra->nexthop.address = nexthop;
1560 	sra->nexthop.label = input_label;
1561 	switch (circuit->circ_type) {
1562 	/* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
1563 	case CIRCUIT_T_BROADCAST:
1564 		ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid));
1565 		ladj_sid->family = family;
1566 		ladj_sid->flags = flags;
1567 		ladj_sid->weight = 0;
1568 		memcpy(ladj_sid->neighbor_id, adj->sysid,
1569 		       sizeof(ladj_sid->neighbor_id));
1570 		ladj_sid->sid = input_label;
1571 		isis_tlvs_add_lan_adj_sid(circuit->ext, ladj_sid);
1572 		sra->u.ladj_sid = ladj_sid;
1573 		break;
1574 	/* Adjacency-SID for Point to Point interface section #2.2.1 */
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;
1580 		adj_sid->sid = input_label;
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 	}
1589 
1590 	/* Add Adjacency-SID in SRDB */
1591 	sra->adj = adj;
1592 	listnode_add(area->srdb.adj_sids, sra);
1593 	listnode_add(adj->adj_sids, sra);
1594 
1595 	isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
1596 }
1597 
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  */
sr_adj_sid_add(struct isis_adjacency * adj,int family)1604 static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
1605 {
1606 	sr_adj_sid_add_single(adj, family, false);
1607 	sr_adj_sid_add_single(adj, family, true);
1608 }
1609 
sr_adj_sid_update(struct sr_adjacency * sra,struct sr_local_block * srlb)1610 static 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 
1640 /**
1641  * Delete local Adj-SID.
1642  *
1643  * @param sra	Segment Routing Adjacency
1644  */
sr_adj_sid_del(struct sr_adjacency * sra)1645 static void sr_adj_sid_del(struct sr_adjacency *sra)
1646 {
1647 	struct isis_circuit *circuit = sra->adj->circuit;
1648 	struct isis_area *area = circuit->area;
1649 
1650 	sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area->area_tag);
1651 
1652 	isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
1653 
1654 	/* Release dynamic label and remove subTLVs */
1655 	switch (circuit->circ_type) {
1656 	case CIRCUIT_T_BROADCAST:
1657 		sr_local_block_release_label(&area->srdb.srlb,
1658 					     sra->u.ladj_sid->sid);
1659 		isis_tlvs_del_lan_adj_sid(circuit->ext, sra->u.ladj_sid);
1660 		break;
1661 	case CIRCUIT_T_P2P:
1662 		sr_local_block_release_label(&area->srdb.srlb,
1663 					     sra->u.adj_sid->sid);
1664 		isis_tlvs_del_adj_sid(circuit->ext, sra->u.adj_sid);
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 
1672 	/* Remove Adjacency-SID from the SRDB */
1673 	listnode_delete(area->srdb.adj_sids, sra);
1674 	listnode_delete(sra->adj->adj_sids, sra);
1675 	XFREE(MTYPE_ISIS_SR_INFO, sra);
1676 }
1677 
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  */
sr_adj_state_change(struct isis_adjacency * adj)1685 static int sr_adj_state_change(struct isis_adjacency *adj)
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))
1697 		sr_adj_sid_del(sra);
1698 
1699 	return 0;
1700 }
1701 
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
1710  */
sr_adj_ip_enabled(struct isis_adjacency * adj,int family)1711 static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
1712 {
1713 	if (!adj->circuit->area->srdb.enabled)
1714 		return 0;
1715 
1716 	sr_adj_sid_add(adj, family);
1717 
1718 	return 0;
1719 }
1720 
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
1729  */
sr_adj_ip_disabled(struct isis_adjacency * adj,int family)1730 static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
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)
1740 			sr_adj_sid_del(sra);
1741 
1742 	return 0;
1743 }
1744 
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  */
sr_if_new_hook(struct interface * ifp)1752 static int sr_if_new_hook(struct interface *ifp)
1753 {
1754 	struct isis_circuit *circuit;
1755 	struct isis_area *area;
1756 	struct connected *connected;
1757 	struct listnode *node;
1758 
1759 	/* Get corresponding circuit */
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 
1780 		if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)
1781 		    && !pcfg->node_sid) {
1782 			pcfg->node_sid = true;
1783 			lsp_regenerate_schedule(area, area->is_type, 0);
1784 		}
1785 	}
1786 
1787 	return 0;
1788 }
1789 
1790 /* --- Segment Routing Show information functions --------------------------- */
1791 
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  */
sr_op2str(char * buf,size_t size,mpls_label_t label_in,mpls_label_t label_out)1802 static 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 
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  */
show_prefix_sid_local(struct vty * vty,struct ttable * tt,const struct isis_area * area,const struct sr_prefix * srp)1839 static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
1840 				  const struct isis_area *area,
1841 				  const struct sr_prefix *srp)
1842 {
1843 	const struct sr_nexthop_info *srnh = &srp->u.local.info;
1844 	char buf_prefix[BUFSIZ];
1845 	char buf_oper[BUFSIZ];
1846 	char buf_iface[BUFSIZ];
1847 	char buf_uptime[BUFSIZ];
1848 
1849 	if (srnh->label != MPLS_INVALID_LABEL) {
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), "-");
1856 		log_uptime(srnh->uptime, buf_uptime, sizeof(buf_uptime));
1857 	} else {
1858 		snprintf(buf_iface, sizeof(buf_iface), "-");
1859 		snprintf(buf_uptime, sizeof(buf_uptime), "-");
1860 	}
1861 	sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
1862 		  MPLS_LABEL_IMPLICIT_NULL);
1863 
1864 	ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
1865 		       prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
1866 		       srp->sid.value, buf_oper, buf_iface, buf_uptime);
1867 }
1868 
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  */
show_prefix_sid_remote(struct vty * vty,struct ttable * tt,const struct isis_area * area,const struct sr_prefix * srp)1877 static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
1878 				   const struct isis_area *area,
1879 				   const struct sr_prefix *srp)
1880 {
1881 	struct isis_nexthop *nexthop;
1882 	struct listnode *node;
1883 	char buf_prefix[BUFSIZ];
1884 	char buf_oper[BUFSIZ];
1885 	char buf_nhop[BUFSIZ];
1886 	char buf_iface[BUFSIZ];
1887 	char buf_uptime[BUFSIZ];
1888 	bool first = true;
1889 
1890 	(void)prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix));
1891 
1892 	if (!srp->u.remote.rinfo) {
1893 		ttable_add_row(tt, "%s|%u|%s|-|-|-", buf_prefix, srp->sid.value,
1894 			       sr_op2str(buf_oper, sizeof(buf_oper),
1895 					 srp->input_label,
1896 					 MPLS_LABEL_IMPLICIT_NULL));
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);
1912 		if (nexthop->sr.label == MPLS_INVALID_LABEL)
1913 			snprintf(buf_uptime, sizeof(buf_uptime), "-");
1914 		else
1915 			log_uptime(nexthop->sr.uptime, buf_uptime,
1916 				   sizeof(buf_uptime));
1917 		sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
1918 			  nexthop->sr.label);
1919 
1920 		if (first)
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);
1924 		else
1925 			ttable_add_row(tt, "|||%s|%s|%s|%s", buf_oper, buf_nhop,
1926 				       buf_iface, buf_uptime);
1927 		first = false;
1928 	}
1929 }
1930 
1931 /**
1932  * Show Prefix-SIDs.
1933  *
1934  * @param vty	VTY output
1935  * @param area	IS-IS area
1936  * @param level	IS-IS level
1937  */
show_prefix_sids(struct vty * vty,struct isis_area * area,int level)1938 static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
1939 {
1940 	struct sr_prefix *srp;
1941 	struct ttable *tt;
1942 
1943 	if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
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]);
1950 	ttable_add_row(tt, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
1951 	tt->style.cell.rpad = 2;
1952 	tt->style.corner = '+';
1953 	ttable_restyle(tt);
1954 	ttable_rowseps(tt, 0, BOTTOM, true, '-');
1955 
1956 	/* Process all Prefix-SID from the SRDB */
1957 	frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
1958 		switch (srp->type) {
1959 		case ISIS_SR_PREFIX_LOCAL:
1960 			show_prefix_sid_local(vty, tt, area, srp);
1961 			break;
1962 		case ISIS_SR_PREFIX_REMOTE:
1963 			show_prefix_sid_remote(vty, tt, area, srp);
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 
1979 /**
1980  * Declaration of new show commands.
1981  */
1982 DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
1983       "show isis [vrf <NAME|all>] segment-routing prefix-sids",
1984       SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
1985       "All VRFs\n"
1986       "Segment-Routing\n"
1987       "Segment-Routing Prefix-SIDs\n")
1988 {
1989 	struct listnode *node, *inode;
1990 	struct isis_area *area;
1991 	struct isis *isis = NULL;
1992 	const char *vrf_name = VRF_DEFAULT_NAME;
1993 	bool all_vrf = false;
1994 	int idx_vrf = 0;
1995 
1996 	ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
1997 	if (vrf_name) {
1998 		if (all_vrf) {
1999 			for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
2000 				for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
2001 							  area)) {
2002 					vty_out(vty, "Area %s:\n",
2003 						area->area_tag ? area->area_tag
2004 							       : "null");
2005 					for (int level = ISIS_LEVEL1;
2006 					     level <= ISIS_LEVELS; level++)
2007 						show_prefix_sids(vty, area,
2008 								 level);
2009 				}
2010 			}
2011 			return 0;
2012 		}
2013 		isis = isis_lookup_by_vrfname(vrf_name);
2014 		if (isis != NULL) {
2015 			for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
2016 						  area)) {
2017 				vty_out(vty, "Area %s:\n",
2018 					area->area_tag ? area->area_tag
2019 						       : "null");
2020 				for (int level = ISIS_LEVEL1;
2021 				     level <= ISIS_LEVELS; level++)
2022 					show_prefix_sids(vty, area, level);
2023 			}
2024 		}
2025 	}
2026 
2027 	return CMD_SUCCESS;
2028 }
2029 
2030 /**
2031  * Show Segment Routing Node.
2032  *
2033  * @param vty	VTY output
2034  * @param area	IS-IS area
2035  * @param level	IS-IS level
2036  */
show_node(struct vty * vty,struct isis_area * area,int level)2037 static void show_node(struct vty *vty, struct isis_area *area, int level)
2038 {
2039 	struct sr_node *srn;
2040 	struct ttable *tt;
2041 
2042 	if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
2043 		return;
2044 
2045 	vty_out(vty, " IS-IS %s SR-Node:\n\n", circuit_t2string(level));
2046 
2047 	/* Prepare table. */
2048 	tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2049 	ttable_add_row(tt, "System ID|SRGB|SRLB|Algorithm|MSD");
2050 	tt->style.cell.rpad = 2;
2051 	tt->style.corner = '+';
2052 	ttable_restyle(tt);
2053 	ttable_rowseps(tt, 0, BOTTOM, true, '-');
2054 
2055 	/* Process all SR-Node from the SRDB */
2056 	frr_each (srdb_node, &area->srdb.sr_nodes[level - 1], srn) {
2057 		ttable_add_row(
2058 			tt, "%s|%u - %u|%u - %u|%s|%u",
2059 			sysid_print(srn->sysid),
2060 			srn->cap.srgb.lower_bound,
2061 			srn->cap.srgb.lower_bound + srn->cap.srgb.range_size
2062 				- 1,
2063 			srn->cap.srlb.lower_bound,
2064 			srn->cap.srlb.lower_bound + srn->cap.srlb.range_size
2065 				- 1,
2066 			srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF",
2067 			srn->cap.msd);
2068 	}
2069 
2070 	/* Dump the generated table. */
2071 	if (tt->nrows > 1) {
2072 		char *table;
2073 
2074 		table = ttable_dump(tt, "\n");
2075 		vty_out(vty, "%s\n", table);
2076 		XFREE(MTYPE_TMP, table);
2077 	}
2078 	ttable_del(tt);
2079 }
2080 
2081 DEFUN(show_sr_node, show_sr_node_cmd,
2082       "show isis segment-routing node",
2083       SHOW_STR PROTO_HELP
2084       "Segment-Routing\n"
2085       "Segment-Routing node\n")
2086 {
2087 	struct listnode *node, *inode;
2088 	struct isis_area *area;
2089 	struct isis *isis;
2090 
2091 	for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
2092 		for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
2093 			vty_out(vty, "Area %s:\n",
2094 				area->area_tag ? area->area_tag : "null");
2095 
2096 			for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
2097 			     level++)
2098 				show_node(vty, area, level);
2099 		}
2100 	}
2101 
2102 	return CMD_SUCCESS;
2103 }
2104 
2105 
2106 /* --- IS-IS Segment Routing Management function ---------------------------- */
2107 
2108 /**
2109  * Thread function to re-attempt connection to the Label Manager and thus be
2110  * able to start Segment Routing.
2111  *
2112  * @param start		Thread structure that contains area as argument
2113  *
2114  * @return		1 on success
2115  */
sr_start_label_manager(struct thread * start)2116 static int sr_start_label_manager(struct thread *start)
2117 {
2118 	struct isis_area *area;
2119 
2120 	area = THREAD_ARG(start);
2121 
2122 	/* re-attempt to start SR & Label Manager connection */
2123 	isis_sr_start(area);
2124 
2125 	return 1;
2126 }
2127 
2128 /**
2129  * Enable SR on the given IS-IS area.
2130  *
2131  * @param area	IS-IS area
2132  *
2133  * @return	0 on success, -1 otherwise
2134  */
isis_sr_start(struct isis_area * area)2135 int isis_sr_start(struct isis_area *area)
2136 {
2137 	struct isis_sr_db *srdb = &area->srdb;
2138 	struct isis_adjacency *adj;
2139 	struct listnode *node;
2140 
2141 	/* First start Label Manager if not ready */
2142 	if (!isis_zebra_label_manager_ready())
2143 		if (isis_zebra_label_manager_connect() < 0) {
2144 			/* Re-attempt to connect to Label Manager in 1 sec. */
2145 			thread_add_timer(master, sr_start_label_manager, area,
2146 					 1, &srdb->t_start_lm);
2147 			return -1;
2148 		}
2149 
2150 	/* Label Manager is ready, initialize the SRLB */
2151 	if (sr_local_block_init(area) < 0)
2152 		return -1;
2153 
2154 	/*
2155 	 * Request SGRB to the label manager if not already active. If the
2156 	 * allocation fails, return an error to disable SR until a new SRGB
2157 	 * is successfully allocated.
2158 	 */
2159 	if (!srdb->srgb_active) {
2160 		if (isis_zebra_request_label_range(
2161 			    srdb->config.srgb_lower_bound,
2162 			    srdb->config.srgb_upper_bound
2163 				    - srdb->config.srgb_lower_bound + 1)
2164 		    < 0) {
2165 			srdb->srgb_active = false;
2166 			return -1;
2167 		} else
2168 			srdb->srgb_active = true;
2169 	}
2170 
2171 	sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
2172 		 area->area_tag);
2173 
2174 	/* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
2175 	for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
2176 		if (adj->ipv4_address_count > 0)
2177 			sr_adj_sid_add(adj, AF_INET);
2178 		if (adj->ipv6_address_count > 0)
2179 			sr_adj_sid_add(adj, AF_INET6);
2180 	}
2181 
2182 	area->srdb.enabled = true;
2183 
2184 	/* Regenerate LSPs to advertise Segment Routing capabilities. */
2185 	lsp_regenerate_schedule(area, area->is_type, 0);
2186 
2187 	return 0;
2188 }
2189 
2190 /**
2191  * Disable SR on the given IS-IS area.
2192  *
2193  * @param area	IS-IS area
2194  */
isis_sr_stop(struct isis_area * area)2195 void isis_sr_stop(struct isis_area *area)
2196 {
2197 	struct isis_sr_db *srdb = &area->srdb;
2198 	struct sr_adjacency *sra;
2199 	struct listnode *node, *nnode;
2200 
2201 	sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
2202 		 area->area_tag);
2203 
2204 	/* Disable any re-attempt to connect to Label Manager */
2205 	THREAD_TIMER_OFF(srdb->t_start_lm);
2206 
2207 	/* Uninstall all local Adjacency-SIDs. */
2208 	for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
2209 		sr_adj_sid_del(sra);
2210 
2211 	/* Uninstall all Prefix-SIDs from all SR Node. */
2212 	for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
2213 		while (srdb_node_count(&srdb->sr_nodes[level - 1]) > 0) {
2214 			struct sr_node *srn;
2215 
2216 			srn = srdb_node_first(&srdb->sr_nodes[level - 1]);
2217 			sr_node_del(area, level, srn);
2218 		}
2219 	}
2220 
2221 	/* Release SRGB if active. */
2222 	if (srdb->srgb_active) {
2223 		isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
2224 					       srdb->config.srgb_upper_bound);
2225 		srdb->srgb_active = false;
2226 	}
2227 
2228 	/* Delete SRLB */
2229 	sr_local_block_delete(area);
2230 
2231 	area->srdb.enabled = false;
2232 
2233 	/* Regenerate LSPs to advertise that the Node is no more SR enable. */
2234 	lsp_regenerate_schedule(area, area->is_type, 0);
2235 }
2236 
2237 /**
2238  * IS-IS Segment Routing initialization for given area.
2239  *
2240  * @param area	IS-IS area
2241  */
isis_sr_area_init(struct isis_area * area)2242 void isis_sr_area_init(struct isis_area *area)
2243 {
2244 	struct isis_sr_db *srdb = &area->srdb;
2245 
2246 	sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
2247 		 area->area_tag);
2248 
2249 	/* Initialize Segment Routing Data Base */
2250 	memset(srdb, 0, sizeof(*srdb));
2251 	srdb->adj_sids = list_new();
2252 
2253 	for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
2254 		srdb_node_init(&srdb->sr_nodes[level - 1]);
2255 		srdb_area_prefix_init(&srdb->prefix_sids[level - 1]);
2256 	}
2257 
2258 	/* Pull defaults from the YANG module. */
2259 #ifndef FABRICD
2260 	srdb->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SR);
2261 	srdb->config.srgb_lower_bound =
2262 		yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR);
2263 	srdb->config.srgb_upper_bound =
2264 		yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR);
2265 	srdb->config.srlb_lower_bound =
2266 		yang_get_default_uint32("%s/srlb/lower-bound", ISIS_SR);
2267 	srdb->config.srlb_upper_bound =
2268 		yang_get_default_uint32("%s/srlb/upper-bound", ISIS_SR);
2269 #else
2270 	srdb->config.enabled = false;
2271 	srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND;
2272 	srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND;
2273 	srdb->config.srlb_lower_bound = SRLB_LOWER_BOUND;
2274 	srdb->config.srlb_upper_bound = SRLB_UPPER_BOUND;
2275 #endif
2276 	srdb->config.msd = 0;
2277 	srdb_prefix_cfg_init(&srdb->config.prefix_sids);
2278 }
2279 
2280 /**
2281  * Terminate IS-IS Segment Routing for the given area.
2282  *
2283  * @param area	IS-IS area
2284  */
isis_sr_area_term(struct isis_area * area)2285 void isis_sr_area_term(struct isis_area *area)
2286 {
2287 	struct isis_sr_db *srdb = &area->srdb;
2288 
2289 	/* Stop Segment Routing */
2290 	if (area->srdb.enabled)
2291 		isis_sr_stop(area);
2292 
2293 	/* Clear Prefix-SID configuration. */
2294 	while (srdb_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
2295 		struct sr_prefix_cfg *pcfg;
2296 
2297 		pcfg = srdb_prefix_cfg_first(&srdb->config.prefix_sids);
2298 		isis_sr_cfg_prefix_del(pcfg);
2299 	}
2300 }
2301 
2302 /**
2303  * IS-IS Segment Routing global initialization.
2304  */
isis_sr_init(void)2305 void isis_sr_init(void)
2306 {
2307 	install_element(VIEW_NODE, &show_sr_prefix_sids_cmd);
2308 	install_element(VIEW_NODE, &show_sr_node_cmd);
2309 
2310 	/* Register hooks. */
2311 	hook_register(isis_adj_state_change_hook, sr_adj_state_change);
2312 	hook_register(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
2313 	hook_register(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
2314 	hook_register(isis_route_update_hook, sr_route_update);
2315 	hook_register(isis_if_new_hook, sr_if_new_hook);
2316 }
2317 
2318 /**
2319  * IS-IS Segment Routing global terminate.
2320  */
isis_sr_term(void)2321 void isis_sr_term(void)
2322 {
2323 	/* Unregister hooks. */
2324 	hook_unregister(isis_adj_state_change_hook, sr_adj_state_change);
2325 	hook_unregister(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
2326 	hook_unregister(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
2327 	hook_unregister(isis_route_update_hook, sr_route_update);
2328 	hook_unregister(isis_if_new_hook, sr_if_new_hook);
2329 }
2330