summaryrefslogtreecommitdiff
path: root/isisd
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2020-05-14 14:23:03 -0300
committerGitHub <noreply@github.com>2020-05-14 14:23:03 -0300
commit82624cef0cf4475aed2be23ed8cad02a8e886d2e (patch)
treefd5e4533504bc0ebd10546a76a0c1a037434d599 /isisd
parent774e3570e9e47d2b259c0380377e078746cffeff (diff)
parentd4d008fea1172e6981ad18518a311d13c96269ed (diff)
Merge pull request #6342 from Orange-OpenSource/dev_isis_srdev_isis_sr
isisd: Preparation to merge Segment-Routing into master
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_nb_config.c8
-rw-r--r--isisd/isis_sr.c1327
-rw-r--r--isisd/isis_sr.h105
-rw-r--r--isisd/isis_tlvs.c28
-rw-r--r--isisd/isis_tlvs.h24
-rw-r--r--isisd/isis_zebra.c84
-rw-r--r--isisd/isis_zebra.h5
-rw-r--r--isisd/isisd.h6
8 files changed, 1065 insertions, 522 deletions
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index ec3b7baa31..a649e896fa 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -1521,7 +1521,9 @@ int isis_instance_segment_routing_msd_node_msd_modify(
area = nb_running_get_entry(args->dnode, NULL, true);
area->srdb.config.msd = yang_dnode_get_uint8(args->dnode, NULL);
- isis_sr_cfg_msd_update(area);
+
+ /* Update and regenerate LSP */
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -1536,7 +1538,9 @@ int isis_instance_segment_routing_msd_node_msd_destroy(
area = nb_running_get_entry(args->dnode, NULL, true);
area->srdb.config.msd = 0;
- isis_sr_cfg_msd_update(area);
+
+ /* Update and regenerate LSP */
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index 9bdb2c40e8..c24c0608b2 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -1,8 +1,7 @@
/*
- * This is an implementation of Segment Routing for IS-IS
- * as per draft draft-ietf-isis-segment-routing-extensions-25
+ * This is an implementation of Segment Routing for IS-IS as per RFC 8667
*
- * Copyright (C) 2019 Orange Labs http://www.orange.com
+ * Copyright (C) 2019 Orange http://www.orange.com
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
@@ -48,54 +47,96 @@
#include "isisd/isis_zebra.h"
#include "isisd/isis_errors.h"
+/* Local variables and functions */
DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
-static void isis_sr_prefix_uninstall(struct sr_prefix *srp);
-static void isis_sr_prefix_reinstall(struct sr_prefix *srp,
- bool replace_semantics);
+static void sr_prefix_uninstall(struct sr_prefix *srp);
+static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
-/*----------------------------------------------------------------------------*/
+/* --- RB-Tree Management functions ----------------------------------------- */
+/**
+ * SR Prefix comparison for RB-Tree.
+ *
+ * @param a First SR prefix
+ * @param b Second SR prefix
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
static inline int sr_prefix_sid_compare(const struct sr_prefix *a,
const struct sr_prefix *b)
{
return prefix_cmp(&a->prefix, &b->prefix);
}
-DECLARE_RBTREE_UNIQ(tree_sr_node_prefix, struct sr_prefix, node_entry,
+DECLARE_RBTREE_UNIQ(srdb_node_prefix, struct sr_prefix, node_entry,
sr_prefix_sid_compare)
-DECLARE_RBTREE_UNIQ(tree_sr_area_prefix, struct sr_prefix, area_entry,
+DECLARE_RBTREE_UNIQ(srdb_area_prefix, struct sr_prefix, area_entry,
sr_prefix_sid_compare)
+/**
+ * Configured SR Prefix comparison for RB-Tree.
+ *
+ * @param a First SR prefix
+ * @param b Second SR prefix
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
const struct sr_prefix_cfg *b)
{
return prefix_cmp(&a->prefix, &b->prefix);
}
-DECLARE_RBTREE_UNIQ(tree_sr_prefix_cfg, struct sr_prefix_cfg, entry,
+DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
sr_prefix_sid_cfg_compare)
+/**
+ * SR Node comparison for RB-Tree.
+ *
+ * @param a First SR node
+ * @param b Second SR node
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
static inline int sr_node_compare(const struct sr_node *a,
const struct sr_node *b)
{
return memcmp(a->sysid, b->sysid, ISIS_SYS_ID_LEN);
}
-DECLARE_RBTREE_UNIQ(tree_sr_node, struct sr_node, entry, sr_node_compare)
+DECLARE_RBTREE_UNIQ(srdb_node, struct sr_node, entry, sr_node_compare)
-/*----------------------------------------------------------------------------*/
+/* --- Functions used for Yang model and CLI to configure Segment Routing --- */
-/* Returns true if the interface/address pair corresponds to a Node-SID. */
-static bool isis_sr_prefix_is_node_sid(const struct interface *ifp,
- const struct prefix *prefix)
+/**
+ * Check if prefix correspond to a Node SID.
+ *
+ * @param ifp Interface
+ * @param prefix Prefix to be checked
+ *
+ * @return True if the interface/address pair corresponds to a Node-SID
+ */
+static bool sr_prefix_is_node_sid(const struct interface *ifp,
+ const struct prefix *prefix)
{
return (if_is_loopback(ifp) && is_host_route(prefix));
}
-/* Handle changes in the local SRGB configuration. */
+/**
+ * Update local SRGB configuration. SRGB is reserved though Label Manager.
+ * This function trigger the update of local Prefix-SID installation.
+ *
+ * @param area IS-IS area
+ * @param lower_bound Lower bound of SRGB
+ * @param upper_bound Upper bound of SRGB
+ *
+ * @return 0 on success, -1 otherwise
+ */
int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
uint32_t upper_bound)
{
struct isis_sr_db *srdb = &area->srdb;
+ sr_debug("ISIS-Sr (%s): Update SRGB", area->area_tag);
+
/* First release the old SRGB. */
if (srdb->config.enabled)
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
@@ -114,11 +155,15 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
- srdb->config.srgb_lower_bound + 1))
return -1;
+ sr_debug(" |- Got new SRGB %u/%u",
+ srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound);
+
/* Reinstall local Prefix-SIDs to update their input labels. */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
- frr_each (tree_sr_area_prefix,
+ frr_each (srdb_area_prefix,
&area->srdb.prefix_sids[level - 1], srp) {
- isis_sr_prefix_reinstall(srp, false);
+ sr_prefix_reinstall(srp, false);
}
}
@@ -132,19 +177,22 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
return 0;
}
-/* Handle changes in the local MSD configuration. */
-void isis_sr_cfg_msd_update(struct isis_area *area)
-{
- lsp_regenerate_schedule(area, area->is_type, 0);
-}
-
-/* Handle new Prefix-SID configuration. */
+/**
+ * Add new Prefix-SID configuration to the SRDB.
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to be added
+ *
+ * @return Newly added Prefix-SID configuration structure
+ */
struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
const struct prefix *prefix)
{
struct sr_prefix_cfg *pcfg;
struct interface *ifp;
+ sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
+
pcfg = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*pcfg));
pcfg->prefix = *prefix;
pcfg->area = area;
@@ -157,36 +205,57 @@ struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
/* Set the N-flag when appropriate. */
ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
- if (ifp && isis_sr_prefix_is_node_sid(ifp, prefix))
+ if (ifp && sr_prefix_is_node_sid(ifp, prefix))
pcfg->node_sid = true;
/* Save prefix-sid configuration. */
- tree_sr_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
+ srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
return pcfg;
}
-/* Handle removal of locally configured Prefix-SID. */
+/**
+ * Removal of locally configured Prefix-SID.
+ *
+ * @param pcfg Configured Prefix-SID
+ */
void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
{
- struct isis_area *area;
+ struct isis_area *area = pcfg->area;
- area = pcfg->area;
- tree_sr_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
+ sr_debug("ISIS-Sr (%s): Delete local Prefix-SID %pFX %s %u",
+ area->area_tag, &pcfg->prefix,
+ pcfg->sid_type == SR_SID_VALUE_TYPE_INDEX ? "index" : "label",
+ pcfg->sid);
+
+ srdb_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
XFREE(MTYPE_ISIS_SR_INFO, pcfg);
}
-/* Lookup Prefix-SID in the local configuration. */
+/**
+ * Lookup for Prefix-SID in the local configuration.
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to lookup
+ *
+ * @return Configured Prefix-SID structure if found, NULL otherwise
+ */
struct sr_prefix_cfg *isis_sr_cfg_prefix_find(struct isis_area *area,
union prefixconstptr prefix)
{
struct sr_prefix_cfg pcfg = {};
prefix_copy(&pcfg.prefix, prefix.p);
- return tree_sr_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
+ return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
}
-/* Fill in Prefix-SID Sub-TLV according to the corresponding configuration. */
+/**
+ * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
+ *
+ * @param pcfg Prefix-SID configuration
+ * @param external False if prefix is locally configured, true otherwise
+ * @param psid Prefix-SID sub-TLV to be updated
+ */
void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
struct isis_prefix_sid *psid)
{
@@ -222,20 +291,30 @@ void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
}
}
-/*----------------------------------------------------------------------------*/
+/* --- Segment Routing Prefix Management functions -------------------------- */
-static struct sr_prefix *isis_sr_prefix_add(struct isis_area *area,
- struct sr_node *srn,
- union prefixconstptr prefix,
- bool local,
- const struct isis_prefix_sid *psid)
+/**
+ * Add Segment Routing Prefix to a given Segment Routing Node.
+ *
+ * @param area IS-IS area
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to be added
+ * @param local True if prefix is locally configured, false otherwise
+ * @param psid Prefix-SID sub-TLVs
+ *
+ * @return New Segment Routing Prefix structure
+ */
+static struct sr_prefix *sr_prefix_add(struct isis_area *area,
+ struct sr_node *srn,
+ union prefixconstptr prefix, bool local,
+ const struct isis_prefix_sid *psid)
{
struct sr_prefix *srp;
srp = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srp));
prefix_copy(&srp->prefix, prefix.p);
srp->sid = *psid;
- srp->local_label = MPLS_INVALID_LABEL;
+ srp->input_label = MPLS_INVALID_LABEL;
if (local) {
srp->type = ISIS_SR_PREFIX_LOCAL;
isis_sr_nexthop_reset(&srp->u.local.info);
@@ -244,45 +323,89 @@ static struct sr_prefix *isis_sr_prefix_add(struct isis_area *area,
srp->u.remote.rinfo = NULL;
}
srp->srn = srn;
- tree_sr_node_prefix_add(&srn->prefix_sids, srp);
+ srdb_node_prefix_add(&srn->prefix_sids, srp);
/* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
- tree_sr_area_prefix_add(&area->srdb.prefix_sids[srn->level - 1], srp);
+ srdb_area_prefix_add(&area->srdb.prefix_sids[srn->level - 1], srp);
+
+ sr_debug(" |- Added new SR Prefix-SID %pFX %s %u to SR Node %s",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, sysid_print(srn->sysid));
return srp;
}
-static void isis_sr_prefix_del(struct isis_area *area, struct sr_node *srn,
- struct sr_prefix *srp)
+/**
+ * Remove given Segment Prefix from given Segment Routing Node.
+ * Prefix-SID is un-installed first.
+ *
+ * @param area IS-IS area
+ * @param srn Segment Routing Node
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_del(struct isis_area *area, struct sr_node *srn,
+ struct sr_prefix *srp)
{
- isis_sr_prefix_uninstall(srp);
- tree_sr_node_prefix_del(&srn->prefix_sids, srp);
- tree_sr_area_prefix_del(&area->srdb.prefix_sids[srn->level - 1], srp);
+ sr_debug(" |- Delete SR Prefix-SID %pFX %s %u to SR Node %s",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, sysid_print(srn->sysid));
+
+ sr_prefix_uninstall(srp);
+ srdb_node_prefix_del(&srn->prefix_sids, srp);
+ srdb_area_prefix_del(&area->srdb.prefix_sids[srn->level - 1], srp);
XFREE(MTYPE_ISIS_SR_INFO, srp);
}
-static struct sr_prefix *isis_sr_prefix_find_area(struct isis_area *area,
- int level,
- union prefixconstptr prefix)
+/**
+ * Find Segment Routing Prefix by Area.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param prefix Prefix to lookup
+ *
+ * @return Segment Routing Prefix structure if found, NULL otherwise
+ */
+static struct sr_prefix *sr_prefix_find_by_area(struct isis_area *area,
+ int level,
+ union prefixconstptr prefix)
{
struct sr_prefix srp = {};
prefix_copy(&srp.prefix, prefix.p);
- return tree_sr_area_prefix_find(&area->srdb.prefix_sids[level - 1],
- &srp);
+ return srdb_area_prefix_find(&area->srdb.prefix_sids[level - 1], &srp);
}
-static struct sr_prefix *isis_sr_prefix_find_node(struct sr_node *srn,
- union prefixconstptr prefix)
+/**
+ * Find Segment Routing Prefix by Segment Routing Node.
+ *
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to lookup
+ *
+ * @return Segment Routing Prefix structure if found, NULL otherwise
+ */
+static struct sr_prefix *sr_prefix_find_by_node(struct sr_node *srn,
+ union prefixconstptr prefix)
{
struct sr_prefix srp = {};
prefix_copy(&srp.prefix, prefix.p);
- return tree_sr_node_prefix_find(&srn->prefix_sids, &srp);
+ return srdb_node_prefix_find(&srn->prefix_sids, &srp);
}
-static struct sr_node *isis_sr_node_add(struct isis_area *area, int level,
- const uint8_t *sysid,
- const struct isis_router_cap *cap)
+/* --- Segment Routing Node Management functions ---------------------------- */
+
+/**
+ * Add Segment Routing Node to the Segment Routing Data Base.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Node System ID
+ * @param cap Segment Routing Capability sub-TLVs
+ *
+ * @return New Segment Routing Node structure
+ */
+static struct sr_node *sr_node_add(struct isis_area *area, int level,
+ const uint8_t *sysid,
+ const struct isis_router_cap *cap)
{
struct sr_node *srn;
@@ -291,43 +414,74 @@ static struct sr_node *isis_sr_node_add(struct isis_area *area, int level,
memcpy(srn->sysid, sysid, ISIS_SYS_ID_LEN);
srn->cap = *cap;
srn->area = area;
- tree_sr_node_prefix_init(&srn->prefix_sids);
- tree_sr_node_add(&area->srdb.sr_nodes[level - 1], srn);
+ srdb_node_prefix_init(&srn->prefix_sids);
+ srdb_node_add(&area->srdb.sr_nodes[level - 1], srn);
+
+ sr_debug(" |- Added new SR Node %s", sysid_print(srn->sysid));
return srn;
}
-static void isis_sr_node_del(struct isis_area *area, int level,
- struct sr_node *srn)
+static void sr_node_del(struct isis_area *area, int level, struct sr_node *srn)
+/**
+ * Remove Segment Routing Node from the Segment Routing Data Base.
+ * All Prefix-SID attached to this Segment Routing Node are removed first.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node to be deleted
+ */
{
+
+ sr_debug(" |- Delete SR Node %s", sysid_print(srn->sysid));
+
/* Remove and uninstall Prefix-SIDs. */
- while (tree_sr_node_prefix_count(&srn->prefix_sids) > 0) {
+ while (srdb_node_prefix_count(&srn->prefix_sids) > 0) {
struct sr_prefix *srp;
- srp = tree_sr_node_prefix_first(&srn->prefix_sids);
- isis_sr_prefix_del(area, srn, srp);
+ srp = srdb_node_prefix_first(&srn->prefix_sids);
+ sr_prefix_del(area, srn, srp);
}
- tree_sr_node_del(&area->srdb.sr_nodes[level - 1], srn);
+ srdb_node_del(&area->srdb.sr_nodes[level - 1], srn);
XFREE(MTYPE_ISIS_SR_INFO, srn);
}
-static struct sr_node *isis_sr_node_find(struct isis_area *area, int level,
- const uint8_t *sysid)
+/**
+ * Find Segment Routing Node in the Segment Routing Data Base per system ID.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Node System ID to lookup
+ *
+ * @return Segment Routing Node structure if found, NULL otherwise
+ */
+static struct sr_node *sr_node_find(struct isis_area *area, int level,
+ const uint8_t *sysid)
{
struct sr_node srn = {};
memcpy(srn.sysid, sysid, ISIS_SYS_ID_LEN);
- return tree_sr_node_find(&area->srdb.sr_nodes[level - 1], &srn);
+ return srdb_node_find(&area->srdb.sr_nodes[level - 1], &srn);
}
-static void isis_sr_adj_srgb_update(struct isis_area *area, uint8_t *sysid,
- int level)
+/**
+ * Update Segment Routing Node following an SRGB update. This function
+ * is called when a neighbor SR Node has updated its SRGB.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Segment Routing Node system ID
+ */
+static void sr_node_srgb_update(struct isis_area *area, int level,
+ uint8_t *sysid)
{
struct sr_prefix *srp;
- frr_each (tree_sr_area_prefix, &area->srdb.prefix_sids[level - 1],
- srp) {
+ sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
+ area->area_tag);
+
+ frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
struct listnode *node;
struct isis_nexthop *nh;
@@ -343,15 +497,25 @@ static void isis_sr_adj_srgb_update(struct isis_area *area, uint8_t *sysid,
continue;
/*
- * Reinstall all Prefix-SID nexthops using route replace
- * semantics.
+ * The Prefix-SID input label hasn't changed. We could
+ * re-install all Prefix-SID with "Make Before Break"
+ * option. Zebra layer will update output label(s) by
+ * adding new entry before removing the old one(s).
*/
- isis_sr_prefix_reinstall(srp, true);
+ sr_prefix_reinstall(srp, true);
break;
}
}
}
+/* --- Segment Routing Nexthop information Management functions ------------- */
+
+/**
+ * Update Segment Routing Nexthop.
+ *
+ * @param srnh Segment Routing next hop
+ * @param label Output MPLS label
+ */
void isis_sr_nexthop_update(struct sr_nexthop_info *srnh, mpls_label_t label)
{
srnh->label = label;
@@ -359,18 +523,31 @@ void isis_sr_nexthop_update(struct sr_nexthop_info *srnh, mpls_label_t label)
srnh->uptime = time(NULL);
}
+/**
+ * Reset Segment Routing Nexthop.
+ *
+ * @param srnh Segment Routing Nexthop
+ */
void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh)
{
srnh->label = MPLS_INVALID_LABEL;
srnh->uptime = 0;
}
-/*----------------------------------------------------------------------------*/
+/* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
-/* Lookup IS-IS route in the SPT. */
-static struct isis_route_info *
-isis_sr_prefix_lookup_route(struct isis_area *area, enum spf_tree_id tree_id,
- struct sr_prefix *srp)
+/**
+ * Lookup IS-IS route in the Shortest Path Tree.
+ *
+ * @param area IS-IS area
+ * @param tree_id Shortest Path Tree identifier
+ * @param srp Segment Routing Prefix to lookup
+ *
+ * @return Route Information for this prefix if found, NULL otherwise
+ */
+static struct isis_route_info *sr_prefix_lookup_route(struct isis_area *area,
+ enum spf_tree_id tree_id,
+ struct sr_prefix *srp)
{
struct route_node *rn;
int level = srp->srn->level;
@@ -386,18 +563,24 @@ isis_sr_prefix_lookup_route(struct isis_area *area, enum spf_tree_id tree_id,
return NULL;
}
-/* Calculate Prefix-SID input label. */
-static mpls_label_t isis_sr_prefix_in_label(const struct sr_prefix *srp)
+/**
+ * Compute input label for the given Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
+ */
+static mpls_label_t sr_prefix_in_label(const struct sr_prefix *srp)
{
const struct sr_node *srn = srp->srn;
struct isis_area *area = srn->area;
- /* Absolute SID value. */
+ /* Return SID value as MPLS label if it is an Absolute SID */
if (CHECK_FLAG(srp->sid.flags,
ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
return srp->sid.value;
- /* Index SID value. */
+ /* Check that SID index falls inside the SRGB */
if (srp->sid.value >= (area->srdb.config.srgb_upper_bound
- area->srdb.config.srgb_lower_bound + 1)) {
flog_warn(EC_ISIS_SID_OVERFLOW,
@@ -406,21 +589,32 @@ static mpls_label_t isis_sr_prefix_in_label(const struct sr_prefix *srp)
return MPLS_INVALID_LABEL;
}
+ /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
return (area->srdb.config.srgb_lower_bound + srp->sid.value);
}
-/* Calculate Prefix-SID output label. */
-static mpls_label_t isis_sr_prefix_out_label(const struct sr_prefix *srp,
- const struct sr_node *srn_nexthop,
- const uint8_t *sysid)
+/**
+ * Compute output label for the given Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ * @param srn_nexthop Segment Routing nexthop node
+ * @param sysid System ID of the SR node which advertised the Prefix-SID
+ *
+ * @return MPLS label or MPLS_INVALID_LABEL in case of error
+ */
+static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
+ const struct sr_node *srn_nexthop,
+ const uint8_t *sysid)
{
const struct sr_node *srn = srp->srn;
- /* Is the adjacency the last hop? */
+ /* Check if the nexthop SR Node is the last hop? */
if (memcmp(sysid, srn->sysid, ISIS_SYS_ID_LEN) == 0) {
+ /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP))
return MPLS_LABEL_IMPLICIT_NULL;
+ /* SR-Node requests Implicit NULL Label */
if (CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL)) {
if (srp->prefix.family == AF_INET)
return MPLS_LABEL_IPV4_EXPLICIT_NULL;
@@ -430,19 +624,19 @@ static mpls_label_t isis_sr_prefix_out_label(const struct sr_prefix *srp,
/* Fallthrough */
}
- /* Absolute SID value. */
+ /* Return SID value as MPLS label if it is an Absolute SID */
if (CHECK_FLAG(srp->sid.flags,
ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
/*
* V/L SIDs have local significance, so only adjacent routers
- * can use them.
+ * can use them (RFC8667 section #2.1.1.1)
*/
if (srp->srn != srn_nexthop)
return MPLS_INVALID_LABEL;
return srp->sid.value;
}
- /* Index SID value. */
+ /* Check that SID index falls inside the SRGB */
if (srp->sid.value >= srn_nexthop->cap.srgb.range_size) {
flog_warn(EC_ISIS_SID_OVERFLOW,
"%s: SID index %u falls outside remote SRGB range",
@@ -450,88 +644,92 @@ static mpls_label_t isis_sr_prefix_out_label(const struct sr_prefix *srp,
return MPLS_INVALID_LABEL;
}
+ /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
return (srn_nexthop->cap.srgb.lower_bound + srp->sid.value);
}
-/* Process local Prefix-SID and install it if possible. */
-static int isis_sr_prefix_install_local(struct sr_prefix *srp)
+/**
+ * Process local Prefix-SID and install it if possible. Input label is
+ * computed before installing it in LFIB.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int sr_prefix_install_local(struct sr_prefix *srp)
{
+ mpls_label_t input_label;
const struct sr_node *srn = srp->srn;
- struct isis_area *area = srn->area;
- mpls_label_t local_label;
/*
- * No need to install LSP to local Prefix-SID unless the
+ * No need to install Label for local Prefix-SID unless the
* no-PHP option is configured.
*/
if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP)
|| CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL))
return -1;
- if (IS_DEBUG_ISIS(DEBUG_SR)) {
- zlog_debug("ISIS-SR (%s) installing Prefix-SID %pFX %s %u (%s)",
- area->area_tag, &srp->prefix,
- CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_VALUE)
- ? "label"
- : "index",
- srp->sid.value, circuit_t2string(srn->level));
- zlog_debug(" nexthop self");
- }
+ sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s) with nexthop self",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, circuit_t2string(srn->level));
- /* Calculate local label. */
- local_label = isis_sr_prefix_in_label(srp);
- if (local_label == MPLS_INVALID_LABEL)
+ /* Compute input label and check that is valid. */
+ input_label = sr_prefix_in_label(srp);
+ if (input_label == MPLS_INVALID_LABEL)
return -1;
/* Update internal state. */
- srp->local_label = local_label;
+ srp->input_label = input_label;
isis_sr_nexthop_update(&srp->u.local.info, MPLS_LABEL_IMPLICIT_NULL);
/* Install Prefix-SID in the forwarding plane. */
- isis_zebra_install_prefix_sid(srp);
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
return 0;
}
-/* Process remote Prefix-SID and install it if possible. */
-static int isis_sr_prefix_install_remote(struct sr_prefix *srp)
+/**
+ * Process remote Prefix-SID and install it if possible. Input and Output
+ * labels are computed before installing them in LFIB.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int sr_prefix_install_remote(struct sr_prefix *srp)
{
const struct sr_node *srn = srp->srn;
struct isis_area *area = srn->area;
enum spf_tree_id tree_id;
struct listnode *node;
struct isis_nexthop *nexthop;
- mpls_label_t local_label;
+ mpls_label_t input_label;
size_t nexthop_num = 0;
- /* Lookup associated IS-IS route. */
+ /* Lookup to associated IS-IS route. */
tree_id = (srp->prefix.family == AF_INET) ? SPFTREE_IPV4 : SPFTREE_IPV6;
- srp->u.remote.rinfo = isis_sr_prefix_lookup_route(area, tree_id, srp);
+ srp->u.remote.rinfo = sr_prefix_lookup_route(area, tree_id, srp);
if (!srp->u.remote.rinfo)
/* SPF hasn't converged for this route yet. */
return -1;
- if (IS_DEBUG_ISIS(DEBUG_SR))
- zlog_debug("ISIS-SR (%s) installing Prefix-SID %pFX %s %u (%s)",
- area->area_tag, &srp->prefix,
- CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_VALUE)
- ? "label"
- : "index",
- srp->sid.value, circuit_t2string(srn->level));
-
- /* Calculate local label. */
- local_label = isis_sr_prefix_in_label(srp);
- if (local_label == MPLS_INVALID_LABEL)
+ /* Compute input label and check that is valid. */
+ input_label = sr_prefix_in_label(srp);
+ if (input_label == MPLS_INVALID_LABEL)
return -1;
+ sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s)", &srp->prefix,
+ IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, circuit_t2string(srn->level));
+
+ /* Process all SPF nexthops */
for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
nexthop)) {
struct sr_node *srn_nexthop;
- mpls_label_t remote_label;
+ mpls_label_t output_label;
/* Check if the nexthop advertised a SRGB. */
- srn_nexthop =
- isis_sr_node_find(area, srn->level, nexthop->sysid);
+ srn_nexthop = sr_node_find(area, srn->level, nexthop->sysid);
if (!srn_nexthop)
goto next;
@@ -545,9 +743,10 @@ static int isis_sr_prefix_install_remote(struct sr_prefix *srp)
&& !IS_SR_IPV6(srn_nexthop->cap.srgb)))
goto next;
- remote_label = isis_sr_prefix_out_label(srp, srn_nexthop,
- nexthop->sysid);
- if (remote_label == MPLS_INVALID_LABEL)
+ /* Compute output label and check if it is valid */
+ output_label =
+ sr_prefix_out_label(srp, srn_nexthop, nexthop->sysid);
+ if (output_label == MPLS_INVALID_LABEL)
goto next;
if (IS_DEBUG_ISIS(DEBUG_SR)) {
@@ -555,51 +754,61 @@ static int isis_sr_prefix_install_remote(struct sr_prefix *srp)
inet_ntop(nexthop->family, &nexthop->ip, buf,
sizeof(buf));
- zlog_debug(" nexthop %s label %u", buf, remote_label);
+ zlog_debug(" |- nexthop %s label %u", buf,
+ output_label);
}
- isis_sr_nexthop_update(&nexthop->sr, remote_label);
+ isis_sr_nexthop_update(&nexthop->sr, output_label);
nexthop_num++;
continue;
next:
isis_sr_nexthop_reset(&nexthop->sr);
}
+
+ /* Check that we found at least one valid nexthop */
if (nexthop_num == 0) {
- if (IS_DEBUG_ISIS(DEBUG_SR))
- zlog_debug(" no valid nexthops");
+ sr_debug(" |- no valid nexthops");
return -1;
}
/* Update internal state. */
- srp->local_label = local_label;
+ srp->input_label = input_label;
/* Install Prefix-SID in the forwarding plane. */
- isis_zebra_install_prefix_sid(srp);
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
return 0;
}
-/* Process local or remote Prefix-SID and install it if possible. */
-static void isis_sr_prefix_install(struct sr_prefix *srp)
+/**
+ * Process local or remote Prefix-SID and install it if possible.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_install(struct sr_prefix *srp)
{
const struct sr_node *srn = srp->srn;
struct isis_area *area = srn->area;
int ret;
+ sr_debug("ISIS-Sr (%s): Install Prefix-SID %pFX %s %u", area->area_tag,
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value);
+
/* L1 routes are preferred over the L2 ones. */
if (area->is_type == IS_LEVEL_1_AND_2) {
struct sr_prefix *srp_l1, *srp_l2;
switch (srn->level) {
case ISIS_LEVEL1:
- srp_l2 = isis_sr_prefix_find_area(area, ISIS_LEVEL2,
- &srp->prefix);
+ srp_l2 = sr_prefix_find_by_area(area, ISIS_LEVEL2,
+ &srp->prefix);
if (srp_l2)
- isis_sr_prefix_uninstall(srp_l2);
+ sr_prefix_uninstall(srp_l2);
break;
case ISIS_LEVEL2:
- srp_l1 = isis_sr_prefix_find_area(area, ISIS_LEVEL1,
- &srp->prefix);
+ srp_l1 = sr_prefix_find_by_area(area, ISIS_LEVEL1,
+ &srp->prefix);
if (srp_l1)
return;
break;
@@ -608,39 +817,38 @@ static void isis_sr_prefix_install(struct sr_prefix *srp)
}
}
+ /* Install corresponding LFIB entry */
if (srp->type == ISIS_SR_PREFIX_LOCAL)
- ret = isis_sr_prefix_install_local(srp);
+ ret = sr_prefix_install_local(srp);
else
- ret = isis_sr_prefix_install_remote(srp);
+ ret = sr_prefix_install_remote(srp);
if (ret != 0)
- isis_sr_prefix_uninstall(srp);
+ sr_prefix_uninstall(srp);
}
-/* Uninstall local or remote Prefix-SID. */
-static void isis_sr_prefix_uninstall(struct sr_prefix *srp)
+/**
+ * Uninstall local or remote Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_uninstall(struct sr_prefix *srp)
{
- const struct sr_node *srn = srp->srn;
struct listnode *node;
struct isis_nexthop *nexthop;
- if (srp->local_label == MPLS_INVALID_LABEL)
+ /* Check that Input Label is valid */
+ if (srp->input_label == MPLS_INVALID_LABEL)
return;
- if (IS_DEBUG_ISIS(DEBUG_SR))
- zlog_debug(
- "ISIS-SR (%s) uninstalling Prefix-SID %pFX %s %u (%s)",
- srn->area->area_tag, &srp->prefix,
- CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_VALUE)
- ? "label"
- : "index",
- srp->sid.value, circuit_t2string(srn->level));
-
+ sr_debug("ISIS-Sr: Un-install Prefix-SID %pFX %s %u", &srp->prefix,
+ IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value);
/* Uninstall Prefix-SID from the forwarding plane. */
- isis_zebra_uninstall_prefix_sid(srp);
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE, srp);
/* Reset internal state. */
- srp->local_label = MPLS_INVALID_LABEL;
+ srp->input_label = MPLS_INVALID_LABEL;
switch (srp->type) {
case ISIS_SR_PREFIX_LOCAL:
isis_sr_nexthop_reset(&srp->u.local.info);
@@ -655,81 +863,114 @@ static void isis_sr_prefix_uninstall(struct sr_prefix *srp)
}
}
-/* Reinstall local or remote Prefix-SID. */
-static void isis_sr_prefix_reinstall(struct sr_prefix *srp,
- bool replace_semantics)
+/**
+ * Reinstall local or remote Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static inline void sr_prefix_reinstall(struct sr_prefix *srp,
+ bool make_before_break)
{
/*
- * Route replace semantics can be used only when we know for sure that
+ * Make Before Break can be used only when we know for sure that
* the Prefix-SID input label hasn't changed. Otherwise we need to
* uninstall the Prefix-SID first using the old input label before
* reinstalling it.
*/
- if (!replace_semantics)
- isis_sr_prefix_uninstall(srp);
+ if (!make_before_break)
+ sr_prefix_uninstall(srp);
- isis_sr_prefix_install(srp);
+ /* New input label is computed in sr_prefix_install() function */
+ sr_prefix_install(srp);
}
-/*----------------------------------------------------------------------------*/
+/* --- IS-IS LSP Parse functions -------------------------------------------- */
-/* Parse all SR-related information from the given Router Capabilities TLV. */
+/**
+ * Parse all SR-related information from the given Router Capabilities TLV.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid System ID of the LSP
+ * @param router_cap Router Capability subTLVs
+ *
+ * @return Segment Routing Node structure for this System ID
+ */
static struct sr_node *
-isis_sr_parse_router_cap_tlv(struct isis_area *area, int level,
- const uint8_t *sysid,
- const struct isis_router_cap *router_cap)
+parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid,
+ const struct isis_router_cap *router_cap)
{
struct sr_node *srn;
if (!router_cap || router_cap->srgb.range_size == 0)
return NULL;
- srn = isis_sr_node_find(area, level, sysid);
+ sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area->area_tag);
+
+ srn = sr_node_find(area, level, sysid);
if (srn) {
if (memcmp(&srn->cap, router_cap, sizeof(srn->cap)) != 0) {
srn->cap = *router_cap;
- SET_FLAG(srn->parse_flags, F_ISIS_SR_NODE_MODIFIED);
+ srn->state = SRDB_STATE_MODIFIED;
} else
- SET_FLAG(srn->parse_flags, F_ISIS_SR_NODE_UNCHANGED);
+ srn->state = SRDB_STATE_UNCHANGED;
+ sr_debug(" |- Found %s SR Node %s",
+ srn->state == SRDB_STATE_MODIFIED ? "Modified"
+ : "Unchanged",
+ sysid_print(srn->sysid));
} else {
- srn = isis_sr_node_add(area, level, sysid, router_cap);
- SET_FLAG(srn->parse_flags, F_ISIS_SR_NODE_NEW);
+ srn = sr_node_add(area, level, sysid, router_cap);
+ srn->state = SRDB_STATE_NEW;
}
return srn;
}
-/* Parse list of Prefix-SID Sub-TLVs. */
-static void isis_sr_parse_prefix_sid_subtlvs(struct sr_node *srn,
- union prefixconstptr prefix,
- bool local,
- struct isis_item_list *prefix_sids)
+/**
+ * Parse list of Prefix-SID Sub-TLVs.
+ *
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to be parsed
+ * @param local True if prefix comes from own LSP, false otherwise
+ * @param prefix_sids Prefix SID subTLVs
+ */
+static void parse_prefix_sid_subtlvs(struct sr_node *srn,
+ union prefixconstptr prefix, bool local,
+ struct isis_item_list *prefix_sids)
{
struct isis_area *area = srn->area;
struct isis_item *i;
+ sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area->area_tag);
+
+ /* Parse list of Prefix SID subTLVs */
for (i = prefix_sids->head; i; i = i->next) {
struct isis_prefix_sid *psid = (struct isis_prefix_sid *)i;
struct sr_prefix *srp;
+ /* Only SPF algorithm is supported right now */
if (psid->algorithm != SR_ALGORITHM_SPF)
continue;
- srp = isis_sr_prefix_find_node(srn, prefix);
+ /* Compute corresponding Segment Routing Prefix */
+ srp = sr_prefix_find_by_node(srn, prefix);
if (srp) {
if (srp->sid.flags != psid->flags
|| srp->sid.algorithm != psid->algorithm
|| srp->sid.value != psid->value) {
srp->sid = *psid;
- SET_FLAG(srp->parse_flags,
- F_ISIS_SR_PREFIX_SID_MODIFIED);
+ srp->state = SRDB_STATE_MODIFIED;
} else
- SET_FLAG(srp->parse_flags,
- F_ISIS_SR_PREFIX_SID_UNCHANGED);
+ srp->state = SRDB_STATE_UNCHANGED;
+ sr_debug(" |- Found %s Prefix-SID %pFX",
+ srp->state == SRDB_STATE_MODIFIED
+ ? "Modified"
+ : "Unchanged",
+ &srp->prefix);
+
} else {
- srp = isis_sr_prefix_add(area, srn, prefix, local,
- psid);
- SET_FLAG(srp->parse_flags, F_ISIS_SR_PREFIX_SID_NEW);
+ srp = sr_prefix_add(area, srn, prefix, local, psid);
+ srp->state = SRDB_STATE_NEW;
}
/*
* Stop the Prefix-SID iteration since we only support the SPF
@@ -739,23 +980,34 @@ static void isis_sr_parse_prefix_sid_subtlvs(struct sr_node *srn,
}
}
-/* Parse all SR-related information from the given LSP. */
-static void isis_sr_parse_lsp(struct isis_area *area, int level,
- struct sr_node **srn, struct isis_lsp *lsp)
+/**
+ * Parse all SR-related information from the given LSP.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node
+ * @param lsp IS-IS LSP
+ */
+static void parse_lsp(struct isis_area *area, int level, struct sr_node **srn,
+ struct isis_lsp *lsp)
{
struct isis_item_list *items;
struct isis_item *i;
bool local = lsp->own_lsp;
+ /* Check LSP sequence number */
if (lsp->hdr.seqno == 0) {
zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
return;
}
+ sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area->area_tag,
+ sysid_print(lsp->hdr.lsp_id));
+
/* Parse the Router Capability TLV. */
if (*srn == NULL) {
- *srn = isis_sr_parse_router_cap_tlv(
- area, level, lsp->hdr.lsp_id, lsp->tlvs->router_cap);
+ *srn = parse_router_cap_tlv(area, level, lsp->hdr.lsp_id,
+ lsp->tlvs->router_cap);
if (!*srn)
return;
}
@@ -769,8 +1021,8 @@ static void isis_sr_parse_lsp(struct isis_area *area, int level,
if (!ir->subtlvs)
continue;
- isis_sr_parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
- &ir->subtlvs->prefix_sids);
+ parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
+ &ir->subtlvs->prefix_sids);
}
/* Parse Multi Topology Reachable IPv6 Prefixes TLV. */
@@ -783,78 +1035,88 @@ static void isis_sr_parse_lsp(struct isis_area *area, int level,
if (!ir->subtlvs)
continue;
- isis_sr_parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
- &ir->subtlvs->prefix_sids);
+ parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
+ &ir->subtlvs->prefix_sids);
}
}
-/* Parse all SR-related information from the entire LSPDB. */
-static void isis_sr_parse_lspdb(struct isis_area *area)
+/**
+ * Parse all SR-related information from the entire LSPDB.
+ *
+ * @param area IS-IS area
+ */
+static void parse_lspdb(struct isis_area *area)
{
struct isis_lsp *lsp;
+ sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area->area_tag);
+
+ /* Process all LSP from Level 1 & 2 */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
frr_each (lspdb, &area->lspdb[level - 1], lsp) {
struct isis_lsp *frag;
struct listnode *node;
struct sr_node *srn = NULL;
+ /* Skip Pseudo ID LSP and LSP without TLVs */
if (LSP_PSEUDO_ID(lsp->hdr.lsp_id))
continue;
if (!lsp->tlvs)
continue;
- isis_sr_parse_lsp(area, level, &srn, lsp);
+ /* Parse LSP, then fragment */
+ parse_lsp(area, level, &srn, lsp);
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
- isis_sr_parse_lsp(area, level, &srn, frag);
+ parse_lsp(area, level, &srn, frag);
}
}
}
-/* Process any new/deleted/modified Prefix-SID in the LSPDB. */
-static void isis_sr_process_prefix_changes(struct sr_node *srn,
- struct sr_prefix *srp)
+/**
+ * Process any new/deleted/modified Prefix-SID in the LSPDB.
+ *
+ * @param srn Segment Routing Node
+ * @param srp Segment Routing Prefix
+ */
+static void process_prefix_changes(struct sr_node *srn, struct sr_prefix *srp)
{
struct isis_area *area = srn->area;
- /* Log any Prefix-SID change in the LSPDB. */
- if (IS_DEBUG_ISIS(DEBUG_SR)) {
- if (CHECK_FLAG(srp->parse_flags, F_ISIS_SR_PREFIX_SID_NEW))
- zlog_debug(
- "ISIS-SR (%s) Prefix-SID created: %pFX (sysid %s)",
- area->area_tag, &srp->prefix,
- sysid_print(srn->sysid));
- else if (CHECK_FLAG(srp->parse_flags,
- F_ISIS_SR_PREFIX_SID_MODIFIED))
- zlog_debug(
- "ISIS-SR (%s) Prefix-SID modified: %pFX (sysid %s)",
- area->area_tag, &srp->prefix,
- sysid_print(srn->sysid));
- else if (!CHECK_FLAG(srp->parse_flags,
- F_ISIS_SR_PREFIX_SID_UNCHANGED))
- zlog_debug(
- "ISIS-SR (%s) Prefix-SID removed: %pFX (sysid %s)",
- area->area_tag, &srp->prefix,
- sysid_print(srn->sysid));
- }
-
/* Install/reinstall/uninstall Prefix-SID if necessary. */
- if (CHECK_FLAG(srp->parse_flags, F_ISIS_SR_PREFIX_SID_NEW))
- isis_sr_prefix_install(srp);
- else if (CHECK_FLAG(srp->parse_flags, F_ISIS_SR_PREFIX_SID_MODIFIED))
- isis_sr_prefix_reinstall(srp, false);
- else if (!CHECK_FLAG(srp->parse_flags,
- F_ISIS_SR_PREFIX_SID_UNCHANGED)) {
- isis_sr_prefix_del(area, srn, srp);
+ switch (srp->state) {
+ case SRDB_STATE_NEW:
+ sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_install(srp);
+ break;
+ case SRDB_STATE_MODIFIED:
+ sr_debug(
+ "ISIS-Sr (%s): Modified Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_reinstall(srp, false);
+ break;
+ case SRDB_STATE_UNCHANGED:
+ break;
+ default:
+ sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_del(area, srn, srp);
return;
}
- srp->parse_flags = 0;
+ /* Validate SRDB State for next LSPDB parsing */
+ srp->state = SRDB_STATE_VALIDATED;
}
-/* Process any new/deleted/modified SRGB in the LSPDB. */
-static void isis_sr_process_node_changes(struct isis_area *area, int level,
- struct sr_node *srn)
+/**
+ * Process any new/deleted/modified SRGB in the LSPDB.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node
+ */
+static void process_node_changes(struct isis_area *area, int level,
+ struct sr_node *srn)
{
struct sr_prefix *srp;
uint8_t sysid[ISIS_SYS_ID_LEN];
@@ -862,44 +1124,46 @@ static void isis_sr_process_node_changes(struct isis_area *area, int level,
memcpy(sysid, srn->sysid, sizeof(sysid));
- /* Log any SRGB change in the LSPDB. */
- if (IS_DEBUG_ISIS(DEBUG_SR)) {
- if (CHECK_FLAG(srn->parse_flags, F_ISIS_SR_NODE_NEW))
- zlog_debug("ISIS-SR (%s) SRGB created (sysid %s)",
- area->area_tag, sysid_print(sysid));
- else if (CHECK_FLAG(srn->parse_flags, F_ISIS_SR_NODE_MODIFIED))
- zlog_debug("ISIS-SR (%s) SRGB modified (sysid %s)",
- area->area_tag, sysid_print(sysid));
- else if (!CHECK_FLAG(srn->parse_flags,
- F_ISIS_SR_NODE_UNCHANGED))
- zlog_debug("ISIS-SR (%s) SRGB removed (sysid %s)",
- area->area_tag, sysid_print(sysid));
- }
-
/*
- * If an adjacent router's SRGB was changed or created, then reinstall
- * all Prefix-SIDs from all nodes.
+ * If an neighbor router's SRGB was changed or created, then reinstall
+ * all Prefix-SIDs from all nodes that use this neighbor as nexthop.
*/
adjacent = isis_adj_exists(area, level, sysid);
- if (CHECK_FLAG(srn->parse_flags,
- F_ISIS_SR_NODE_NEW | F_ISIS_SR_NODE_MODIFIED)) {
+ switch (srn->state) {
+ case SRDB_STATE_NEW:
+ case SRDB_STATE_MODIFIED:
+ sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
+ area->area_tag, sysid_print(srn->sysid));
if (adjacent)
- isis_sr_adj_srgb_update(area, sysid, level);
- } else if (!CHECK_FLAG(srn->parse_flags, F_ISIS_SR_NODE_UNCHANGED)) {
- isis_sr_node_del(area, level, srn);
+ sr_node_srgb_update(area, level, sysid);
+ break;
+ case SRDB_STATE_UNCHANGED:
+ break;
+ default:
+ /* SR capabilities have been removed. Delete SR-Node */
+ sr_debug("ISIS-Sr (%s): Remove SR node %s", area->area_tag,
+ sysid_print(srn->sysid));
+ sr_node_del(area, level, srn);
+ /* and Update remaining Prefix-SID from all remaining SR Node */
if (adjacent)
- isis_sr_adj_srgb_update(area, sysid, level);
+ sr_node_srgb_update(area, level, sysid);
return;
}
- srn->parse_flags = 0;
+ /* Validate SRDB State for next LSPDB parsing */
+ srn->state = SRDB_STATE_VALIDATED;
- frr_each_safe (tree_sr_node_prefix, &srn->prefix_sids, srp)
- isis_sr_process_prefix_changes(srn, srp);
+ /* Finally, process all Prefix-SID of this SR Node */
+ frr_each_safe (srdb_node_prefix, &srn->prefix_sids, srp)
+ process_prefix_changes(srn, srp);
}
-/* Parse and process all SR-related Sub-TLVs after running the SPF algorithm. */
+/**
+ * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
+ *
+ * @param area IS-IS area
+ */
void isis_area_verify_sr(struct isis_area *area)
{
struct sr_node *srn;
@@ -908,40 +1172,48 @@ void isis_area_verify_sr(struct isis_area *area)
return;
/* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
- isis_sr_parse_lspdb(area);
+ parse_lspdb(area);
/* Process possible SR-related changes in the LDPSB. */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
- frr_each_safe (tree_sr_node, &area->srdb.sr_nodes[level - 1],
- srn)
- isis_sr_process_node_changes(area, level, srn);
+ frr_each_safe (srdb_node, &area->srdb.sr_nodes[level - 1], srn)
+ process_node_changes(area, level, srn);
}
}
-/*
+/**
* Once a route is updated in the SPT, reinstall or uninstall its corresponding
* Prefix-SID (if any).
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to be updated
+ * @param route_info New Route Information
+ *
+ * @return 0
*/
-static int isis_sr_route_update(struct isis_area *area, struct prefix *prefix,
- struct isis_route_info *route_info)
+static int sr_route_update(struct isis_area *area, struct prefix *prefix,
+ struct isis_route_info *route_info)
{
struct sr_prefix *srp;
if (!area->srdb.enabled)
return 0;
+ sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area->area_tag,
+ prefix);
+
+ /* Lookup to Segment Routing Prefix for this prefix */
switch (area->is_type) {
case IS_LEVEL_1:
- srp = isis_sr_prefix_find_area(area, ISIS_LEVEL1, prefix);
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
break;
case IS_LEVEL_2:
- srp = isis_sr_prefix_find_area(area, ISIS_LEVEL2, prefix);
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
break;
case IS_LEVEL_1_AND_2:
- srp = isis_sr_prefix_find_area(area, ISIS_LEVEL1, prefix);
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
if (!srp)
- srp = isis_sr_prefix_find_area(area, ISIS_LEVEL2,
- prefix);
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
break;
default:
flog_err(EC_LIB_DEVELOPMENT, "%s: unknown area level",
@@ -949,51 +1221,38 @@ static int isis_sr_route_update(struct isis_area *area, struct prefix *prefix,
exit(1);
}
+ /* Skip NULL or local Segment Routing Prefix */
if (!srp || srp->type == ISIS_SR_PREFIX_LOCAL)
return 0;
+ /* Install or unintall Prefix-SID if route is Active or not */
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
- isis_sr_prefix_reinstall(srp, true);
+ /*
+ * The Prefix-SID input label hasn't changed. We could use the
+ * "Make Before Break" option. Zebra layer will update output
+ * label by adding new label(s) before removing old one(s).
+ */
+ sr_prefix_reinstall(srp, true);
srp->u.remote.rinfo = route_info;
} else {
- isis_sr_prefix_uninstall(srp);
+ sr_prefix_uninstall(srp);
srp->u.remote.rinfo = NULL;
}
return 0;
}
-/*----------------------------------------------------------------------------*/
-
-/* Install or uninstall (LAN)-Adj-SID. */
-static void isis_sr_adj_sid_install_uninstall(bool install,
- const struct sr_adjacency *sra)
-{
- struct zapi_labels zl;
- struct zapi_nexthop *znh;
- int cmd;
-
- cmd = install ? ZEBRA_MPLS_LABELS_ADD : ZEBRA_MPLS_LABELS_DELETE;
-
- memset(&zl, 0, sizeof(zl));
- zl.type = ZEBRA_LSP_ISIS_SR;
- zl.local_label = sra->nexthop.label;
- zl.nexthop_num = 1;
- znh = &zl.nexthops[0];
- znh->gate = sra->nexthop.address;
- znh->type = (sra->nexthop.family == AF_INET)
- ? NEXTHOP_TYPE_IPV4_IFINDEX
- : NEXTHOP_TYPE_IPV6_IFINDEX;
- znh->ifindex = sra->adj->circuit->interface->ifindex;
- znh->label_num = 1;
- znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
-
- (void)zebra_send_mpls_labels(zclient, cmd, &zl);
-}
+/* --- Segment Routing Adjacency-SID management functions ------------------- */
-/* Add new local Adj-SID. */
-static void isis_sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
- bool backup)
+/**
+ * Add new local Adjacency-SID.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ * @param backup True to initialize backup Adjacency SID
+ */
+static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
+ bool backup)
{
struct isis_circuit *circuit = adj->circuit;
struct isis_area *area = circuit->area;
@@ -1002,8 +1261,12 @@ static void isis_sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
struct isis_lan_adj_sid *ladj_sid;
union g_addr nexthop = {};
uint8_t flags;
- mpls_label_t local_label;
+ mpls_label_t input_label;
+
+ sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area->area_tag,
+ backup ? "Backup" : "Primary");
+ /* Determine nexthop IP address */
switch (family) {
case AF_INET:
if (!circuit->ip_router)
@@ -1023,31 +1286,24 @@ static void isis_sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
exit(1);
}
+ /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
flags = EXT_SUBTLV_LINK_ADJ_SID_VFLG | EXT_SUBTLV_LINK_ADJ_SID_LFLG;
if (family == AF_INET6)
SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG);
if (backup)
SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG);
- local_label = isis_zebra_request_dynamic_label();
+ input_label = isis_zebra_request_dynamic_label();
if (circuit->ext == NULL)
circuit->ext = isis_alloc_ext_subtlvs();
- if (IS_DEBUG_ISIS(DEBUG_SR)) {
- char buf[INET6_ADDRSTRLEN];
-
- inet_ntop(family, &nexthop, buf, sizeof(buf));
- zlog_debug("ISIS-SR (%s) installing Adj-SID %s%%%s label %u",
- area->area_tag, buf, circuit->interface->name,
- local_label);
- }
-
sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
sra->nexthop.family = family;
sra->nexthop.address = nexthop;
- sra->nexthop.label = local_label;
+ sra->nexthop.label = input_label;
switch (circuit->circ_type) {
+ /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
case CIRCUIT_T_BROADCAST:
ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid));
ladj_sid->family = family;
@@ -1055,16 +1311,17 @@ static void isis_sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
ladj_sid->weight = 0;
memcpy(ladj_sid->neighbor_id, adj->sysid,
sizeof(ladj_sid->neighbor_id));
- ladj_sid->sid = local_label;
+ ladj_sid->sid = input_label;
isis_tlvs_add_lan_adj_sid(circuit->ext, ladj_sid);
sra->u.ladj_sid = ladj_sid;
break;
+ /* Adjacency-SID for Point to Point interface section #2.2.1 */
case CIRCUIT_T_P2P:
adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid));
adj_sid->family = family;
adj_sid->flags = flags;
adj_sid->weight = 0;
- adj_sid->sid = local_label;
+ adj_sid->sid = input_label;
isis_tlvs_add_adj_sid(circuit->ext, adj_sid);
sra->u.adj_sid = adj_sid;
break;
@@ -1073,36 +1330,42 @@ static void isis_sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
__func__, circuit->circ_type);
exit(1);
}
+
+ /* Add Adjacency-SID in SRDB */
sra->adj = adj;
listnode_add(area->srdb.adj_sids, sra);
listnode_add(adj->adj_sids, sra);
- isis_sr_adj_sid_install_uninstall(true, sra);
+ isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
}
-static void isis_sr_adj_sid_add(struct isis_adjacency *adj, int family)
+/**
+ * Add Primary and Backup local Adjacency SID.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ */
+static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
{
- isis_sr_adj_sid_add_single(adj, family, false);
- isis_sr_adj_sid_add_single(adj, family, true);
+ sr_adj_sid_add_single(adj, family, false);
+ sr_adj_sid_add_single(adj, family, true);
}
-/* Delete local Adj-SID. */
-static void isis_sr_adj_sid_del(struct sr_adjacency *sra)
+/**
+ * Delete local Adj-SID.
+ *
+ * @param sra Segment Routing Adjacency
+ */
+static void sr_adj_sid_del(struct sr_adjacency *sra)
{
struct isis_circuit *circuit = sra->adj->circuit;
struct isis_area *area = circuit->area;
- if (IS_DEBUG_ISIS(DEBUG_SR)) {
- char buf[INET6_ADDRSTRLEN];
+ sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area->area_tag);
- inet_ntop(sra->nexthop.family, &sra->nexthop.address, buf,
- sizeof(buf));
- zlog_debug("ISIS-SR (%s) uninstalling Adj-SID %s%%%s",
- area->area_tag, buf, circuit->interface->name);
- }
-
- isis_sr_adj_sid_install_uninstall(false, sra);
+ isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
+ /* Release dynamic label and remove subTLVs */
switch (circuit->circ_type) {
case CIRCUIT_T_BROADCAST:
isis_zebra_release_dynamic_label(sra->u.ladj_sid->sid);
@@ -1118,13 +1381,20 @@ static void isis_sr_adj_sid_del(struct sr_adjacency *sra)
exit(1);
}
+ /* Remove Adjacency-SID from the SRDB */
listnode_delete(area->srdb.adj_sids, sra);
listnode_delete(sra->adj->adj_sids, sra);
XFREE(MTYPE_ISIS_SR_INFO, sra);
}
-/* Remove all Adj-SIDs associated to an adjacency that is going down. */
-static int isis_sr_adj_state_change(struct isis_adjacency *adj)
+/**
+ * Remove all Adjacency-SIDs associated to an adjacency that is going down.
+ *
+ * @param adj IS-IS Adjacency
+ *
+ * @return 0
+ */
+static int sr_adj_state_change(struct isis_adjacency *adj)
{
struct sr_adjacency *sra;
struct listnode *node, *nnode;
@@ -1136,30 +1406,40 @@ static int isis_sr_adj_state_change(struct isis_adjacency *adj)
return 0;
for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
- isis_sr_adj_sid_del(sra);
+ sr_adj_sid_del(sra);
return 0;
}
-/*
- * Adjacency now has one or more IPv4/IPv6 addresses. Add new IPv4 or IPv6
- * Adj-SID accordingly.
+/**
+ * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
+ * IPv6 address to corresponding Adjacency-SID accordingly.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ *
+ * @return 0
*/
-static int isis_sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
+static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
{
if (!adj->circuit->area->srdb.enabled)
return 0;
- isis_sr_adj_sid_add(adj, family);
+ sr_adj_sid_add(adj, family);
return 0;
}
-/*
- * Adjacency doesn't have any IPv4 or IPv6 addresses anymore. Delete the
- * corresponding Adj-SID(s) accordingly.
+/**
+ * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
+ * delete the corresponding Adjacency-SID(s) accordingly.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ *
+ * @return 0
*/
-static int isis_sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
+static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
{
struct sr_adjacency *sra;
struct listnode *node, *nnode;
@@ -1169,18 +1449,26 @@ static int isis_sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
if (sra->nexthop.family == family)
- isis_sr_adj_sid_del(sra);
+ sr_adj_sid_del(sra);
return 0;
}
-static int isis_sr_if_new_hook(struct interface *ifp)
+/**
+ * Activate local Prefix-SID when loopback interface goes up for IS-IS.
+ *
+ * @param ifp Loopback Interface
+ *
+ * @return 0
+ */
+static int sr_if_new_hook(struct interface *ifp)
{
struct isis_circuit *circuit;
struct isis_area *area;
struct connected *connected;
struct listnode *node;
+ /* Get corresponding circuit */
circuit = circuit_scan_by_ifp(ifp);
if (!circuit)
return 0;
@@ -1201,7 +1489,7 @@ static int isis_sr_if_new_hook(struct interface *ifp)
if (!pcfg)
continue;
- if (isis_sr_prefix_is_node_sid(ifp, &pcfg->prefix)
+ if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)
&& !pcfg->node_sid) {
pcfg->node_sid = true;
lsp_regenerate_schedule(area, area->is_type, 0);
@@ -1211,58 +1499,113 @@ static int isis_sr_if_new_hook(struct interface *ifp)
return 0;
}
-/*----------------------------------------------------------------------------*/
+/* --- Segment Routing Show information functions --------------------------- */
-static void isis_sr_show_prefix_sid_local(struct vty *vty, struct ttable *tt,
- const struct isis_area *area,
- const struct sr_prefix *srp)
+/**
+ * Show LFIB operation in human readable format.
+ *
+ * @param buf Buffer to store string output. Must be pre-allocate
+ * @param size Size of the buffer
+ * @param label_in Input Label
+ * @param label_out Output Label
+ *
+ * @return String containing LFIB operation in human readable format
+ */
+static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
+ mpls_label_t label_out)
+{
+ if (size < 24)
+ return NULL;
+
+ if (label_in == MPLS_INVALID_LABEL) {
+ snprintf(buf, size, "no-op.");
+ return buf;
+ }
+
+ switch (label_out) {
+ case MPLS_LABEL_IMPLICIT_NULL:
+ snprintf(buf, size, "Pop(%u)", label_in);
+ break;
+ case MPLS_LABEL_IPV4_EXPLICIT_NULL:
+ case MPLS_LABEL_IPV6_EXPLICIT_NULL:
+ snprintf(buf, size, "Swap(%u, null)", label_in);
+ break;
+ case MPLS_INVALID_LABEL:
+ snprintf(buf, size, "no-op.");
+ break;
+ default:
+ snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
+ break;
+ }
+ return buf;
+}
+
+/**
+ * Show Local Prefix-SID.
+ *
+ * @param vty VTY output
+ * @param tt Table format
+ * @param area IS-IS area
+ * @param srp Segment Routing Prefix
+ */
+static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
+ const struct isis_area *area,
+ const struct sr_prefix *srp)
{
const struct sr_nexthop_info *srnh = &srp->u.local.info;
char buf_prefix[BUFSIZ];
- char buf_llabel[BUFSIZ];
- char buf_rlabel[BUFSIZ];
+ char buf_oper[BUFSIZ];
+ char buf_iface[BUFSIZ];
char buf_uptime[BUFSIZ];
- if (srp->local_label != MPLS_INVALID_LABEL)
- label2str(srp->local_label, buf_llabel, sizeof(buf_llabel));
- else
- snprintf(buf_llabel, sizeof(buf_llabel), "-");
if (srnh->label != MPLS_INVALID_LABEL) {
- label2str(srnh->label, buf_rlabel, sizeof(buf_rlabel));
+ struct interface *ifp;
+ ifp = if_lookup_prefix(&srp->prefix, VRF_DEFAULT);
+ if (ifp)
+ strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
+ else
+ snprintf(buf_iface, sizeof(buf_iface), "-");
log_uptime(srnh->uptime, buf_uptime, sizeof(buf_uptime));
} else {
- snprintf(buf_rlabel, sizeof(buf_rlabel), "-");
+ snprintf(buf_iface, sizeof(buf_iface), "-");
snprintf(buf_uptime, sizeof(buf_uptime), "-");
}
+ sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
+ MPLS_LABEL_IMPLICIT_NULL);
- ttable_add_row(tt, "%s|%u|%s|local|%s|%s",
+ ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
- srp->sid.value, buf_llabel, buf_rlabel, buf_uptime);
+ srp->sid.value, buf_oper, buf_iface, buf_uptime);
}
-static void isis_sr_show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
- const struct isis_area *area,
- const struct sr_prefix *srp)
+/**
+ * Show Remote Prefix-SID.
+ *
+ * @param vty VTY output
+ * @param tt Table format
+ * @param area IS-IS area
+ * @param srp Segment Routing Prefix
+ */
+static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
+ const struct isis_area *area,
+ const struct sr_prefix *srp)
{
struct isis_nexthop *nexthop;
struct listnode *node;
char buf_prefix[BUFSIZ];
- char buf_llabel[BUFSIZ];
+ char buf_oper[BUFSIZ];
char buf_nhop[BUFSIZ];
char buf_iface[BUFSIZ];
- char buf_rlabel[BUFSIZ];
char buf_uptime[BUFSIZ];
bool first = true;
(void)prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix));
- if (srp->local_label != MPLS_INVALID_LABEL)
- label2str(srp->local_label, buf_llabel, sizeof(buf_llabel));
- else
- snprintf(buf_llabel, sizeof(buf_llabel), "-");
if (!srp->u.remote.rinfo) {
ttable_add_row(tt, "%s|%u|%s|-|-|-", buf_prefix, srp->sid.value,
- buf_llabel);
+ sr_op2str(buf_oper, sizeof(buf_oper),
+ srp->input_label,
+ MPLS_LABEL_IMPLICIT_NULL));
return;
}
@@ -1278,54 +1621,58 @@ static void isis_sr_show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
else
snprintf(buf_iface, sizeof(buf_iface), "ifindex %u",
nexthop->ifindex);
- if (nexthop->sr.label == MPLS_INVALID_LABEL) {
- snprintf(buf_rlabel, sizeof(buf_rlabel), "-");
+ if (nexthop->sr.label == MPLS_INVALID_LABEL)
snprintf(buf_uptime, sizeof(buf_uptime), "-");
- } else {
- label2str(nexthop->sr.label, buf_rlabel,
- sizeof(buf_rlabel));
+ else
log_uptime(nexthop->sr.uptime, buf_uptime,
sizeof(buf_uptime));
- }
+ sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
+ nexthop->sr.label);
if (first)
- ttable_add_row(tt, "%s|%u|%s|%s, %s|%s|%s", buf_prefix,
- srp->sid.value, buf_llabel, buf_nhop,
- buf_iface, buf_rlabel, buf_uptime);
+ ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", buf_prefix,
+ srp->sid.value, buf_oper, buf_nhop,
+ buf_iface, buf_uptime);
else
- ttable_add_row(tt, "|||%s, %s|%s|%s", buf_nhop,
- buf_iface, buf_rlabel, buf_uptime);
+ ttable_add_row(tt, "|||%s|%s|%s|%s", buf_oper, buf_nhop,
+ buf_iface, buf_uptime);
first = false;
}
}
-static void isis_sr_show_prefix_sids(struct vty *vty, struct isis_area *area,
- int level)
+/**
+ * Show Prefix-SIDs.
+ *
+ * @param vty VTY output
+ * @param area IS-IS area
+ * @param level IS-IS level
+ */
+static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
{
struct sr_prefix *srp;
struct ttable *tt;
- if (tree_sr_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
+ if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
return;
vty_out(vty, " IS-IS %s Prefix-SIDs:\n\n", circuit_t2string(level));
/* Prepare table. */
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
- ttable_add_row(tt, "Prefix|SID|In Label|Nexthop|Out Label|Uptime");
+ ttable_add_row(tt, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
tt->style.cell.rpad = 2;
tt->style.corner = '+';
ttable_restyle(tt);
ttable_rowseps(tt, 0, BOTTOM, true, '-');
- frr_each (tree_sr_area_prefix, &area->srdb.prefix_sids[level - 1],
- srp) {
+ /* Process all Prefix-SID from the SRDB */
+ frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
switch (srp->type) {
case ISIS_SR_PREFIX_LOCAL:
- isis_sr_show_prefix_sid_local(vty, tt, area, srp);
+ show_prefix_sid_local(vty, tt, area, srp);
break;
case ISIS_SR_PREFIX_REMOTE:
- isis_sr_show_prefix_sid_remote(vty, tt, area, srp);
+ show_prefix_sid_remote(vty, tt, area, srp);
break;
}
}
@@ -1341,6 +1688,9 @@ static void isis_sr_show_prefix_sids(struct vty *vty, struct isis_area *area,
ttable_del(tt);
}
+/**
+ * Declaration of new show commands.
+ */
DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
"show isis segment-routing prefix-sids",
SHOW_STR PROTO_HELP
@@ -1355,15 +1705,89 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
area->area_tag ? area->area_tag : "null");
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
- isis_sr_show_prefix_sids(vty, area, level);
+ show_prefix_sids(vty, area, level);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/**
+ * Show Segment Routing Node.
+ *
+ * @param vty VTY output
+ * @param area IS-IS area
+ * @param level IS-IS level
+ */
+static void show_node(struct vty *vty, struct isis_area *area, int level)
+{
+ struct sr_node *srn;
+ struct ttable *tt;
+
+ if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
+ return;
+
+ vty_out(vty, " IS-IS %s SR-Node:\n\n", circuit_t2string(level));
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "System ID|SRGB|Algorithm|MSD");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+ /* Process all SR-Node from the SRDB */
+ frr_each (srdb_node, &area->srdb.sr_nodes[level - 1], srn) {
+ ttable_add_row(tt, "%s|%u - %u|%s|%u", sysid_print(srn->sysid),
+ srn->cap.srgb.lower_bound,
+ srn->cap.srgb.lower_bound
+ + srn->cap.srgb.range_size - 1,
+ srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF"
+ : "S-SPF",
+ srn->cap.msd);
+ }
+
+ /* Dump the generated table. */
+ if (tt->nrows > 1) {
+ char *table;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ }
+ ttable_del(tt);
+}
+
+DEFUN(show_sr_node, show_sr_node_cmd,
+ "show isis segment-routing node",
+ SHOW_STR PROTO_HELP
+ "Segment-Routing\n"
+ "Segment-Routing node\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ show_node(vty, area, level);
}
return CMD_SUCCESS;
}
-/*----------------------------------------------------------------------------*/
-/* Try to enable SR on the given IS-IS area. */
+/* --- IS-IS Segment Routing Management function ---------------------------- */
+
+/**
+ * Enable SR on the given IS-IS area.
+ *
+ * @param area IS-IS area
+ *
+ * @return 0 on success, -1 otherwise
+ */
int isis_sr_start(struct isis_area *area)
{
struct isis_sr_db *srdb = &area->srdb;
@@ -1380,11 +1804,10 @@ int isis_sr_start(struct isis_area *area)
- srdb->config.srgb_lower_bound + 1))
return -1;
- if (IS_DEBUG_ISIS(DEBUG_SR))
- zlog_debug("ISIS-SR (%s) Starting Segment Routing",
- area->area_tag);
+ sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
+ area->area_tag);
- /* Create Adj-SIDs for existing adjacencies. */
+ /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
struct isis_adjacency *adj;
struct listnode *anode;
@@ -1397,54 +1820,55 @@ int isis_sr_start(struct isis_area *area)
circuit->u.bc.adjdb[level - 1],
anode, adj)) {
if (adj->ipv4_address_count > 0)
- isis_sr_adj_sid_add(adj,
- AF_INET);
+ sr_adj_sid_add(adj, AF_INET);
if (adj->ipv6_address_count > 0)
- isis_sr_adj_sid_add(adj,
- AF_INET6);
+ sr_adj_sid_add(adj, AF_INET6);
}
}
break;
case CIRCUIT_T_P2P:
adj = circuit->u.p2p.neighbor;
if (adj && adj->ipv4_address_count > 0)
- isis_sr_adj_sid_add(adj, AF_INET);
+ sr_adj_sid_add(adj, AF_INET);
if (adj && adj->ipv6_address_count > 0)
- isis_sr_adj_sid_add(adj, AF_INET6);
+ sr_adj_sid_add(adj, AF_INET6);
break;
default:
break;
}
}
- /* Regenerate LSPs. */
+ /* Regenerate LSPs to advertise Segment Routing capabilities. */
lsp_regenerate_schedule(area, area->is_type, 0);
return 0;
}
-/* Disable SR on the given IS-IS area. */
+/**
+ * Disable SR on the given IS-IS area.
+ *
+ * @param area IS-IS area
+ */
void isis_sr_stop(struct isis_area *area)
{
struct isis_sr_db *srdb = &area->srdb;
struct sr_adjacency *sra;
struct listnode *node, *nnode;
- if (IS_DEBUG_ISIS(DEBUG_SR))
- zlog_debug("ISIS-SR (%s) Stopping Segment Routing",
- area->area_tag);
+ sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
+ area->area_tag);
- /* Uninstall Adj-SIDs. */
+ /* Uninstall all local Adjacency-SIDs. */
for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
- isis_sr_adj_sid_del(sra);
+ sr_adj_sid_del(sra);
- /* Uninstall Prefix-SIDs. */
+ /* Uninstall all Prefix-SIDs from all SR Node. */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
- while (tree_sr_node_count(&srdb->sr_nodes[level - 1]) > 0) {
+ while (srdb_node_count(&srdb->sr_nodes[level - 1]) > 0) {
struct sr_node *srn;
- srn = tree_sr_node_first(&srdb->sr_nodes[level - 1]);
- isis_sr_node_del(area, level, srn);
+ srn = srdb_node_first(&srdb->sr_nodes[level - 1]);
+ sr_node_del(area, level, srn);
}
}
@@ -1452,21 +1876,30 @@ void isis_sr_stop(struct isis_area *area)
isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
srdb->config.srgb_upper_bound);
- /* Regenerate LSPs. */
+ /* Regenerate LSPs to advertise that the Node is no more SR enable. */
lsp_regenerate_schedule(area, area->is_type, 0);
}
+/**
+ * IS-IS Segment Routing initialization for given area.
+ *
+ * @param area IS-IS area
+ */
void isis_sr_area_init(struct isis_area *area)
{
struct isis_sr_db *srdb = &area->srdb;
+ sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
+ area->area_tag);
+
+ /* Initialize Segment Routing Data Base */
memset(srdb, 0, sizeof(*srdb));
srdb->enabled = false;
srdb->adj_sids = list_new();
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
- tree_sr_node_init(&srdb->sr_nodes[level - 1]);
- tree_sr_area_prefix_init(&srdb->prefix_sids[level - 1]);
+ srdb_node_init(&srdb->sr_nodes[level - 1]);
+ srdb_area_prefix_init(&srdb->prefix_sids[level - 1]);
}
/* Pull defaults from the YANG module. */
@@ -1482,9 +1915,14 @@ void isis_sr_area_init(struct isis_area *area)
srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND;
#endif
srdb->config.msd = 0;
- tree_sr_prefix_cfg_init(&srdb->config.prefix_sids);
+ srdb_prefix_cfg_init(&srdb->config.prefix_sids);
}
+/**
+ * Terminate IS-IS Segment Routing for the given area.
+ *
+ * @param area IS-IS area
+ */
void isis_sr_area_term(struct isis_area *area)
{
struct isis_sr_db *srdb = &area->srdb;
@@ -1494,32 +1932,39 @@ void isis_sr_area_term(struct isis_area *area)
isis_sr_stop(area);
/* Clear Prefix-SID configuration. */
- while (tree_sr_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
+ while (srdb_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
struct sr_prefix_cfg *pcfg;
- pcfg = tree_sr_prefix_cfg_first(&srdb->config.prefix_sids);
+ pcfg = srdb_prefix_cfg_first(&srdb->config.prefix_sids);
isis_sr_cfg_prefix_del(pcfg);
}
}
+/**
+ * IS-IS Segment Routing global initialization.
+ */
void isis_sr_init(void)
{
install_element(VIEW_NODE, &show_sr_prefix_sids_cmd);
+ install_element(VIEW_NODE, &show_sr_node_cmd);
/* Register hooks. */
- hook_register(isis_adj_state_change_hook, isis_sr_adj_state_change);
- hook_register(isis_adj_ip_enabled_hook, isis_sr_adj_ip_enabled);
- hook_register(isis_adj_ip_disabled_hook, isis_sr_adj_ip_disabled);
- hook_register(isis_route_update_hook, isis_sr_route_update);
- hook_register(isis_if_new_hook, isis_sr_if_new_hook);
+ hook_register(isis_adj_state_change_hook, sr_adj_state_change);
+ hook_register(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
+ hook_register(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
+ hook_register(isis_route_update_hook, sr_route_update);
+ hook_register(isis_if_new_hook, sr_if_new_hook);
}
+/**
+ * IS-IS Segment Routing global terminate.
+ */
void isis_sr_term(void)
{
/* Unregister hooks. */
- hook_unregister(isis_adj_state_change_hook, isis_sr_adj_state_change);
- hook_unregister(isis_adj_ip_enabled_hook, isis_sr_adj_ip_enabled);
- hook_unregister(isis_adj_ip_disabled_hook, isis_sr_adj_ip_disabled);
- hook_unregister(isis_route_update_hook, isis_sr_route_update);
- hook_unregister(isis_if_new_hook, isis_sr_if_new_hook);
+ hook_unregister(isis_adj_state_change_hook, sr_adj_state_change);
+ hook_unregister(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
+ hook_unregister(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
+ hook_unregister(isis_route_update_hook, sr_route_update);
+ hook_unregister(isis_if_new_hook, sr_if_new_hook);
}
diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h
index 286ebeb953..dec329ab48 100644
--- a/isisd/isis_sr.h
+++ b/isisd/isis_sr.h
@@ -1,8 +1,7 @@
/*
- * This is an implementation of Segment Routing for IS-IS
- * as per draft draft-ietf-isis-segment-routing-extensions-25
+ * This is an implementation of Segment Routing for IS-IS as per RFC 8667
*
- * Copyright (C) 2019 Orange Labs http://www.orange.com
+ * Copyright (C) 2019 Orange http://www.orange.com
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
@@ -55,30 +54,31 @@
#define SRGB_LOWER_BOUND 16000
#define SRGB_UPPER_BOUND 23999
-PREDECL_RBTREE_UNIQ(tree_sr_node)
-PREDECL_RBTREE_UNIQ(tree_sr_node_prefix)
-PREDECL_RBTREE_UNIQ(tree_sr_area_prefix)
-PREDECL_RBTREE_UNIQ(tree_sr_prefix_cfg)
+/* Segment Routing Data Base (SRDB) RB-Tree structure */
+PREDECL_RBTREE_UNIQ(srdb_node)
+PREDECL_RBTREE_UNIQ(srdb_node_prefix)
+PREDECL_RBTREE_UNIQ(srdb_area_prefix)
+PREDECL_RBTREE_UNIQ(srdb_prefix_cfg)
-/* SR Adj-SID type. */
+/* Segment Routing Adjacency-SID type. */
enum sr_adj_type {
ISIS_SR_ADJ_NORMAL = 0,
ISIS_SR_LAN_BACKUP,
};
-/* SR Adjacency. */
+/* Segment Routing Adjacency. */
struct sr_adjacency {
/* Adjacency type. */
enum sr_adj_type type;
- /* Adj-SID nexthop information. */
+ /* Adjacency-SID nexthop information. */
struct {
int family;
union g_addr address;
mpls_label_t label;
} nexthop;
- /* (LAN-)Adj-SID Sub-TLV. */
+ /* (LAN-)Adjacency-SID Sub-TLV. */
union {
struct isis_adj_sid *adj_sid;
struct isis_lan_adj_sid *ladj_sid;
@@ -88,32 +88,40 @@ struct sr_adjacency {
struct isis_adjacency *adj;
};
-/* SR Prefix-SID type. */
+/* Segment Routing Prefix-SID type. */
enum sr_prefix_type {
ISIS_SR_PREFIX_LOCAL = 0,
ISIS_SR_PREFIX_REMOTE,
};
-/* SR Nexthop Information. */
+/* Segment Routing Nexthop Information. */
struct sr_nexthop_info {
mpls_label_t label;
time_t uptime;
};
-/* SR Prefix-SID. */
+/* State of Object (SR-Node and SR-Prefix) stored in SRDB */
+enum srdb_state {
+ SRDB_STATE_VALIDATED = 0,
+ SRDB_STATE_NEW,
+ SRDB_STATE_MODIFIED,
+ SRDB_STATE_UNCHANGED
+};
+
+/* Segment Routing Prefix-SID. */
struct sr_prefix {
- /* RB-tree entries. */
- struct tree_sr_node_prefix_item node_entry;
- struct tree_sr_area_prefix_item area_entry;
+ /* SRDB RB-tree entries. */
+ struct srdb_node_prefix_item node_entry;
+ struct srdb_area_prefix_item area_entry;
/* IP prefix. */
struct prefix prefix;
- /* SID value, algorithm and flags. */
+ /* SID value, algorithm and flags subTLVs. */
struct isis_prefix_sid sid;
- /* Local label value. */
- mpls_label_t local_label;
+ /* Input label value. */
+ mpls_label_t input_label;
/* Prefix-SID type. */
enum sr_prefix_type type;
@@ -128,20 +136,17 @@ struct sr_prefix {
} remote;
} u;
- /* Backpointer to SR node. */
+ /* Backpointer to Segment Routing node. */
struct sr_node *srn;
- /* Flags used while the LSPDB is being parsed. */
- uint8_t parse_flags;
-#define F_ISIS_SR_PREFIX_SID_NEW 0x01
-#define F_ISIS_SR_PREFIX_SID_MODIFIED 0x02
-#define F_ISIS_SR_PREFIX_SID_UNCHANGED 0x04
+ /* SR-Prefix State used while the LSPDB is being parsed. */
+ enum srdb_state state;
};
-/* SR node. */
+/* Segment Routing node. */
struct sr_node {
- /* RB-tree entry. */
- struct tree_sr_node_item entry;
+ /* SRDB RB-tree entry. */
+ struct srdb_node_item entry;
/* IS-IS level: ISIS_LEVEL1 or ISIS_LEVEL2. */
int level;
@@ -149,39 +154,38 @@ struct sr_node {
/* IS-IS node identifier. */
uint8_t sysid[ISIS_SYS_ID_LEN];
- /* IS-IS node capabilities (SRGB, SR Algorithms, etc). */
+ /* Segment Routing node capabilities (SRGB, SR Algorithms) subTLVs. */
struct isis_router_cap cap;
/* List of Prefix-SIDs advertised by this node. */
- struct tree_sr_node_prefix_head prefix_sids;
+ struct srdb_node_prefix_head prefix_sids;
/* Backpointer to IS-IS area. */
struct isis_area *area;
- /* Flags used while the LSPDB is being parsed. */
- uint8_t parse_flags;
-#define F_ISIS_SR_NODE_NEW 0x01
-#define F_ISIS_SR_NODE_MODIFIED 0x02
-#define F_ISIS_SR_NODE_UNCHANGED 0x04
+ /* SR-Node State used while the LSPDB is being parsed. */
+ enum srdb_state state;
};
-/* NOTE: these values must be in sync with the YANG module. */
+/* SID type. NOTE: these values must be in sync with the YANG module. */
enum sr_sid_value_type {
SR_SID_VALUE_TYPE_INDEX = 0,
SR_SID_VALUE_TYPE_ABSOLUTE = 1,
};
-/* NOTE: these values must be in sync with the YANG module. */
+#define IS_SID_VALUE(flag) CHECK_FLAG(flag, ISIS_PREFIX_SID_VALUE)
+
+/* Last Hop Behavior. NOTE: these values must be in sync with the YANG module */
enum sr_last_hop_behavior {
SR_LAST_HOP_BEHAVIOR_EXP_NULL = 0,
SR_LAST_HOP_BEHAVIOR_NO_PHP = 1,
SR_LAST_HOP_BEHAVIOR_PHP = 2,
};
-/* SR Prefix-SID configuration. */
+/* Segment Routing Prefix-SID configuration. */
struct sr_prefix_cfg {
- /* RB-tree entry. */
- struct tree_sr_prefix_cfg_item entry;
+ /* SRDB RB-tree entry. */
+ struct srdb_prefix_cfg_item entry;
/* IP prefix. */
struct prefix prefix;
@@ -202,21 +206,21 @@ struct sr_prefix_cfg {
struct isis_area *area;
};
-/* Per-area IS-IS Segment Routing information. */
+/* Per-area IS-IS Segment Routing Data Base (SRDB). */
struct isis_sr_db {
- /* Operational status of Segment Routing. */
+ /* Global Operational status of Segment Routing. */
bool enabled;
- /* Adj-SIDs. */
+ /* List of local Adjacency-SIDs. */
struct list *adj_sids;
- /* SR information from all nodes. */
- struct tree_sr_node_head sr_nodes[ISIS_LEVELS];
+ /* Segment Routing Node information per IS-IS level. */
+ struct srdb_node_head sr_nodes[ISIS_LEVELS];
- /* Prefix-SIDs. */
- struct tree_sr_area_prefix_head prefix_sids[ISIS_LEVELS];
+ /* Segment Routing Prefix-SIDs per IS-IS level. */
+ struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS];
- /* Area SR configuration. */
+ /* Area Segment Routing configuration. */
struct {
/* Administrative status of Segment Routing. */
bool enabled;
@@ -229,14 +233,13 @@ struct isis_sr_db {
uint8_t msd;
/* Prefix-SID mappings. */
- struct tree_sr_prefix_cfg_head prefix_sids;
+ struct srdb_prefix_cfg_head prefix_sids;
} config;
};
/* Prototypes. */
extern int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
uint32_t upper_bound);
-extern void isis_sr_cfg_msd_update(struct isis_area *area);
extern struct sr_prefix_cfg *
isis_sr_cfg_prefix_add(struct isis_area *area, const struct prefix *prefix);
extern void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg);
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index be88ee85a6..923956fa6d 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -284,7 +284,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
sbuf_push(buf, indent,
"Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
exts->use_bw);
- /* Segment Routing Adjacency */
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
struct isis_adj_sid *adj;
@@ -315,6 +315,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
: '0');
}
}
+ /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
@@ -476,6 +477,7 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, exts->use_bw);
}
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
struct isis_adj_sid *adj;
@@ -495,6 +497,7 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
}
}
+ /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
@@ -721,7 +724,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
SET_SUBTLV(exts, EXT_USE_BW);
}
break;
- /* Segment Routing Adjacency */
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
case ISIS_SUBTLV_ADJ_SID:
if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
&& subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
@@ -749,6 +752,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
SET_SUBTLV(exts, EXT_ADJ_SID);
}
break;
+ /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
case ISIS_SUBTLV_LAN_ADJ_SID:
if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
&& subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
@@ -789,7 +793,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
return 0;
}
-/* Functions for Sub-TLV 3 SR Prefix-SID */
+/* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
@@ -2585,7 +2589,7 @@ out:
return 1;
}
-/* Functions related to TLV 242 Router Capability */
+/* Functions related to TLV 242 Router Capability as per RFC7981 */
static struct isis_router_cap *copy_tlv_router_cap(
const struct isis_router_cap *router_cap)
{
@@ -2614,7 +2618,7 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
- /* SR Global Block */
+ /* Segment Routing Global Block as per RFC8667 section #3.1 */
if (router_cap->srgb.range_size != 0)
sbuf_push(buf, indent,
" Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n",
@@ -2623,7 +2627,7 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
router_cap->srgb.lower_bound,
router_cap->srgb.range_size);
- /* SR Algorithms */
+ /* Segment Routing Algorithms as per RFC8667 section #3.2 */
if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
sbuf_push(buf, indent, " Algorithm: %s",
router_cap->algo[0] == 0 ? "0: SPF"
@@ -2637,7 +2641,7 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
sbuf_push(buf, indent, "\n");
}
- /* SR Node MSSD */
+ /* Segment Routing Node MSD as per RFC8491 section #2 */
if (router_cap->msd != 0)
sbuf_push(buf, indent, " Node MSD: %d\n", router_cap->msd);
}
@@ -2674,7 +2678,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
stream_put_ipv4(s, router_cap->router_id.s_addr);
stream_putc(s, router_cap->flags);
- /* Add SRGB if set */
+ /* Add SRGB if set as per RFC8667 section #3.1 */
if ((router_cap->srgb.range_size != 0)
&& (router_cap->srgb.lower_bound != 0)) {
stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
@@ -2685,7 +2689,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
stream_put3(s, router_cap->srgb.lower_bound);
- /* Then SR Algorithm if set */
+ /* Then SR Algorithm if set as per RFC8667 section #3.2 */
for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
break;
@@ -2695,7 +2699,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
for (int i = 0; i < nb_algo; i++)
stream_putc(s, router_cap->algo[i]);
}
- /* And finish with MSD if set */
+ /* And finish with MSD if set as per RFC8491 section #2 */
if (router_cap->msd != 0) {
stream_putc(s, ISIS_SUBTLV_NODE_MSD);
stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
@@ -4602,6 +4606,7 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
}
+/* Add IS-IS SR Adjacency-SID subTLVs */
void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_adj_sid *adj)
{
@@ -4609,6 +4614,7 @@ void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
SET_SUBTLV(exts, EXT_ADJ_SID);
}
+/* Delete IS-IS SR Adjacency-SID subTLVs */
void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_adj_sid *adj)
{
@@ -4618,6 +4624,7 @@ void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
UNSET_SUBTLV(exts, EXT_ADJ_SID);
}
+/* Add IS-IS SR LAN-Adjacency-SID subTLVs */
void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_lan_adj_sid *lan)
{
@@ -4625,6 +4632,7 @@ void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
}
+/* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_lan_adj_sid *lan)
{
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index c3b25669b6..f468d85bbd 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -135,10 +135,7 @@ struct isis_threeway_adj {
uint32_t neighbor_circuit_id;
};
-/*
- * Segment Routing subTLV's as per
- * draft-ietf-isis-segment-routing-extension-25
- */
+/* Segment Routing subTLV's as per RFC8667 */
#define ISIS_SUBTLV_SRGB_FLAG_I 0x80
#define ISIS_SUBTLV_SRGB_FLAG_V 0x40
#define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I)
@@ -216,7 +213,7 @@ struct isis_router_cap {
struct in_addr router_id;
uint8_t flags;
- /* draft-ietf-segment-routing-extensions-25 */
+ /* RFC 8667 section #3 */
struct isis_srgb srgb;
uint8_t algo[SR_ALGORITHM_COUNT];
/* RFC 8491 */
@@ -344,7 +341,7 @@ struct isis_subtlvs {
/* draft-baker-ipv6-isis-dst-src-routing-06 */
struct prefix_ipv6 *source_prefix;
- /* draft-ietf-isis-segment-routing-extensions-25 */
+ /* RFC 8667 section #2.4 */
struct isis_item_list prefix_sids;
};
@@ -394,15 +391,17 @@ enum isis_tlv_type {
/* RFC 5307 */
ISIS_SUBTLV_LLRI = 4,
+ /* RFC 8491 */
+ ISIS_SUBTLV_NODE_MSD = 23,
+
/* RFC 5316 */
ISIS_SUBTLV_RAS = 24,
ISIS_SUBTLV_RIP = 25,
- /* draft-isis-segment-routing-extension-25 */
+ /* RFC 8667 section #2 */
ISIS_SUBTLV_SID_LABEL = 1,
ISIS_SUBTLV_SID_LABEL_RANGE = 2,
ISIS_SUBTLV_ALGORITHM = 19,
- ISIS_SUBTLV_NODE_MSD = 23,
ISIS_SUBTLV_PREFIX_SID = 3,
ISIS_SUBTLV_ADJ_SID = 31,
ISIS_SUBTLV_LAN_ADJ_SID = 32,
@@ -421,21 +420,26 @@ enum isis_tlv_type {
/* subTLVs size for TE and SR */
enum ext_subtlv_size {
+ /* RFC 5307 */
ISIS_SUBTLV_LLRI_SIZE = 8,
+ /* RFC 5305 & RFC 6119 */
ISIS_SUBTLV_UNRSV_BW_SIZE = 32,
ISIS_SUBTLV_TE_METRIC_SIZE = 3,
ISIS_SUBTLV_IPV6_ADDR_SIZE = 16,
- /* draft-isis-segment-routing-extension-25 */
+ /* RFC 8491 */
+ ISIS_SUBTLV_NODE_MSD_SIZE = 2,
+
+ /* RFC 8667 section #2 */
ISIS_SUBTLV_SID_LABEL_SIZE = 3,
ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9,
ISIS_SUBTLV_ALGORITHM_SIZE = 4,
- ISIS_SUBTLV_NODE_MSD_SIZE = 2,
ISIS_SUBTLV_ADJ_SID_SIZE = 5,
ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11,
ISIS_SUBTLV_PREFIX_SID_SIZE = 5,
+ /* RFC 7810 */
ISIS_SUBTLV_MM_DELAY_SIZE = 8,
ISIS_SUBTLV_HDR_SIZE = 2,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index d4b9d2a621..e0bf0cee14 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -49,6 +49,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
+#include "isisd/isis_adjacency.h"
#include "isisd/isis_te.h"
#include "isisd/isis_sr.h"
@@ -253,8 +254,12 @@ void isis_zebra_route_del_route(struct prefix *prefix,
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
-/* Install Prefix-SID in the forwarding plane. */
-void isis_zebra_install_prefix_sid(const struct sr_prefix *srp)
+/**
+ * Install Prefix-SID in the forwarding plane through Zebra.
+ *
+ * @param srp Segment Routing Prefix-SID
+ */
+static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
{
struct zapi_labels zl;
struct zapi_nexthop *znh;
@@ -265,7 +270,7 @@ void isis_zebra_install_prefix_sid(const struct sr_prefix *srp)
/* Prepare message. */
memset(&zl, 0, sizeof(zl));
zl.type = ZEBRA_LSP_ISIS_SR;
- zl.local_label = srp->local_label;
+ zl.local_label = srp->input_label;
switch (srp->type) {
case ISIS_SR_PREFIX_LOCAL:
@@ -314,15 +319,19 @@ void isis_zebra_install_prefix_sid(const struct sr_prefix *srp)
(void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
}
-/* Uninstall Prefix-SID from the forwarding plane. */
-void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
+/**
+ * Uninstall Prefix-SID from the forwarding plane through Zebra.
+ *
+ * @param srp Segment Routing Prefix-SID
+ */
+static void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
{
struct zapi_labels zl;
/* Prepare message. */
memset(&zl, 0, sizeof(zl));
zl.type = ZEBRA_LSP_ISIS_SR;
- zl.local_label = srp->local_label;
+ zl.local_label = srp->input_label;
if (srp->type == ISIS_SR_PREFIX_REMOTE) {
/* Update route in the RIB too. */
@@ -336,6 +345,69 @@ void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
(void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
}
+/**
+ * Send Prefix-SID to ZEBRA for installation or deletion.
+ *
+ * @param cmd ZEBRA_MPLS_LABELS_REPLACE or ZEBRA_ROUTE_DELETE
+ * @param srp Segment Routing Prefix-SID
+ */
+void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
+{
+
+ if (cmd != ZEBRA_MPLS_LABELS_REPLACE
+ && cmd != ZEBRA_MPLS_LABELS_DELETE) {
+ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
+ __func__);
+ return;
+ }
+
+ sr_debug(" |- %s label %u for prefix %pFX",
+ cmd == ZEBRA_MPLS_LABELS_REPLACE ? "Update" : "Delete",
+ srp->input_label, &srp->prefix);
+
+ if (cmd == ZEBRA_MPLS_LABELS_REPLACE)
+ isis_zebra_prefix_install_prefix_sid(srp);
+ else
+ isis_zebra_uninstall_prefix_sid(srp);
+}
+
+/**
+ * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
+ *
+ * @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
+ * @param sra Segment Routing Adjacency-SID
+ */
+void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
+{
+ struct zapi_labels zl;
+ struct zapi_nexthop *znh;
+
+ if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
+ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
+ __func__);
+ return;
+ }
+
+ sr_debug(" |- %s label %u for interface %s",
+ cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
+ sra->nexthop.label, sra->adj->circuit->interface->name);
+
+ memset(&zl, 0, sizeof(zl));
+ zl.type = ZEBRA_LSP_ISIS_SR;
+ zl.local_label = sra->nexthop.label;
+ zl.nexthop_num = 1;
+ znh = &zl.nexthops[0];
+ znh->gate = sra->nexthop.address;
+ znh->type = (sra->nexthop.family == AF_INET)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ znh->ifindex = sra->adj->circuit->interface->ifindex;
+ znh->label_num = 1;
+ znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
+
+ (void)zebra_send_mpls_labels(zclient, cmd, &zl);
+}
+
static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
{
struct zapi_route api;
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index cca2b08811..b143d34626 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -36,6 +36,7 @@ void isis_zebra_stop(void);
struct isis_route_info;
struct sr_prefix;
+struct sr_adjacency;
void isis_zebra_route_add_route(struct prefix *prefix,
struct prefix_ipv6 *src_p,
@@ -43,8 +44,8 @@ void isis_zebra_route_add_route(struct prefix *prefix,
void isis_zebra_route_del_route(struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info);
-void isis_zebra_install_prefix_sid(const struct sr_prefix *srp);
-void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp);
+void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp);
+void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
int isis_distribute_list_update(int routetype);
void isis_zebra_redistribute_set(afi_t afi, int type);
void isis_zebra_redistribute_unset(afi_t afi, int type);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 56ea0993fd..439428d797 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -254,6 +254,12 @@ extern struct thread_master *master;
zlog_debug(__VA_ARGS__); \
} while (0)
+#define sr_debug(...) \
+ do { \
+ if (IS_DEBUG_ISIS(DEBUG_SR)) \
+ zlog_debug(__VA_ARGS__); \
+ } while (0)
+
#define DEBUG_TE DEBUG_LSP_GEN
#define IS_DEBUG_ISIS(x) (isis->debugs & x)