]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: refactor handling of SR Prefix-SIDs
authorRenato Westphal <renato@opensourcerouting.org>
Sun, 20 Sep 2020 05:39:28 +0000 (02:39 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Fri, 23 Oct 2020 13:31:39 +0000 (10:31 -0300)
Embed Prefix-SID information inside SPF data structures so that
Prefix-SIDs can be installed together with their associated routes
at the end of the SPF algorithm. This is different from the current
implementation where Prefix-SIDs are parsed and processed separately,
which is vastly suboptimal.

Advantages of the new code:
* No need to parse the LSPDB an additional time to detect and process
  SR-related changes;
* Routes are installed with their Prefix-SID labels in the same ZAPI
  message. This can prevent packet dropping for a few milliseconds
  after each SPF run if there are BGP-labeled routes (e.g. L3VPN) that
  recurse on IGP labeled routes;
* Much easier to support Anycast-SIDs, as the SPF code will naturally
  figure out the best nexthops and use only them (that can't be done
  in any reasonable way if the Prefix-SID Sub-TVLs are processed
  separately);
* Less code to maintain and reduced memory footprint;

The "show isis segment-routing prefix-sids" command was removed as
it doesn't make sense anymore now that "show isis route" exists.
Prefix-SIDs are a property of routes, so what was done was to extend
the "show isis route" command with a new "prefix-sid" option that
changes the output table to show the Prefix-SID information associated
to each route.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
15 files changed:
doc/user/isisd.rst
isisd/isis_lfa.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_spf_private.h
isisd/isis_sr.c
isisd/isis_sr.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
tests/isisd/test_isis_spf.c
tests/isisd/test_isis_spf.refout

index df7c72f8dcb605524158d8a1051697ade3ddb156..d71f4246fd359148604162ed8029738a0a353aac 100644 (file)
@@ -423,8 +423,8 @@ Showing ISIS information
    Show topology IS-IS paths to Intermediate Systems, globally, in area
    (level-1) or domain (level-2).
 
-.. index:: show isis route [level-1|level-2] [backup]
-.. clicmd:: show isis route [level-1|level-2] [backup]
+.. index:: show isis route [level-1|level-2] [prefix-sid|backup]
+.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup]
 
    Show the ISIS routing table, as determined by the most recent SPF
    calculation.
index f3d4091f3ea6bc5660c28ae55068f0fbc42efc76..52af1da81ab84984abaf5676a1d513b5e5909ae8 100644 (file)
@@ -180,23 +180,6 @@ bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
        return false;
 }
 
-/* Find SRGB associated to a System ID. */
-static struct isis_sr_block *tilfa_find_srgb(struct lspdb_head *lspdb,
-                                            const uint8_t *sysid)
-{
-       struct isis_lsp *lsp;
-
-       lsp = isis_root_system_lsp(lspdb, sysid);
-       if (!lsp)
-               return NULL;
-
-       if (!lsp->tlvs->router_cap
-           || lsp->tlvs->router_cap->srgb.range_size == 0)
-               return NULL;
-
-       return &lsp->tlvs->router_cap->srgb;
-}
-
 struct tilfa_find_pnode_prefix_sid_args {
        uint32_t sid_index;
 };
@@ -313,7 +296,7 @@ tilfa_compute_label_stack(struct lspdb_head *lspdb,
 
                switch (sid->type) {
                case TILFA_SID_PREFIX:
-                       srgb = tilfa_find_srgb(lspdb, sadj->id);
+                       srgb = isis_sr_find_srgb(lspdb, sadj->id);
                        if (!srgb) {
                                zlog_warn("%s: SRGB not found for node %s",
                                          __func__,
@@ -704,7 +687,7 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
                struct route_table *route_table;
 
                route_table = spftree_pc->lfa.old.spftree->route_table_backup;
-               if (route_node_lookup(route_table, &vertex->N.ip.dest)) {
+               if (route_node_lookup(route_table, &vertex->N.ip.p.dest)) {
                        if (IS_DEBUG_TILFA)
                                zlog_debug(
                                        "ISIS-TI-LFA: %s %s already covered by node protection",
index 7e8c877bd024721dc6620d76c5082b212a989de9..d664a6f8962545c55eb25ed384b57d8137140c44 100644 (file)
@@ -71,7 +71,6 @@ static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
        nexthop->family = family;
        nexthop->ifindex = ifindex;
        nexthop->ip = *ip;
-       isis_sr_nexthop_reset(&nexthop->sr);
 
        return nexthop;
 }
@@ -117,7 +116,7 @@ static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
 }
 
 void adjinfo2nexthop(int family, struct list *nexthops,
-                    struct isis_adjacency *adj,
+                    struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
                     struct mpls_label_stack *label_stack)
 {
        struct isis_nexthop *nh;
@@ -134,6 +133,8 @@ void adjinfo2nexthop(int family, struct list *nexthops,
                                        AF_INET, &ip,
                                        adj->circuit->interface->ifindex);
                                memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
+                               if (sr)
+                                       nh->sr = *sr;
                                nh->label_stack = label_stack;
                                listnode_add(nexthops, nh);
                                break;
@@ -150,6 +151,8 @@ void adjinfo2nexthop(int family, struct list *nexthops,
                                        AF_INET6, &ip,
                                        adj->circuit->interface->ifindex);
                                memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
+                               if (sr)
+                                       nh->sr = *sr;
                                nh->label_stack = label_stack;
                                listnode_add(nexthops, nh);
                                break;
@@ -165,22 +168,22 @@ void adjinfo2nexthop(int family, struct list *nexthops,
 
 static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
                                          const uint8_t *sysid,
+                                         struct isis_sr_psid_info *sr,
                                          struct mpls_label_stack *label_stack)
 {
        struct isis_nexthop *nh;
 
        nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
        memcpy(nh->sysid, sysid, sizeof(nh->sysid));
-       isis_sr_nexthop_reset(&nh->sr);
+       nh->sr = *sr;
        nh->label_stack = label_stack;
        listnode_add(rinfo->nexthops, nh);
 }
 
-static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
-                                                  struct prefix_ipv6 *src_p,
-                                                  uint32_t cost,
-                                                  uint32_t depth,
-                                                  struct list *adjacencies)
+static struct isis_route_info *
+isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
+                   uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
+                   struct list *adjacencies)
 {
        struct isis_route_info *rinfo;
        struct isis_vertex_adj *vadj;
@@ -192,6 +195,7 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
        for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
                struct isis_spf_adj *sadj = vadj->sadj;
                struct isis_adjacency *adj = sadj->adj;
+               struct isis_sr_psid_info *sr = &vadj->sr;
                struct mpls_label_stack *label_stack = vadj->label_stack;
 
                /*
@@ -199,7 +203,7 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
                 * environment.
                 */
                if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
-                       isis_route_add_dummy_nexthops(rinfo, sadj->id,
+                       isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
                                                      label_stack);
                        continue;
                }
@@ -227,12 +231,13 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
                                 prefix->family);
                        exit(1);
                }
-               adjinfo2nexthop(prefix->family, rinfo->nexthops, adj,
+               adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
                                label_stack);
        }
 
        rinfo->cost = cost;
        rinfo->depth = depth;
+       rinfo->sr = *sr;
 
        return rinfo;
 }
@@ -254,12 +259,28 @@ void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
                isis_route_info_delete(node->info);
 }
 
+static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
+                                  struct isis_sr_psid_info *old)
+{
+       if (new->present != old->present)
+               return false;
+
+       if (new->label != old->label)
+               return false;
+
+       if (new->sid.flags != old->sid.flags
+           || new->sid.value != old->sid.value)
+               return false;
+
+       return true;
+}
+
 static int isis_route_info_same(struct isis_route_info *new,
                                struct isis_route_info *old, char *buf,
                                size_t buf_size)
 {
        struct listnode *node;
-       struct isis_nexthop *nexthop;
+       struct isis_nexthop *new_nh, *old_nh;
 
        if (new->cost != old->cost) {
                if (buf)
@@ -275,6 +296,12 @@ static int isis_route_info_same(struct isis_route_info *new,
                return 0;
        }
 
+       if (!isis_sr_psid_info_same(&new->sr, &old->sr)) {
+               if (buf)
+                       snprintf(buf, buf_size, "SR input label");
+               return 0;
+       }
+
        if (new->nexthops->count != old->nexthops->count) {
                if (buf)
                        snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
@@ -282,14 +309,20 @@ static int isis_route_info_same(struct isis_route_info *new,
                return 0;
        }
 
-       for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop)) {
-               if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
-                                  nexthop->ifindex)) {
+       for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
+               old_nh = nexthoplookup(old->nexthops, new_nh->family,
+                                      &new_nh->ip, new_nh->ifindex);
+               if (!old_nh) {
                        if (buf)
                                snprintf(buf, buf_size,
                                         "new nhop"); /* TODO: print nhop */
                        return 0;
                }
+               if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
+                       if (buf)
+                               snprintf(buf, buf_size, "nhop SR label");
+                       return 0;
+               }
        }
 
        /* only the resync flag needs to be checked */
@@ -303,13 +336,11 @@ static int isis_route_info_same(struct isis_route_info *new,
        return 1;
 }
 
-struct isis_route_info *isis_route_create(struct prefix *prefix,
-                                         struct prefix_ipv6 *src_p,
-                                         uint32_t cost,
-                                         uint32_t depth,
-                                         struct list *adjacencies,
-                                         struct isis_area *area,
-                                         struct route_table *table)
+struct isis_route_info *
+isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
+                 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
+                 struct list *adjacencies, struct isis_area *area,
+                 struct route_table *table)
 {
        struct route_node *route_node;
        struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
@@ -318,8 +349,8 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
        if (!table)
                return NULL;
 
-       rinfo_new = isis_route_info_new(prefix, src_p, cost,
-                                       depth, adjacencies);
+       rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
+                                       adjacencies);
        route_node = srcdest_rnode_get(table, prefix, src_p);
 
        rinfo_old = route_node->info;
@@ -351,6 +382,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
                                zlog_debug(
                                        "ISIS-Rte (%s): route changed: %pFX, change: %s",
                                        area->area_tag, prefix, change_buf);
+                       rinfo_new->sr_previous = rinfo_old->sr;
                        isis_route_info_delete(rinfo_old);
                        route_info = rinfo_new;
                        UNSET_FLAG(route_info->flag,
@@ -406,7 +438,25 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
                if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
                        return;
 
-               isis_zebra_route_add_route(area->isis, prefix, src_p, route_info);
+               /*
+                * Explicitly uninstall previous Prefix-SID label if it has
+                * changed or was removed.
+                */
+               if (route_info->sr_previous.present
+                   && (!route_info->sr.present
+                       || route_info->sr_previous.label
+                                  != route_info->sr.label))
+                       isis_zebra_prefix_sid_uninstall(
+                               area, prefix, route_info,
+                               &route_info->sr_previous);
+
+               /* Install route. */
+               isis_zebra_route_add_route(area->isis, prefix, src_p,
+                                          route_info);
+               /* Install/reinstall Prefix-SID label. */
+               if (route_info->sr.present)
+                       isis_zebra_prefix_sid_install(area, prefix, route_info,
+                                                     &route_info->sr);
                hook_call(isis_route_update_hook, area, prefix, route_info);
 
                SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
@@ -415,7 +465,13 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
                if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
                        return;
 
-               isis_zebra_route_del_route(area->isis, prefix, src_p, route_info);
+               /* Uninstall Prefix-SID label. */
+               if (route_info->sr.present)
+                       isis_zebra_prefix_sid_uninstall(
+                               area, prefix, route_info, &route_info->sr);
+               /* Uninstall route. */
+               isis_zebra_route_del_route(area->isis, prefix, src_p,
+                                          route_info);
                hook_call(isis_route_update_hook, area, prefix, route_info);
 
                UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
index fbb548a79e41b59bac662567d895ddebd3aa28c0..b5e4aed6cccbe6df6e968d5dc8a8ceeee4df2445 100644 (file)
@@ -32,7 +32,7 @@ struct isis_nexthop {
        int family;
        union g_addr ip;
        uint8_t sysid[ISIS_SYS_ID_LEN];
-       struct sr_nexthop_info sr;
+       struct isis_sr_psid_info sr;
        struct mpls_label_stack *label_stack;
 };
 
@@ -43,6 +43,8 @@ struct isis_route_info {
        uint8_t flag;
        uint32_t cost;
        uint32_t depth;
+       struct isis_sr_psid_info sr;
+       struct isis_sr_psid_info sr_previous;
        struct list *nexthops;
        struct isis_route_info *backup;
 };
@@ -54,15 +56,13 @@ DECLARE_HOOK(isis_route_update_hook,
 
 void isis_nexthop_delete(struct isis_nexthop *nexthop);
 void adjinfo2nexthop(int family, struct list *nexthops,
-                    struct isis_adjacency *adj,
+                    struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
                     struct mpls_label_stack *label_stack);
-struct isis_route_info *isis_route_create(struct prefix *prefix,
-                                         struct prefix_ipv6 *src_p,
-                                         uint32_t cost,
-                                         uint32_t depth,
-                                         struct list *adjacencies,
-                                         struct isis_area *area,
-                                         struct route_table *table);
+struct isis_route_info *
+isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
+                 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
+                 struct list *adjacencies, struct isis_area *area,
+                 struct route_table *table);
 
 /* Walk the given table and install new routes to zebra and remove old ones.
  * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
index dacf4e14ecb3c137be3b093b0b55955eeb2dd892..690ea9f1a5e8979fd68c0478a71c563f75b861f0 100644 (file)
@@ -176,9 +176,8 @@ const char *vid2string(const struct isis_vertex *vertex, char *buff, int size)
        }
 
        if (VTYPE_IP(vertex->type)) {
-               srcdest2str(&vertex->N.ip.dest,
-                           &vertex->N.ip.src,
-                           buff, size);
+               srcdest2str(&vertex->N.ip.p.dest, &vertex->N.ip.p.src, buff,
+                           size);
                return buff;
        }
 
@@ -215,13 +214,33 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
        return vertex;
 }
 
-static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_vertex *vertex,
-                                                  struct isis_spf_adj *sadj)
+static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree,
+                                                  struct isis_vertex *vertex,
+                                                  struct isis_spf_adj *sadj,
+                                                  struct isis_prefix_sid *psid)
 {
        struct isis_vertex_adj *vadj;
 
        vadj = XCALLOC(MTYPE_ISIS_VERTEX_ADJ, sizeof(*vadj));
        vadj->sadj = sadj;
+       if (psid) {
+               if (vertex->N.ip.sr.present
+                   && vertex->N.ip.sr.sid.value != psid->value)
+                       zlog_warn(
+                               "ISIS-SPF: ignoring different Prefix-SID for route %pFX",
+                               &vertex->N.ip.p.dest);
+               else {
+                       bool last_hop;
+
+                       last_hop = (vertex->depth == 2);
+                       vadj->sr.sid = *psid;
+                       vadj->sr.label = sr_prefix_out_label(
+                               spftree->lspdb, vertex->N.ip.p.dest.family,
+                               psid, sadj->id, last_hop);
+                       if (vadj->sr.label != MPLS_INVALID_LABEL)
+                               vadj->sr.present = true;
+               }
+       }
        listnode_add(vertex->Adj_N, vadj);
 
        return vadj;
@@ -466,11 +485,10 @@ static void vertex_update_firsthops(struct isis_vertex *vertex,
 /*
  * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
  */
-static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
-                                            enum vertextype vtype, void *id,
-                                            uint32_t cost, int depth,
-                                            struct isis_spf_adj *sadj,
-                                            struct isis_vertex *parent)
+static struct isis_vertex *
+isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id,
+                 uint32_t cost, int depth, struct isis_spf_adj *sadj,
+                 struct isis_prefix_sid *psid, struct isis_vertex *parent)
 {
        struct isis_vertex *vertex;
        struct listnode *node;
@@ -496,6 +514,16 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
        vertex = isis_vertex_new(spftree, id, vtype);
        vertex->d_N = cost;
        vertex->depth = depth;
+       if (VTYPE_IP(vtype) && psid) {
+               bool local;
+
+               local = (vertex->depth == 1);
+               vertex->N.ip.sr.sid = *psid;
+               vertex->N.ip.sr.label =
+                       sr_prefix_in_label(spftree->area, psid, local);
+               if (vertex->N.ip.sr.label != MPLS_INVALID_LABEL)
+                       vertex->N.ip.sr.present = true;
+       }
 
        if (parent) {
                listnode_add(vertex->parents, parent);
@@ -508,9 +536,10 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
                struct isis_vertex_adj *parent_vadj;
 
                for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj))
-                       isis_vertex_adj_add(vertex, parent_vadj->sadj);
+                       isis_vertex_adj_add(spftree, vertex, parent_vadj->sadj,
+                                           psid);
        } else if (sadj) {
-               isis_vertex_adj_add(vertex, sadj);
+               isis_vertex_adj_add(spftree, vertex, sadj, psid);
        }
 
 #ifdef EXTREME_DEBUG
@@ -528,6 +557,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
 static void isis_spf_add_local(struct isis_spftree *spftree,
                               enum vertextype vtype, void *id,
                               struct isis_spf_adj *sadj, uint32_t cost,
+                              struct isis_prefix_sid *psid,
                               struct isis_vertex *parent)
 {
        struct isis_vertex *vertex;
@@ -538,7 +568,8 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
                /* C.2.5   c) */
                if (vertex->d_N == cost) {
                        if (sadj)
-                               isis_vertex_adj_add(vertex, sadj);
+                               isis_vertex_adj_add(spftree, vertex, sadj,
+                                                   psid);
                        /*       d) */
                        if (!CHECK_FLAG(spftree->flags,
                                        F_SPFTREE_NO_ADJACENCIES)
@@ -558,13 +589,13 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
                }
        }
 
-       isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, parent);
+       isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, psid, parent);
        return;
 }
 
 static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                      void *id, uint32_t dist, uint16_t depth,
-                     struct isis_vertex *parent)
+                     struct isis_prefix_sid *psid, struct isis_vertex *parent)
 {
        struct isis_vertex *vertex;
 #ifdef EXTREME_DEBUG
@@ -628,8 +659,9 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                                                  parent_vadj))
                                if (!isis_vertex_adj_exists(spftree, vertex,
                                                            parent_vadj->sadj))
-                                       isis_vertex_adj_add(vertex,
-                                                           parent_vadj->sadj);
+                                       isis_vertex_adj_add(spftree, vertex,
+                                                           parent_vadj->sadj,
+                                                           psid);
                        if (CHECK_FLAG(spftree->flags,
                                       F_SPFTREE_HOPCOUNT_METRIC))
                                vertex_update_firsthops(vertex, parent);
@@ -656,7 +688,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                   (parent ? print_sys_hostname(parent->N.id) : "null"));
 #endif /* EXTREME_DEBUG */
 
-       isis_spf_add2tent(spftree, vtype, id, dist, depth, NULL, parent);
+       isis_spf_add2tent(spftree, vtype, id, dist, depth, NULL, psid, parent);
        return;
 }
 
@@ -675,6 +707,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
        static const uint8_t null_sysid[ISIS_SYS_ID_LEN];
        struct isis_mt_router_info *mt_router_info = NULL;
        struct prefix_pair ip_info;
+       bool has_valid_psid;
 
        if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) {
                if (IS_DEBUG_TILFA)
@@ -739,7 +772,7 @@ lspfragloop:
                                          LSP_PSEUDO_ID(r->id)
                                                  ? VTYPE_PSEUDO_IS
                                                  : VTYPE_NONPSEUDO_IS,
-                                         (void *)r->id, dist, depth + 1,
+                                         (void *)r->id, dist, depth + 1, NULL,
                                          parent);
                        }
                }
@@ -773,7 +806,8 @@ lspfragloop:
                        process_N(spftree,
                                  LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
                                                        : VTYPE_NONPSEUDO_TE_IS,
-                                 (void *)er->id, dist, depth + 1, parent);
+                                 (void *)er->id, dist, depth + 1, NULL,
+                                 parent);
                }
        }
 
@@ -798,7 +832,7 @@ lspfragloop:
                                ip_info.dest.u.prefix4 = r->prefix.prefix;
                                ip_info.dest.prefixlen = r->prefix.prefixlen;
                                process_N(spftree, vtype, &ip_info,
-                                         dist, depth + 1, parent);
+                                         dist, depth + 1, NULL, parent);
                        }
                }
        }
@@ -823,8 +857,34 @@ lspfragloop:
                        dist = cost + r->metric;
                        ip_info.dest.u.prefix4 = r->prefix.prefix;
                        ip_info.dest.prefixlen = r->prefix.prefixlen;
-                       process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
-                                 dist, depth + 1, parent);
+
+                       /* Parse list of Prefix-SID subTLVs */
+                       has_valid_psid = false;
+                       if (r->subtlvs) {
+                               for (struct isis_item *i =
+                                            r->subtlvs->prefix_sids.head;
+                                    i; i = i->next) {
+                                       struct isis_prefix_sid *psid =
+                                               (struct isis_prefix_sid *)i;
+
+                                       if (psid->algorithm != SR_ALGORITHM_SPF)
+                                               continue;
+
+                                       has_valid_psid = true;
+                                       process_N(spftree, VTYPE_IPREACH_TE,
+                                                 &ip_info, dist, depth + 1,
+                                                 psid, parent);
+                                       /*
+                                        * Stop the Prefix-SID iteration since
+                                        * we only support the SPF algorithm for
+                                        * now.
+                                        */
+                                       break;
+                               }
+                       }
+                       if (!has_valid_psid)
+                               process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
+                                         dist, depth + 1, NULL, parent);
                }
        }
 
@@ -865,8 +925,34 @@ lspfragloop:
                                }
                                ip_info.src = *r->subtlvs->source_prefix;
                        }
-                       process_N(spftree, vtype, &ip_info, dist,
-                                 depth + 1, parent);
+
+                       /* Parse list of Prefix-SID subTLVs */
+                       has_valid_psid = false;
+                       if (r->subtlvs) {
+                               for (struct isis_item *i =
+                                            r->subtlvs->prefix_sids.head;
+                                    i; i = i->next) {
+                                       struct isis_prefix_sid *psid =
+                                               (struct isis_prefix_sid *)i;
+
+                                       if (psid->algorithm != SR_ALGORITHM_SPF)
+                                               continue;
+
+                                       has_valid_psid = true;
+                                       process_N(spftree, vtype, &ip_info,
+                                                 dist, depth + 1, psid,
+                                                 parent);
+                                       /*
+                                        * Stop the Prefix-SID iteration since
+                                        * we only support the SPF algorithm for
+                                        * now.
+                                        */
+                                       break;
+                               }
+                       }
+                       if (!has_valid_psid)
+                               process_N(spftree, vtype, &ip_info, dist,
+                                         depth + 1, NULL, parent);
                }
        }
 
@@ -922,6 +1008,7 @@ static int isis_spf_preload_tent_ip_reach_cb(const struct prefix *prefix,
        struct isis_vertex *parent = args->parent;
        struct prefix_pair ip_info;
        enum vertextype vtype;
+       bool has_valid_psid = false;
 
        if (external)
                return LSP_ITER_CONTINUE;
@@ -936,7 +1023,30 @@ static int isis_spf_preload_tent_ip_reach_cb(const struct prefix *prefix,
        else
                vtype = VTYPE_IP6REACH_INTERNAL;
 
-       isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, parent);
+       /* Parse list of Prefix-SID subTLVs */
+       if (subtlvs) {
+               for (struct isis_item *i = subtlvs->prefix_sids.head; i;
+                    i = i->next) {
+                       struct isis_prefix_sid *psid =
+                               (struct isis_prefix_sid *)i;
+
+                       if (psid->algorithm != SR_ALGORITHM_SPF)
+                               continue;
+
+                       has_valid_psid = true;
+                       isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0,
+                                          psid, parent);
+
+                       /*
+                        * Stop the Prefix-SID iteration since we only support
+                        * the SPF algorithm for now.
+                        */
+                       break;
+               }
+       }
+       if (!has_valid_psid)
+               isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, NULL,
+                                  parent);
 
        return LSP_ITER_CONTINUE;
 }
@@ -985,7 +1095,8 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree,
                                                      F_ISIS_SPF_ADJ_OLDMETRIC)
                                                   ? VTYPE_NONPSEUDO_IS
                                                   : VTYPE_NONPSEUDO_TE_IS,
-                                          sadj->id, sadj, metric, parent);
+                                          sadj->id, sadj, metric, NULL,
+                                          parent);
                } else if (sadj->lan.lsp_pseudo) {
                        isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo,
                                             metric, 0, spftree->sysid, parent);
@@ -1291,8 +1402,9 @@ static void spf_path_process(struct isis_spftree *spftree,
                        } else
                                route_table = spftree->route_table;
 
-                       isis_route_create(&vertex->N.ip.dest, &vertex->N.ip.src,
-                                         vertex->d_N, vertex->depth,
+                       isis_route_create(&vertex->N.ip.p.dest,
+                                         &vertex->N.ip.p.src, vertex->d_N,
+                                         vertex->depth, &vertex->N.ip.sr,
                                          vertex->Adj_N, area, route_table);
                } else if (IS_DEBUG_SPF_EVENTS)
                        zlog_debug(
@@ -1532,8 +1644,6 @@ static int isis_run_spf_cb(struct thread *thread)
 
        isis_area_verify_routes(area);
 
-       isis_area_verify_sr(area);
-
        /* walk all circuits and reset any spf specific flags */
        struct listnode *node;
        struct isis_circuit *circuit;
@@ -1824,12 +1934,126 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
        return CMD_SUCCESS;
 }
 
+static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
+                            struct isis_route_info *rinfo, bool prefix_sid,
+                            bool no_adjacencies)
+{
+       struct isis_nexthop *nexthop;
+       struct listnode *node;
+       bool first = true;
+       char buf_prefix[BUFSIZ];
+
+       (void)prefix2str(prefix, buf_prefix, sizeof(buf_prefix));
+       for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
+               struct interface *ifp;
+               char buf_iface[BUFSIZ];
+               char buf_nhop[BUFSIZ];
+
+               if (!no_adjacencies) {
+                       inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
+                                 sizeof(buf_nhop));
+                       ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
+                       if (ifp)
+                               strlcpy(buf_iface, ifp->name,
+                                       sizeof(buf_iface));
+                       else
+                               snprintf(buf_iface, sizeof(buf_iface),
+                                        "ifindex %u", nexthop->ifindex);
+               } else {
+                       strlcpy(buf_nhop, print_sys_hostname(nexthop->sysid),
+                               sizeof(buf_nhop));
+                       strlcpy(buf_iface, "-", sizeof(buf_iface));
+               }
+
+               if (prefix_sid) {
+                       char buf_sid[BUFSIZ] = {};
+                       char buf_lblop[BUFSIZ] = {};
+
+                       if (nexthop->sr.present) {
+                               snprintf(buf_sid, sizeof(buf_sid), "%u",
+                                        nexthop->sr.sid.value);
+                               sr_op2str(buf_lblop, sizeof(buf_lblop),
+                                         rinfo->sr.label, nexthop->sr.label);
+                       } else {
+                               strlcpy(buf_sid, "-", sizeof(buf_sid));
+                               strlcpy(buf_lblop, "-", sizeof(buf_lblop));
+                       }
+
+                       if (first) {
+                               ttable_add_row(tt, "%s|%u|%s|%s|%s|%s",
+                                              buf_prefix, rinfo->cost,
+                                              buf_iface, buf_nhop, buf_sid,
+                                              buf_lblop);
+                               first = false;
+                       } else
+                               ttable_add_row(tt, "||%s|%s|%s|%s", buf_iface,
+                                              buf_nhop, buf_sid, buf_lblop);
+               } else {
+                       char buf_labels[BUFSIZ] = {};
+
+                       if (nexthop->label_stack) {
+                               for (int i = 0;
+                                    i < nexthop->label_stack->num_labels;
+                                    i++) {
+                                       char buf_label[BUFSIZ];
+
+                                       label2str(
+                                               nexthop->label_stack->label[i],
+                                               buf_label, sizeof(buf_label));
+                                       if (i != 0)
+                                               strlcat(buf_labels, "/",
+                                                       sizeof(buf_labels));
+                                       strlcat(buf_labels, buf_label,
+                                               sizeof(buf_labels));
+                               }
+                       } else if (nexthop->sr.present)
+                               label2str(nexthop->sr.label, buf_labels,
+                                         sizeof(buf_labels));
+                       else
+                               strlcpy(buf_labels, "-", sizeof(buf_labels));
+
+                       if (first) {
+                               ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
+                                              rinfo->cost, buf_iface, buf_nhop,
+                                              buf_labels);
+                               first = false;
+                       } else
+                               ttable_add_row(tt, "||%s|%s|%s", buf_iface,
+                                              buf_nhop, buf_labels);
+               }
+       }
+       if (list_isempty(rinfo->nexthops)) {
+               if (prefix_sid) {
+                       char buf_sid[BUFSIZ] = {};
+                       char buf_lblop[BUFSIZ] = {};
+
+                       if (rinfo->sr.present) {
+                               snprintf(buf_sid, sizeof(buf_sid), "%u",
+                                        rinfo->sr.sid.value);
+                               sr_op2str(buf_lblop, sizeof(buf_lblop),
+                                         rinfo->sr.label,
+                                         MPLS_LABEL_IMPLICIT_NULL);
+                       } else {
+                               strlcpy(buf_sid, "-", sizeof(buf_sid));
+                               strlcpy(buf_lblop, "-", sizeof(buf_lblop));
+                       }
+
+                       ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", buf_prefix,
+                                      rinfo->cost, "-", "-", buf_sid,
+                                      buf_lblop);
+               } else
+                       ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
+                                      rinfo->cost, "-", "-", "-");
+       }
+}
+
 void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
-                      bool backup)
+                      bool prefix_sid, bool backup)
 {
        struct route_table *route_table;
        struct ttable *tt;
        struct route_node *rn;
+       bool no_adjacencies = false;
        const char *tree_id_text = NULL;
 
        if (!spftree)
@@ -1855,82 +2079,28 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
 
        /* Prepare table. */
        tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
-       ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
+       if (prefix_sid)
+               ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|SID|Label Op.");
+       else
+               ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
        tt->style.cell.rpad = 2;
        tt->style.corner = '+';
        ttable_restyle(tt);
        ttable_rowseps(tt, 0, BOTTOM, true, '-');
 
+       if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+               no_adjacencies = true;
+
        route_table =
                (backup) ? spftree->route_table_backup : spftree->route_table;
        for (rn = route_top(route_table); rn; rn = route_next(rn)) {
                struct isis_route_info *rinfo;
-               struct isis_nexthop *nexthop;
-               struct listnode *node;
-               bool first = true;
-               char buf_prefix[BUFSIZ];
 
                rinfo = rn->info;
                if (!rinfo)
                        continue;
 
-               (void)prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
-               for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
-                       struct interface *ifp;
-                       char buf_iface[BUFSIZ];
-                       char buf_nhop[BUFSIZ];
-                       char buf_labels[BUFSIZ] = {};
-
-                       if (!CHECK_FLAG(spftree->flags,
-                                       F_SPFTREE_NO_ADJACENCIES)) {
-                               inet_ntop(nexthop->family, &nexthop->ip,
-                                         buf_nhop, sizeof(buf_nhop));
-                               ifp = if_lookup_by_index(nexthop->ifindex,
-                                                        VRF_DEFAULT);
-                               if (ifp)
-                                       strlcpy(buf_iface, ifp->name,
-                                               sizeof(buf_iface));
-                               else
-                                       snprintf(buf_iface, sizeof(buf_iface),
-                                                "ifindex %u",
-                                                nexthop->ifindex);
-                       } else {
-                               strlcpy(buf_nhop,
-                                       print_sys_hostname(nexthop->sysid),
-                                       sizeof(buf_nhop));
-                               strlcpy(buf_iface, "-", sizeof(buf_iface));
-                       }
-
-                       if (nexthop->label_stack) {
-                               for (int i = 0;
-                                    i < nexthop->label_stack->num_labels;
-                                    i++) {
-                                       char buf_label[BUFSIZ];
-
-                                       label2str(
-                                               nexthop->label_stack->label[i],
-                                               buf_label, sizeof(buf_label));
-                                       if (i != 0)
-                                               strlcat(buf_labels, "/",
-                                                       sizeof(buf_labels));
-                                       strlcat(buf_labels, buf_label,
-                                               sizeof(buf_labels));
-                               }
-                       } else if (nexthop->sr.label != MPLS_INVALID_LABEL)
-                               label2str(nexthop->sr.label, buf_labels,
-                                         sizeof(buf_labels));
-                       else
-                               strlcpy(buf_labels, "-", sizeof(buf_labels));
-
-                       if (first) {
-                               ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
-                                              rinfo->cost, buf_iface, buf_nhop,
-                                              buf_labels);
-                               first = false;
-                       } else
-                               ttable_add_row(tt, "||%s|%s|%s", buf_iface,
-                                              buf_nhop, buf_labels);
-               }
+               isis_print_route(tt, &rn->p, rinfo, prefix_sid, no_adjacencies);
        }
 
        /* Dump the generated table. */
@@ -1945,7 +2115,8 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
 }
 
 static void show_isis_route_common(struct vty *vty, int levels,
-                                  struct isis *isis, bool backup)
+                                  struct isis *isis, bool prefix_sid,
+                                  bool backup)
 {
        struct listnode *node;
        struct isis_area *area;
@@ -1965,19 +2136,19 @@ static void show_isis_route_common(struct vty *vty, int levels,
                                isis_print_routes(
                                        vty,
                                        area->spftree[SPFTREE_IPV4][level - 1],
-                                       backup);
+                                       prefix_sid, backup);
                        }
                        if (area->ipv6_circuits > 0) {
                                isis_print_routes(
                                        vty,
                                        area->spftree[SPFTREE_IPV6][level - 1],
-                                       backup);
+                                       prefix_sid, backup);
                        }
                        if (isis_area_ipv6_dstsrc_enabled(area)) {
                                isis_print_routes(vty,
                                                  area->spftree[SPFTREE_DSTSRC]
                                                               [level - 1],
-                                                 backup);
+                                                 prefix_sid, backup);
                        }
                }
        }
@@ -1989,13 +2160,14 @@ DEFUN(show_isis_route, show_isis_route_cmd,
 #ifndef FABRICD
       " [<level-1|level-2>]"
 #endif
-      " [backup]",
+      " [<prefix-sid|backup>]",
       SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
       "IS-IS routing table\n"
 #ifndef FABRICD
       "level-1 routes\n"
       "level-2 routes\n"
 #endif
+      "Show Prefix-SID information\n"
       "Show backup routes\n")
 {
        int levels;
@@ -2003,6 +2175,7 @@ DEFUN(show_isis_route, show_isis_route_cmd,
        struct listnode *node;
        const char *vrf_name = VRF_DEFAULT_NAME;
        bool all_vrf = false;
+       bool prefix_sid = false;
        bool backup = false;
        int idx = 0;
 
@@ -2019,6 +2192,8 @@ DEFUN(show_isis_route, show_isis_route_cmd,
        }
        ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
 
+       if (argv_find(argv, argc, "prefix-sid", &idx))
+               prefix_sid = true;
        if (argv_find(argv, argc, "backup", &idx))
                backup = true;
 
@@ -2026,12 +2201,13 @@ DEFUN(show_isis_route, show_isis_route_cmd,
                if (all_vrf) {
                        for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
                                show_isis_route_common(vty, levels, isis,
-                                                      backup);
+                                                      prefix_sid, backup);
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
                if (isis != NULL)
-                       show_isis_route_common(vty, levels, isis, backup);
+                       show_isis_route_common(vty, levels, isis, prefix_sid,
+                                              backup);
        }
 
        return CMD_SUCCESS;
index 5d07c80d20a9198997fb573fd1645903f034bb1c..15d3ff92727831265cd8a83ca2b4a7d619902714 100644 (file)
@@ -68,7 +68,7 @@ int _isis_spf_schedule(struct isis_area *area, int level,
                       const char *func, const char *file, int line);
 void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree);
 void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
-                      bool backup);
+                      bool prefix_sid, bool backup);
 void isis_spf_init(void);
 void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
 void isis_run_spf(struct isis_spftree *spftree);
index 1a2e969bd9f11fb305540f318ff97fb3481b022a..e999f965396925667b7a8ead19d8614d8b3da95e 100644 (file)
@@ -52,6 +52,7 @@ struct prefix_pair {
 
 struct isis_vertex_adj {
        struct isis_spf_adj *sadj;
+       struct isis_sr_psid_info sr;
        struct mpls_label_stack *label_stack;
 };
 
@@ -62,7 +63,10 @@ struct isis_vertex {
        enum vertextype type;
        union {
                uint8_t id[ISIS_SYS_ID_LEN + 1];
-               struct prefix_pair ip;
+               struct {
+                       struct prefix_pair p;
+                       struct isis_sr_psid_info sr;
+               } ip;
        } N;
        uint32_t d_N;     /* d(N) Distance from this IS      */
        uint16_t depth; /* The depth in the imaginary tree */
@@ -91,8 +95,8 @@ static unsigned isis_vertex_queue_hash_key(const void *vp)
        if (VTYPE_IP(vertex->type)) {
                uint32_t key;
 
-               key = prefix_hash_key(&vertex->N.ip.dest);
-               key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key);
+               key = prefix_hash_key(&vertex->N.ip.p.dest);
+               key = jhash_1word(prefix_hash_key(&vertex->N.ip.p.src), key);
                return key;
        }
 
@@ -108,11 +112,12 @@ static bool isis_vertex_queue_hash_cmp(const void *a, const void *b)
                return false;
 
        if (VTYPE_IP(va->type)) {
-               if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest))
+               if (prefix_cmp(&va->N.ip.p.dest, &vb->N.ip.p.dest))
                        return false;
 
-               return prefix_cmp((const struct prefix *)&va->N.ip.src,
-                                 (const struct prefix *)&vb->N.ip.src) == 0;
+               return prefix_cmp((const struct prefix *)&va->N.ip.p.src,
+                                 (const struct prefix *)&vb->N.ip.p.src)
+                      == 0;
        }
 
        return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
@@ -351,7 +356,7 @@ static void isis_vertex_id_init(struct isis_vertex *vertex, const void *id,
        if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
                memcpy(vertex->N.id, id, ISIS_SYS_ID_LEN + 1);
        } else if (VTYPE_IP(vtype)) {
-               memcpy(&vertex->N.ip, id, sizeof(vertex->N.ip));
+               memcpy(&vertex->N.ip.p, id, sizeof(vertex->N.ip.p));
        } else {
                flog_err(EC_LIB_DEVELOPMENT, "Unknown Vertex Type");
        }
index 842103de1e17502e9adc118a829f0686e21c8d60..deb0767d170ce0eaa322fad978b58500c967b86b 100644 (file)
@@ -31,6 +31,7 @@
 #include "memory.h"
 #include "prefix.h"
 #include "table.h"
+#include "srcdest_table.h"
 #include "vty.h"
 #include "zclient.h"
 #include "lib/lib_errors.h"
@@ -50,8 +51,6 @@
 /* Local variables and functions */
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
 
-static void sr_prefix_uninstall(struct sr_prefix *srp);
-static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
 static void sr_local_block_delete(struct isis_area *area);
 static int sr_local_block_init(struct isis_area *area);
 static void sr_adj_sid_update(struct sr_adjacency *sra,
@@ -61,53 +60,149 @@ static void sr_adj_sid_del(struct sr_adjacency *sra);
 /* --- RB-Tree Management functions ----------------------------------------- */
 
 /**
- * SR Prefix comparison for RB-Tree.
+ * 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_compare(const struct sr_prefix *a,
-                                       const struct sr_prefix *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(srdb_node_prefix, struct sr_prefix, node_entry,
-                   sr_prefix_sid_compare)
-DECLARE_RBTREE_UNIQ(srdb_area_prefix, struct sr_prefix, area_entry,
-                   sr_prefix_sid_compare)
+DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
+                   sr_prefix_sid_cfg_compare)
 
 /**
- * Configured SR Prefix comparison for RB-Tree.
+ * Find SRGB associated to a System ID.
  *
- * @param a    First SR prefix
- * @param b    Second SR prefix
+ * @param area IS-IS LSP database
+ * @param sysid        System ID to lookup
  *
- * @return     -1 (a < b), 0 (a == b) or +1 (a > b)
+ * @return     Pointer to SRGB if found, NULL otherwise
  */
-static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
-                                           const struct sr_prefix_cfg *b)
+struct isis_sr_block *isis_sr_find_srgb(struct lspdb_head *lspdb,
+                                       const uint8_t *sysid)
 {
-       return prefix_cmp(&a->prefix, &b->prefix);
+       struct isis_lsp *lsp;
+
+       lsp = isis_root_system_lsp(lspdb, sysid);
+       if (!lsp)
+               return NULL;
+
+       if (!lsp->tlvs->router_cap
+           || lsp->tlvs->router_cap->srgb.range_size == 0)
+               return NULL;
+
+       return &lsp->tlvs->router_cap->srgb;
 }
-DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
-                   sr_prefix_sid_cfg_compare)
 
 /**
- * SR Node comparison for RB-Tree.
+ * Compute input label for the given Prefix-SID.
  *
- * @param a    First SR node
- * @param b    Second SR node
+ * @param area   IS-IS area
+ * @param psid   IS-IS Prefix-SID Sub-TLV
+ * @param local          Indicates whether the Prefix-SID is local or not
  *
- * @return     -1 (a < b), 0 (a == b) or +1 (a > b)
+ * @return     MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
  */
-static inline int sr_node_compare(const struct sr_node *a,
-                                 const struct sr_node *b)
+mpls_label_t sr_prefix_in_label(struct isis_area *area,
+                               struct isis_prefix_sid *psid, bool local)
 {
-       return memcmp(a->sysid, b->sysid, ISIS_SYS_ID_LEN);
+       /*
+        * No need to assign a label for local Prefix-SIDs unless the no-PHP
+        * flag is set.
+        */
+       if (local
+           && (!CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP)
+               || CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL)))
+               return MPLS_INVALID_LABEL;
+
+       /* Return SID value as MPLS label if it is an Absolute SID */
+       if (CHECK_FLAG(psid->flags,
+                      ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
+               return psid->value;
+
+       /* Check that SID index falls inside the SRGB */
+       if (psid->value >= (area->srdb.config.srgb_upper_bound
+                           - area->srdb.config.srgb_lower_bound + 1)) {
+               flog_warn(EC_ISIS_SID_OVERFLOW,
+                         "%s: SID index %u falls outside local SRGB range",
+                         __func__, psid->value);
+               return MPLS_INVALID_LABEL;
+       }
+
+       /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
+       return (area->srdb.config.srgb_lower_bound + psid->value);
+}
+
+/**
+ * Compute output label for the given Prefix-SID.
+ *
+ * @param lspdb                IS-IS LSP database
+ * @param family       Prefix-SID address family
+ * @param psid         Prefix-SID Sub-TLV
+ * @param nh_sysid     System ID of the nexthop node
+ * @param last_hop     Indicates whether the nexthop node is the last hop
+ *
+ * @return             MPLS label or MPLS_INVALID_LABEL in case of error
+ */
+mpls_label_t sr_prefix_out_label(struct lspdb_head *lspdb, int family,
+                                struct isis_prefix_sid *psid,
+                                const uint8_t *nh_sysid, bool last_hop)
+{
+       struct isis_sr_block *nh_srgb;
+
+       if (last_hop) {
+               if (!CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP))
+                       return MPLS_LABEL_IMPLICIT_NULL;
+
+               if (CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL)) {
+                       if (family == AF_INET)
+                               return MPLS_LABEL_IPV4_EXPLICIT_NULL;
+                       else
+                               return MPLS_LABEL_IPV6_EXPLICIT_NULL;
+               }
+               /* Fallthrough */
+       }
+
+       /* Return SID value as MPLS label if it is an Absolute SID */
+       if (CHECK_FLAG(psid->flags,
+                      ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
+               /*
+                * V/L SIDs have local significance, so only adjacent routers
+                * can use them (RFC8667 section #2.1.1.1)
+                */
+               if (!last_hop)
+                       return MPLS_INVALID_LABEL;
+               return psid->value;
+       }
+
+       /* Check that SID index falls inside the SRGB */
+       nh_srgb = isis_sr_find_srgb(lspdb, nh_sysid);
+       if (!nh_srgb)
+               return MPLS_INVALID_LABEL;
+
+       /*
+        * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
+        * IPv6 packets.
+        */
+       if ((family == AF_INET && !IS_SR_IPV4(nh_srgb))
+           || (family == AF_INET6 && !IS_SR_IPV6(nh_srgb)))
+               return MPLS_INVALID_LABEL;
+
+       if (psid->value >= nh_srgb->range_size) {
+               flog_warn(EC_ISIS_SID_OVERFLOW,
+                         "%s: SID index %u falls outside remote SRGB range",
+                         __func__, psid->value);
+               return MPLS_INVALID_LABEL;
+       }
+
+       /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
+       return (nh_srgb->lower_bound + psid->value);
 }
-DECLARE_RBTREE_UNIQ(srdb_node, struct sr_node, entry, sr_node_compare)
 
 /* --- Functions used for Yang model and CLI to configure Segment Routing --- */
 
@@ -162,8 +257,6 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
        srdb->config.srgb_upper_bound = upper_bound;
 
        if (srdb->enabled) {
-               struct sr_prefix *srp;
-
                /* then request new SRGB if SR is enabled. */
                if (isis_zebra_request_label_range(
                            srdb->config.srgb_lower_bound,
@@ -179,14 +272,6 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
                         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 (srdb_area_prefix,
-                                 &area->srdb.prefix_sids[level - 1], srp) {
-                               sr_prefix_reinstall(srp, false);
-                       }
-               }
-
                lsp_regenerate_schedule(area, area->is_type, 0);
        } else if (srdb->config.enabled) {
                /* Try to enable SR again using the new SRGB. */
@@ -232,1027 +317,136 @@ int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound,
        srdb->config.srlb_upper_bound = upper_bound;
 
        if (srdb->enabled) {
-               /* Initialize new SRLB */
-               if (sr_local_block_init(area) != 0)
-                       return -1;
-
-               /* Reinstall local Adjacency-SIDs with new labels. */
-               for (ALL_LIST_ELEMENTS_RO(area->srdb.adj_sids, node, sra))
-                       sr_adj_sid_update(sra, &srdb->srlb);
-
-               /* Update and Flood LSP */
-               lsp_regenerate_schedule(area, area->is_type, 0);
-       } else if (srdb->config.enabled) {
-               /* Try to enable SR again using the new SRLB. */
-               isis_sr_start(area);
-       }
-
-       return 0;
-}
-
-/**
- * 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;
-
-       /* Pull defaults from the YANG module. */
-       pcfg->sid_type = yang_get_default_enum(
-               "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR);
-       pcfg->last_hop_behavior = yang_get_default_enum(
-               "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR);
-
-       /* Set the N-flag when appropriate. */
-       ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
-       if (ifp && sr_prefix_is_node_sid(ifp, prefix))
-               pcfg->node_sid = true;
-
-       /* Save prefix-sid configuration. */
-       srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
-
-       return pcfg;
-}
-
-/**
- * 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 = pcfg->area;
-
-       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 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 srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
-}
-
-/**
- * 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)
-{
-       /* Set SID algorithm. */
-       psid->algorithm = SR_ALGORITHM_SPF;
-
-       /* Set SID flags. */
-       psid->flags = 0;
-       switch (pcfg->last_hop_behavior) {
-       case SR_LAST_HOP_BEHAVIOR_EXP_NULL:
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
-               break;
-       case SR_LAST_HOP_BEHAVIOR_NO_PHP:
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
-               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
-               break;
-       case SR_LAST_HOP_BEHAVIOR_PHP:
-               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
-               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
-               break;
-       }
-       if (external)
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED);
-       if (pcfg->node_sid)
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);
-
-       /* Set SID value. */
-       psid->value = pcfg->sid;
-       if (pcfg->sid_type == SR_SID_VALUE_TYPE_ABSOLUTE) {
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE);
-               SET_FLAG(psid->flags, ISIS_PREFIX_SID_LOCAL);
-       }
-}
-
-/* --- Segment Routing Prefix Management functions -------------------------- */
-
-/**
- * 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->input_label = MPLS_INVALID_LABEL;
-       if (local) {
-               srp->type = ISIS_SR_PREFIX_LOCAL;
-               isis_sr_nexthop_reset(&srp->u.local.info);
-       } else {
-               srp->type = ISIS_SR_PREFIX_REMOTE;
-               srp->u.remote.rinfo = NULL;
-       }
-       srp->srn = srn;
-       srdb_node_prefix_add(&srn->prefix_sids, srp);
-       /* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
-       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;
-}
-
-/**
- * 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)
-{
-       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);
-}
-
-/**
- * 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 srdb_area_prefix_find(&area->srdb.prefix_sids[level - 1], &srp);
-}
-
-/**
- * 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 srdb_node_prefix_find(&srn->prefix_sids, &srp);
-}
-
-/* --- 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)
-{
-       struct sr_node *srn;
-
-       srn = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srn));
-       srn->level = level;
-       memcpy(srn->sysid, sysid, ISIS_SYS_ID_LEN);
-       srn->area = area;
-       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 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 (srdb_node_prefix_count(&srn->prefix_sids) > 0) {
-               struct sr_prefix *srp;
-
-               srp = srdb_node_prefix_first(&srn->prefix_sids);
-               sr_prefix_del(area, srn, srp);
-       }
-
-       srdb_node_del(&area->srdb.sr_nodes[level - 1], srn);
-       XFREE(MTYPE_ISIS_SR_INFO, srn);
-}
-
-/**
- * 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 srdb_node_find(&area->srdb.sr_nodes[level - 1], &srn);
-}
-
-/**
- * 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;
-
-       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;
-
-               if (srp->type == ISIS_SR_PREFIX_LOCAL)
-                       continue;
-
-               if (srp->u.remote.rinfo == NULL)
-                       continue;
-
-               for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
-                                         nh)) {
-                       if (memcmp(nh->sysid, sysid, ISIS_SYS_ID_LEN) != 0)
-                               continue;
-
-                       /*
-                        * 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).
-                        */
-                       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;
-       if (srnh->uptime == 0)
-               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 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;
-
-       rn = route_node_lookup(area->spftree[tree_id][level - 1]->route_table,
-                              &srp->prefix);
-       if (rn) {
-               route_unlock_node(rn);
-               if (rn->info)
-                       return rn->info;
-       }
-
-       return NULL;
-}
-
-/**
- * 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;
-
-       /* 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;
-
-       /* 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,
-                         "%s: SID index %u falls outside local SRGB range",
-                         __func__, srp->sid.value);
-               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);
-}
-
-/**
- * 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;
-
-       /* 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;
-                       else
-                               return MPLS_LABEL_IPV6_EXPLICIT_NULL;
-               }
-               /* Fallthrough */
-       }
-
-       /* 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 (RFC8667 section #2.1.1.1)
-                */
-               if (srp->srn != srn_nexthop)
-                       return MPLS_INVALID_LABEL;
-               return srp->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",
-                         __func__, srp->sid.value);
-               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. 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;
-
-       /*
-        * 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;
-
-       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));
-
-       /* 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->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_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
-
-       return 0;
-}
-
-/**
- * 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 input_label;
-       size_t nexthop_num = 0;
-
-       /* Lookup to associated IS-IS route. */
-       tree_id = (srp->prefix.family == AF_INET) ? SPFTREE_IPV4 : SPFTREE_IPV6;
-       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;
-
-       /* 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 output_label;
-
-               /* Check if the nexthop advertised a SRGB. */
-               srn_nexthop = sr_node_find(area, srn->level, nexthop->sysid);
-               if (!srn_nexthop)
-                       goto next;
-
-               /*
-                * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
-                * IPv6 packets.
-                */
-               if ((nexthop->family == AF_INET
-                    && !IS_SR_IPV4(srn_nexthop->cap.srgb))
-                   || (nexthop->family == AF_INET6
-                       && !IS_SR_IPV6(srn_nexthop->cap.srgb)))
-                       goto next;
-
-               /* 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_SR) {
-                       static char buf[INET6_ADDRSTRLEN];
-
-                       inet_ntop(nexthop->family, &nexthop->ip, buf,
-                                 sizeof(buf));
-                       zlog_debug("    |- nexthop %s label %u", buf,
-                                  output_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) {
-               sr_debug("    |- no valid nexthops");
-               return -1;
-       }
-
-       /* Update internal state. */
-       srp->input_label = input_label;
-
-       /* Install Prefix-SID in the forwarding plane. */
-       isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
-
-       return 0;
-}
-
-/**
- * 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 = sr_prefix_find_by_area(area, ISIS_LEVEL2,
-                                                       &srp->prefix);
-                       if (srp_l2)
-                               sr_prefix_uninstall(srp_l2);
-                       break;
-               case ISIS_LEVEL2:
-                       srp_l1 = sr_prefix_find_by_area(area, ISIS_LEVEL1,
-                                                       &srp->prefix);
-                       if (srp_l1)
-                               return;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Install corresponding LFIB entry */
-       if (srp->type == ISIS_SR_PREFIX_LOCAL)
-               ret = sr_prefix_install_local(srp);
-       else
-               ret = sr_prefix_install_remote(srp);
-       if (ret != 0)
-               sr_prefix_uninstall(srp);
-}
-
-/**
- * Uninstall local or remote Prefix-SID.
- *
- * @param srp  Segment Routing Prefix
- */
-static void sr_prefix_uninstall(struct sr_prefix *srp)
-{
-       struct listnode *node;
-       struct isis_nexthop *nexthop;
-
-       /* Check that Input Label is valid */
-       if (srp->input_label == MPLS_INVALID_LABEL)
-               return;
-
-       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_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE, srp);
-
-       /* Reset internal state. */
-       srp->input_label = MPLS_INVALID_LABEL;
-       switch (srp->type) {
-       case ISIS_SR_PREFIX_LOCAL:
-               isis_sr_nexthop_reset(&srp->u.local.info);
-               break;
-       case ISIS_SR_PREFIX_REMOTE:
-               if (srp->u.remote.rinfo) {
-                       for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops,
-                                                 node, nexthop))
-                               isis_sr_nexthop_reset(&nexthop->sr);
-               }
-               break;
-       }
-}
-
-/**
- * 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)
-{
-       /*
-        * 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 (!make_before_break)
-               sr_prefix_uninstall(srp);
-
-       /* New input label is computed in sr_prefix_install() function */
-       sr_prefix_install(srp);
-}
-
-/* --- IS-IS LSP Parse functions -------------------------------------------- */
-
-/**
- * Compare Router Capabilities. Only Flags, SRGB and Algorithm are used for the
- * comparison. MSD and SRLB modification must not trigger and SR-Prefix update.
- *
- * @param r1   First Router Capabilities to compare
- * @param r2   Second Router Capabilities to compare
- * @return     0 if r1 and r2 are equal or -1 otherwise
- */
-static int router_cap_cmp(const struct isis_router_cap *r1,
-                         const struct isis_router_cap *r2)
-{
-       if (r1->flags == r2->flags
-           && r1->srgb.lower_bound == r2->srgb.lower_bound
-           && r1->srgb.range_size == r2->srgb.range_size
-           && r1->algo[0] == r2->algo[0])
-               return 0;
-       else
-               return -1;
-}
-
-/**
- * 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 *
-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;
-
-       sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area->area_tag);
-
-       srn = sr_node_find(area, level, sysid);
-       if (srn) {
-               if (router_cap_cmp(&srn->cap, router_cap) != 0) {
-                       srn->state = SRDB_STATE_MODIFIED;
-               } else
-                       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 = sr_node_add(area, level, sysid);
-               srn->state = SRDB_STATE_NEW;
-       }
-
-       /*
-        * Update Router Capabilities in any case as SRLB or MSD
-        * modification are not take into account for comparison.
-        */
-       srn->cap = *router_cap;
-
-       return srn;
-}
-
-/**
- * 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;
+               /* Initialize new SRLB */
+               if (sr_local_block_init(area) != 0)
+                       return -1;
 
-               /* Only SPF algorithm is supported right now */
-               if (psid->algorithm != SR_ALGORITHM_SPF)
-                       continue;
+               /* Reinstall local Adjacency-SIDs with new labels. */
+               for (ALL_LIST_ELEMENTS_RO(area->srdb.adj_sids, node, sra))
+                       sr_adj_sid_update(sra, &srdb->srlb);
 
-               /* 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;
-                               srp->state = SRDB_STATE_MODIFIED;
-                       } else if (srp->state == SRDB_STATE_VALIDATED)
-                               srp->state = SRDB_STATE_UNCHANGED;
-                       sr_debug("  |- Found %s Prefix-SID %pFX",
-                                srp->state == SRDB_STATE_MODIFIED
-                                        ? "Modified"
-                                        : "Unchanged",
-                                &srp->prefix);
-
-               } else {
-                       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
-                * algorithm for now.
-                */
-               break;
+               /* Update and Flood LSP */
+               lsp_regenerate_schedule(area, area->is_type, 0);
+       } else if (srdb->config.enabled) {
+               /* Try to enable SR again using the new SRLB. */
+               isis_sr_start(area);
        }
+
+       return 0;
 }
 
 /**
- * Parse all SR-related information from the given LSP.
+ * Add new Prefix-SID configuration to the SRDB.
  *
- * @param area IS-IS area
- * @param level        IS-IS level
- * @param srn  Segment Routing Node
- * @param lsp  IS-IS LSP
+ * @param area   IS-IS area
+ * @param prefix  Prefix to be added
+ *
+ * @return       Newly added Prefix-SID configuration structure
  */
-static void parse_lsp(struct isis_area *area, int level, struct sr_node **srn,
-                     struct isis_lsp *lsp)
+struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
+                                            const struct prefix *prefix)
 {
-       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 = parse_router_cap_tlv(area, level, lsp->hdr.lsp_id,
-                                           lsp->tlvs->router_cap);
-               if (!*srn)
-                       return;
-       }
+       struct sr_prefix_cfg *pcfg;
+       struct interface *ifp;
 
-       /* Parse the Extended IP Reachability TLV. */
-       items = &lsp->tlvs->extended_ip_reach;
-       for (i = items->head; i; i = i->next) {
-               struct isis_extended_ip_reach *ir;
+       sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
 
-               ir = (struct isis_extended_ip_reach *)i;
-               if (!ir->subtlvs)
-                       continue;
+       pcfg = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*pcfg));
+       pcfg->prefix = *prefix;
+       pcfg->area = area;
 
-               parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
-                                        &ir->subtlvs->prefix_sids);
-       }
+       /* Pull defaults from the YANG module. */
+       pcfg->sid_type = yang_get_default_enum(
+               "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR);
+       pcfg->last_hop_behavior = yang_get_default_enum(
+               "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR);
 
-       /* Parse Multi Topology Reachable IPv6 Prefixes TLV. */
-       items = isis_lookup_mt_items(&lsp->tlvs->mt_ipv6_reach,
-                                    ISIS_MT_IPV6_UNICAST);
-       for (i = items ? items->head : NULL; i; i = i->next) {
-               struct isis_ipv6_reach *ir;
+       /* Set the N-flag when appropriate. */
+       ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
+       if (ifp && sr_prefix_is_node_sid(ifp, prefix))
+               pcfg->node_sid = true;
 
-               ir = (struct isis_ipv6_reach *)i;
-               if (!ir->subtlvs)
-                       continue;
+       /* Save prefix-sid configuration. */
+       srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
 
-               parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
-                                        &ir->subtlvs->prefix_sids);
-       }
+       return pcfg;
 }
 
 /**
- * Parse all SR-related information from the entire LSPDB.
+ * Removal of locally configured Prefix-SID.
  *
- * @param area IS-IS area
+ * @param pcfg Configured Prefix-SID
  */
-static void parse_lspdb(struct isis_area *area)
+void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
 {
-       struct isis_lsp *lsp;
+       struct isis_area *area = pcfg->area;
 
-       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;
-
-                       /* Parse LSP, then fragment */
-                       parse_lsp(area, level, &srn, lsp);
-                       for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
-                               parse_lsp(area, level, &srn, frag);
-               }
-       }
+       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);
 }
 
 /**
- * Process any new/deleted/modified Prefix-SID in the LSPDB.
+ * Lookup for Prefix-SID in the local configuration.
  *
- * @param srn  Segment Routing Node
- * @param srp  Segment Routing Prefix
+ * @param area   IS-IS area
+ * @param prefix  Prefix to lookup
+ *
+ * @return       Configured Prefix-SID structure if found, NULL otherwise
  */
-static void process_prefix_changes(struct sr_node *srn, struct sr_prefix *srp)
+struct sr_prefix_cfg *isis_sr_cfg_prefix_find(struct isis_area *area,
+                                             union prefixconstptr prefix)
 {
-       struct isis_area *area = srn->area;
-
-       /* Install/reinstall/uninstall Prefix-SID if necessary. */
-       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;
-       }
+       struct sr_prefix_cfg pcfg = {};
 
-       /* Validate SRDB State for next LSPDB parsing */
-       srp->state = SRDB_STATE_VALIDATED;
+       prefix_copy(&pcfg.prefix, prefix.p);
+       return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
 }
 
 /**
- * Process any new/deleted/modified SRGB in the LSPDB.
+ * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
  *
- * @param area IS-IS area
- * @param level        IS-IS level
- * @param srn  Segment Routing Node
+ * @param pcfg     Prefix-SID configuration
+ * @param external  False if prefix is locally configured, true otherwise
+ * @param psid     Prefix-SID sub-TLV to be updated
  */
-static void process_node_changes(struct isis_area *area, int level,
-                                struct sr_node *srn)
+void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
+                              struct isis_prefix_sid *psid)
 {
-       struct sr_prefix *srp;
-       uint8_t sysid[ISIS_SYS_ID_LEN];
-       bool adjacent;
-
-       memcpy(sysid, srn->sysid, sizeof(sysid));
+       /* Set SID algorithm. */
+       psid->algorithm = SR_ALGORITHM_SPF;
 
-       /*
-        * 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_find(area, level, sysid);
-       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)
-                       sr_node_srgb_update(area, level, sysid);
+       /* Set SID flags. */
+       psid->flags = 0;
+       switch (pcfg->last_hop_behavior) {
+       case SR_LAST_HOP_BEHAVIOR_EXP_NULL:
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
                break;
-       case SRDB_STATE_UNCHANGED:
+       case SR_LAST_HOP_BEHAVIOR_NO_PHP:
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
+               break;
+       case SR_LAST_HOP_BEHAVIOR_PHP:
+               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+               UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
                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)
-                       sr_node_srgb_update(area, level, sysid);
-               return;
        }
+       if (external)
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED);
+       if (pcfg->node_sid)
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);
 
-       /* Validate SRDB State for next LSPDB parsing */
-       srn->state = SRDB_STATE_VALIDATED;
-
-       /* Finally, process all Prefix-SID of this SR Node */
-       frr_each_safe (srdb_node_prefix, &srn->prefix_sids, srp)
-               process_prefix_changes(srn, srp);
+       /* Set SID value. */
+       psid->value = pcfg->sid;
+       if (pcfg->sid_type == SR_SID_VALUE_TYPE_ABSOLUTE) {
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE);
+               SET_FLAG(psid->flags, ISIS_PREFIX_SID_LOCAL);
+       }
 }
 
 /**
@@ -1272,89 +466,6 @@ void isis_area_delete_backup_adj_sids(struct isis_area *area, int level)
                        sr_adj_sid_del(sra);
 }
 
-/**
- * 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;
-
-       if (!area->srdb.enabled)
-               return;
-
-       /* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
-       parse_lspdb(area);
-
-       /* Process possible SR-related changes in the LDPSB. */
-       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
-               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 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 = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
-               break;
-       case IS_LEVEL_2:
-               srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
-               break;
-       case IS_LEVEL_1_AND_2:
-               srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
-               if (!srp)
-                       srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
-               break;
-       default:
-               flog_err(EC_LIB_DEVELOPMENT, "%s: unknown area level",
-                        __func__);
-               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)) {
-               /*
-                * 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 {
-               sr_prefix_uninstall(srp);
-               srp->u.remote.rinfo = NULL;
-       }
-
-       return 0;
-}
-
 /* --- Segment Routing Local Block management functions --------------------- */
 
 /**
@@ -1588,7 +699,7 @@ void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
                        struct mpls_label_stack *label_stack;
 
                        label_stack = vadj->label_stack;
-                       adjinfo2nexthop(family, sra->backup_nexthops, adj,
+                       adjinfo2nexthop(family, sra->backup_nexthops, adj, NULL,
                                        label_stack);
                }
        }
@@ -1847,8 +958,6 @@ static int sr_if_new_hook(struct interface *ifp)
        return 0;
 }
 
-/* --- Segment Routing Show information functions --------------------------- */
-
 /**
  * Show LFIB operation in human readable format.
  *
@@ -1856,13 +965,11 @@ static int sr_if_new_hook(struct interface *ifp)
  * @param size       Size of the buffer
  * @param label_in    Input Label
  * @param label_out   Output Label
- * @param label_stack Output Label Stack (TI-LFA)
  *
  * @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,
-                      const struct mpls_label_stack *label_stack)
+char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
+               mpls_label_t label_out)
 {
        if (size < 24)
                return NULL;
@@ -1872,16 +979,6 @@ static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
                return buf;
        }
 
-       if (label_stack) {
-               char buf_labels[256];
-
-               mpls_label2str(label_stack->num_labels, &label_stack->label[0],
-                              buf_labels, sizeof(buf_labels), 1);
-
-               snprintf(buf, size, "Swap(%u, %s)", label_in, buf_labels);
-               return buf;
-       }
-
        switch (label_out) {
        case MPLS_LABEL_IMPLICIT_NULL:
                snprintf(buf, size, "Pop(%u)", label_in);
@@ -1900,215 +997,6 @@ static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
        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_oper[BUFSIZ];
-       char buf_iface[BUFSIZ];
-       char buf_uptime[BUFSIZ];
-
-       if (srnh->label != MPLS_INVALID_LABEL) {
-               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_iface, sizeof(buf_iface), "-");
-               snprintf(buf_uptime, sizeof(buf_uptime), "-");
-       }
-       sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
-                 MPLS_LABEL_IMPLICIT_NULL, NULL);
-
-       ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
-                      prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
-                      srp->sid.value, buf_oper, buf_iface, buf_uptime);
-}
-
-/**
- * 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, bool backup)
-{
-       struct isis_nexthop *nexthop;
-       struct listnode *node;
-       char buf_prefix[BUFSIZ];
-       char buf_oper[BUFSIZ];
-       char buf_nhop[BUFSIZ];
-       char buf_iface[BUFSIZ];
-       char buf_uptime[BUFSIZ];
-       bool first = true;
-       struct isis_route_info *rinfo;
-
-       (void)prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix));
-
-       rinfo = srp->u.remote.rinfo;
-       if (rinfo && backup)
-               rinfo = rinfo->backup;
-       if (!rinfo) {
-               ttable_add_row(tt, "%s|%u|%s|-|-|-", buf_prefix, srp->sid.value,
-                              sr_op2str(buf_oper, sizeof(buf_oper),
-                                        srp->input_label,
-                                        MPLS_LABEL_IMPLICIT_NULL, NULL));
-               return;
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
-               struct interface *ifp;
-
-               inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
-                         sizeof(buf_nhop));
-               ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
-               if (ifp)
-                       strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
-               else
-                       snprintf(buf_iface, sizeof(buf_iface), "ifindex %u",
-                                nexthop->ifindex);
-               if (nexthop->sr.label == MPLS_INVALID_LABEL)
-                       snprintf(buf_uptime, sizeof(buf_uptime), "-");
-               else
-                       log_uptime(nexthop->sr.uptime, buf_uptime,
-                                  sizeof(buf_uptime));
-               sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
-                         nexthop->sr.label, nexthop->label_stack);
-
-               if (first)
-                       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_oper, buf_nhop,
-                                      buf_iface, buf_uptime);
-               first = false;
-       }
-}
-
-/**
- * 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,
-                            bool backup)
-{
-       struct sr_prefix *srp;
-       struct ttable *tt;
-
-       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|Label Op.|Nexthop|Interface|Uptime");
-       tt->style.cell.rpad = 2;
-       tt->style.corner = '+';
-       ttable_restyle(tt);
-       ttable_rowseps(tt, 0, BOTTOM, true, '-');
-
-       /* 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:
-                       show_prefix_sid_local(vty, tt, area, srp);
-                       break;
-               case ISIS_SR_PREFIX_REMOTE:
-                       show_prefix_sid_remote(vty, tt, area, srp, backup);
-                       break;
-               }
-       }
-
-       /* 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);
-}
-
-/**
- * Declaration of new show commands.
- */
-DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
-      "show isis [vrf <NAME|all>] segment-routing prefix-sids [backup]",
-      SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
-      "All VRFs\n"
-      "Segment-Routing\n"
-      "Segment-Routing Prefix-SIDs\n"
-      "Show backup Prefix-SIDs\n")
-{
-       struct listnode *node, *inode;
-       struct isis_area *area;
-       struct isis *isis = NULL;
-       const char *vrf_name = VRF_DEFAULT_NAME;
-       bool all_vrf = false;
-       bool backup = false;
-       int idx = 0;
-
-       ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
-       if (argv_find(argv, argc, "backup", &idx))
-               backup = true;
-
-       if (vrf_name) {
-               if (all_vrf) {
-                       for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
-                               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_prefix_sids(vty, area,
-                                                                level, backup);
-                               }
-                       }
-                       return 0;
-               }
-               isis = isis_lookup_by_vrfname(vrf_name);
-               if (isis != NULL) {
-                       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_prefix_sids(vty, area, level,
-                                                        backup);
-                       }
-               }
-       }
-
-       return CMD_SUCCESS;
-}
-
 /**
  * Show Segment Routing Node.
  *
@@ -2118,13 +1006,10 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
  */
 static void show_node(struct vty *vty, struct isis_area *area, int level)
 {
-       struct sr_node *srn;
+       struct isis_lsp *lsp;
        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));
+       vty_out(vty, " IS-IS %s SR-Nodes:\n\n", circuit_t2string(level));
 
        /* Prepare table. */
        tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
@@ -2134,19 +1019,23 @@ static void show_node(struct vty *vty, struct isis_area *area, int level)
        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) {
+       frr_each (lspdb, &area->lspdb[level - 1], lsp) {
+               struct isis_router_cap *cap;
+
+               if (!lsp->tlvs)
+                       continue;
+               cap = lsp->tlvs->router_cap;
+               if (!cap)
+                       continue;
+
                ttable_add_row(
                        tt, "%s|%u - %u|%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.srlb.lower_bound,
-                       srn->cap.srlb.lower_bound + srn->cap.srlb.range_size
-                               - 1,
-                       srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF",
-                       srn->cap.msd);
+                       sysid_print(lsp->hdr.lsp_id), cap->srgb.lower_bound,
+                       cap->srgb.lower_bound + cap->srgb.range_size - 1,
+                       cap->srlb.lower_bound,
+                       cap->srlb.lower_bound + cap->srlb.range_size - 1,
+                       cap->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF",
+                       cap->msd);
        }
 
        /* Dump the generated table. */
@@ -2184,7 +1073,6 @@ DEFUN(show_sr_node, show_sr_node_cmd,
        return CMD_SUCCESS;
 }
 
-
 /* --- IS-IS Segment Routing Management function ---------------------------- */
 
 /**
@@ -2290,16 +1178,6 @@ void isis_sr_stop(struct isis_area *area)
        for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
                sr_adj_sid_del(sra);
 
-       /* Uninstall all Prefix-SIDs from all SR Node. */
-       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
-               while (srdb_node_count(&srdb->sr_nodes[level - 1]) > 0) {
-                       struct sr_node *srn;
-
-                       srn = srdb_node_first(&srdb->sr_nodes[level - 1]);
-                       sr_node_del(area, level, srn);
-               }
-       }
-
        /* Release SRGB if active. */
        if (srdb->srgb_active) {
                isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
@@ -2332,11 +1210,6 @@ void isis_sr_area_init(struct isis_area *area)
        memset(srdb, 0, sizeof(*srdb));
        srdb->adj_sids = list_new();
 
-       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
-               srdb_node_init(&srdb->sr_nodes[level - 1]);
-               srdb_area_prefix_init(&srdb->prefix_sids[level - 1]);
-       }
-
        /* Pull defaults from the YANG module. */
 #ifndef FABRICD
        srdb->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SR);
@@ -2386,14 +1259,12 @@ void isis_sr_area_term(struct isis_area *area)
  */
 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, 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);
 }
 
@@ -2406,6 +1277,5 @@ void isis_sr_term(void)
        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);
 }
index 2e4f3a69f79413a75d15c183c8f44b51f895b2e2..ce97b024afd1b7e238f0cd6e98b42a62b7245986 100644 (file)
 #define SRLB_UPPER_BOUND               15999
 
 /* 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)
 
+/*
+ * Segment Routing Prefix-SID information.
+ *
+ * This structure is intended to be embedded inside other structures that
+ * might or might not contain Prefix-SID information.
+ */
+struct isis_sr_psid_info {
+       /* Prefix-SID Sub-TLV information. */
+       struct isis_prefix_sid sid;
+
+       /* Resolved input/output label. */
+       mpls_label_t label;
+
+       /* Indicates whether the Prefix-SID is present or not. */
+       bool present;
+};
+
 /* Segment Routing Local Block allocation */
 struct sr_local_block {
        bool active;
@@ -106,85 +120,6 @@ struct sr_adjacency {
        struct isis_adjacency *adj;
 };
 
-/* Segment Routing Prefix-SID type. */
-enum sr_prefix_type {
-       ISIS_SR_PREFIX_LOCAL = 0,
-       ISIS_SR_PREFIX_REMOTE,
-};
-
-/* Segment Routing Nexthop Information. */
-struct sr_nexthop_info {
-       mpls_label_t label;
-       time_t uptime;
-};
-
-/* 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 {
-       /* 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 subTLVs. */
-       struct isis_prefix_sid sid;
-
-       /* Input label value. */
-       mpls_label_t input_label;
-
-       /* Prefix-SID type. */
-       enum sr_prefix_type type;
-       union {
-               struct {
-                       /* Information about this local Prefix-SID. */
-                       struct sr_nexthop_info info;
-               } local;
-               struct {
-                       /* Route associated to this remote Prefix-SID. */
-                       struct isis_route_info *rinfo;
-               } remote;
-       } u;
-
-       /* Backpointer to Segment Routing node. */
-       struct sr_node *srn;
-
-       /* SR-Prefix State used while the LSPDB is being parsed. */
-       enum srdb_state state;
-};
-
-/* Segment Routing node. */
-struct sr_node {
-       /* SRDB RB-tree entry. */
-       struct srdb_node_item entry;
-
-       /* IS-IS level: ISIS_LEVEL1 or ISIS_LEVEL2. */
-       int level;
-
-       /* IS-IS node identifier. */
-       uint8_t sysid[ISIS_SYS_ID_LEN];
-
-       /* Segment Routing node capabilities (SRGB, SR Algorithms) subTLVs. */
-       struct isis_router_cap cap;
-
-       /* List of Prefix-SIDs advertised by this node. */
-       struct srdb_node_prefix_head prefix_sids;
-
-       /* Backpointer to IS-IS area. */
-       struct isis_area *area;
-
-       /* SR-Node State used while the LSPDB is being parsed. */
-       enum srdb_state state;
-};
-
 /* SID type. NOTE: these values must be in sync with the YANG module. */
 enum sr_sid_value_type {
        SR_SID_VALUE_TYPE_INDEX = 0,
@@ -235,12 +170,6 @@ struct isis_sr_db {
        /* List of local Adjacency-SIDs. */
        struct list *adj_sids;
 
-       /* Segment Routing Node information per IS-IS level. */
-       struct srdb_node_head sr_nodes[ISIS_LEVELS];
-
-       /* Segment Routing Prefix-SIDs per IS-IS level. */
-       struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS];
-
        /* Management of SRLB & SRGB allocation */
        struct sr_local_block srlb;
        bool srgb_active;
@@ -267,6 +196,14 @@ struct isis_sr_db {
 };
 
 /* Prototypes. */
+extern struct isis_sr_block *isis_sr_find_srgb(struct lspdb_head *lspdb,
+                                              const uint8_t *sysid);
+extern mpls_label_t sr_prefix_in_label(struct isis_area *area,
+                                      struct isis_prefix_sid *psid,
+                                      bool local);
+extern mpls_label_t sr_prefix_out_label(struct lspdb_head *lspdb, int family,
+                                       struct isis_prefix_sid *psid,
+                                       const uint8_t *nh_sysid, bool last_hop);
 extern int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
                                   uint32_t upper_bound);
 extern int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound,
@@ -279,16 +216,14 @@ isis_sr_cfg_prefix_find(struct isis_area *area, union prefixconstptr prefix);
 extern void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg,
                                      bool external,
                                      struct isis_prefix_sid *psid);
-extern void isis_sr_nexthop_update(struct sr_nexthop_info *srnh,
-                                  mpls_label_t label);
-extern void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh);
 extern void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
                                  bool backup, struct list *nexthops);
 extern struct sr_adjacency *isis_sr_adj_sid_find(struct isis_adjacency *adj,
                                                 int family,
                                                 enum sr_adj_type type);
 extern void isis_area_delete_backup_adj_sids(struct isis_area *area, int level);
-extern void isis_area_verify_sr(struct isis_area *area);
+extern char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
+                      mpls_label_t label_out);
 extern int isis_sr_start(struct isis_area *area);
 extern void isis_sr_stop(struct isis_area *area);
 extern void isis_sr_area_init(struct isis_area *area);
index c1603d2ef07a3d382173182df57a75de27141d9d..a5c2fd5894ab4a5b538060616f1df056c39feeab 100644 (file)
@@ -2603,8 +2603,8 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
                sbuf_push(
                        buf, indent,
                        "  Segment Routing: I:%s V:%s, Global Block Base: %u Range: %u\n",
-                       IS_SR_IPV4(router_cap->srgb) ? "1" : "0",
-                       IS_SR_IPV6(router_cap->srgb) ? "1" : "0",
+                       IS_SR_IPV4(&router_cap->srgb) ? "1" : "0",
+                       IS_SR_IPV6(&router_cap->srgb) ? "1" : "0",
                        router_cap->srgb.lower_bound,
                        router_cap->srgb.range_size);
 
index 1c0d97f2c39684f99082a55010a9e78c84c50486..54ded8121d740a9c0b6b498bb421c8791d7a1f50 100644 (file)
@@ -138,8 +138,8 @@ struct isis_threeway_adj {
 /* 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)
-#define IS_SR_IPV6(srgb)               (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V)
+#define IS_SR_IPV4(srgb)               ((srgb)->flags & ISIS_SUBTLV_SRGB_FLAG_I)
+#define IS_SR_IPV6(srgb)               ((srgb)->flags & ISIS_SUBTLV_SRGB_FLAG_V)
 #define SUBTLV_SR_BLOCK_SIZE            6
 #define SUBTLV_RANGE_INDEX_SIZE         10
 #define SUBTLV_RANGE_LABEL_SIZE         9
index aeb54fce281fbfe44e98f6fff320842dfdd59b56..805ede1e44593c24e68f6f63f7405556e44c8762 100644 (file)
@@ -155,16 +155,14 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
 }
 
 enum isis_zebra_nexthop_type {
-       ISIS_ROUTE_NEXTHOP_MAIN = 0,
-       ISIS_ROUTE_NEXTHOP_BACKUP,
-       ISIS_MPLS_NEXTHOP_MAIN,
-       ISIS_MPLS_NEXTHOP_BACKUP,
+       ISIS_NEXTHOP_MAIN = 0,
+       ISIS_NEXTHOP_BACKUP,
 };
 
 static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
                                   struct zapi_nexthop zapi_nexthops[],
                                   enum isis_zebra_nexthop_type type,
-                                  uint8_t backup_nhs)
+                                  bool mpls_lsp, uint8_t backup_nhs)
 {
        struct isis_nexthop *nexthop;
        struct listnode *node;
@@ -210,23 +208,18 @@ static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
 
                /* Add MPLS label(s). */
                switch (type) {
-               case ISIS_ROUTE_NEXTHOP_MAIN:
-               case ISIS_ROUTE_NEXTHOP_BACKUP:
-                       /*
-                        * SR/TI-LFA labels are installed using separate
-                        * messages.
-                        */
-                       break;
-               case ISIS_MPLS_NEXTHOP_MAIN:
-                       if (nexthop->sr.label != MPLS_INVALID_LABEL) {
+               case ISIS_NEXTHOP_MAIN:
+                       if (nexthop->sr.present) {
                                api_nh->label_num = 1;
                                api_nh->labels[0] = nexthop->sr.label;
-                       } else {
-                               api_nh->label_num = 1;
-                               api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
-                       }
+                       } else if (mpls_lsp)
+                               /*
+                                * Do not use non-SR enabled nexthops to prevent
+                                * broken LSPs from being formed.
+                                */
+                               continue;
                        break;
-               case ISIS_MPLS_NEXTHOP_BACKUP:
+               case ISIS_NEXTHOP_BACKUP:
                        if (nexthop->label_stack) {
                                api_nh->label_num =
                                        nexthop->label_stack->num_labels;
@@ -234,7 +227,11 @@ static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
                                       nexthop->label_stack->label,
                                       sizeof(mpls_label_t)
                                               * api_nh->label_num);
-                       } else {
+                       } else if (mpls_lsp) {
+                               /*
+                                * This is necessary because zebra requires
+                                * the nexthops of MPLS LSPs to be labeled.
+                                */
                                api_nh->label_num = 1;
                                api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
                        }
@@ -266,7 +263,7 @@ void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
        struct zapi_route api;
        int count = 0;
 
-       if (zclient->sock < 0)
+       if (zclient->sock < 0 || list_isempty(route_info->nexthops))
                return;
 
        memset(&api, 0, sizeof(api));
@@ -286,7 +283,7 @@ void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
        if (route_info->backup) {
                count = isis_zebra_add_nexthops(
                        isis, route_info->backup->nexthops, api.backup_nexthops,
-                       ISIS_ROUTE_NEXTHOP_BACKUP, 0);
+                       ISIS_NEXTHOP_BACKUP, false, 0);
                if (count > 0) {
                        SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
                        api.backup_nexthop_num = count;
@@ -295,7 +292,7 @@ void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
 
        /* Add primary nexthops. */
        count = isis_zebra_add_nexthops(isis, route_info->nexthops,
-                                       api.nexthops, ISIS_ROUTE_NEXTHOP_MAIN,
+                                       api.nexthops, ISIS_NEXTHOP_MAIN, false,
                                        count);
        if (!count)
                return;
@@ -328,31 +325,39 @@ void isis_zebra_route_del_route(struct isis *isis,
 }
 
 /**
- * Install Prefix-SID in the forwarding plane through Zebra.
+ * Install Prefix-SID label entry in the forwarding plane through Zebra.
  *
- * @param srp  Segment Routing Prefix-SID
+ * @param area         IS-IS area
+ * @param prefix       Route prefix
+ * @param rinfo                Route information
+ * @param psid         Prefix-SID information
  */
-static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
+void isis_zebra_prefix_sid_install(struct isis_area *area,
+                                  struct prefix *prefix,
+                                  struct isis_route_info *rinfo,
+                                  struct isis_sr_psid_info *psid)
 {
-       struct isis *isis = srp->srn->area->isis;
        struct zapi_labels zl;
-       struct zapi_nexthop *znh;
-       struct interface *ifp;
-       struct isis_route_info *rinfo;
        int count = 0;
 
+       sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX",
+                area->area_tag, psid->label, prefix);
+
        /* Prepare message. */
        memset(&zl, 0, sizeof(zl));
        zl.type = ZEBRA_LSP_ISIS_SR;
-       zl.local_label = srp->input_label;
+       zl.local_label = psid->label;
+
+       /* Local routes don't have any nexthop and require special handling. */
+       if (list_isempty(rinfo->nexthops)) {
+               struct zapi_nexthop *znh;
+               struct interface *ifp;
 
-       switch (srp->type) {
-       case ISIS_SR_PREFIX_LOCAL:
                ifp = if_lookup_by_name("lo", VRF_DEFAULT);
                if (!ifp) {
                        zlog_warn(
                                "%s: couldn't install Prefix-SID %pFX: loopback interface not found",
-                               __func__, &srp->prefix);
+                               __func__, prefix);
                        return;
                }
 
@@ -361,21 +366,12 @@ static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
                znh->ifindex = ifp->ifindex;
                znh->label_num = 1;
                znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
-               break;
-       case ISIS_SR_PREFIX_REMOTE:
-               /* Update route in the RIB too. */
-               SET_FLAG(zl.message, ZAPI_LABELS_FTN);
-               zl.route.prefix = srp->prefix;
-               zl.route.type = ZEBRA_ROUTE_ISIS;
-               zl.route.instance = 0;
-
-               rinfo = srp->u.remote.rinfo;
-
+       } else {
                /* Add backup nexthops first. */
                if (rinfo->backup) {
                        count = isis_zebra_add_nexthops(
-                               isis, rinfo->backup->nexthops,
-                               zl.backup_nexthops, ISIS_MPLS_NEXTHOP_BACKUP,
+                               area->isis, rinfo->backup->nexthops,
+                               zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
                                0);
                        if (count > 0) {
                                SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
@@ -384,13 +380,12 @@ static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
                }
 
                /* Add primary nexthops. */
-               count = isis_zebra_add_nexthops(isis, rinfo->nexthops,
-                                               zl.nexthops,
-                                               ISIS_MPLS_NEXTHOP_MAIN, count);
+               count = isis_zebra_add_nexthops(area->isis, rinfo->nexthops,
+                                               zl.nexthops, ISIS_NEXTHOP_MAIN,
+                                               true, count);
                if (!count)
                        return;
                zl.nexthop_num = count;
-               break;
        }
 
        /* Send message to zebra. */
@@ -398,57 +393,32 @@ static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
 }
 
 /**
- * Uninstall Prefix-SID from the forwarding plane through Zebra.
+ * Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
  *
- * @param srp  Segment Routing Prefix-SID
+ * @param area         IS-IS area
+ * @param prefix       Route prefix
+ * @param rinfo                Route information
+ * @param psid         Prefix-SID information
  */
-static void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
+void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
+                                    struct prefix *prefix,
+                                    struct isis_route_info *rinfo,
+                                    struct isis_sr_psid_info *psid)
 {
        struct zapi_labels zl;
 
+       sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX",
+                area->area_tag, psid->label, prefix);
+
        /* Prepare message. */
        memset(&zl, 0, sizeof(zl));
        zl.type = ZEBRA_LSP_ISIS_SR;
-       zl.local_label = srp->input_label;
-
-       if (srp->type == ISIS_SR_PREFIX_REMOTE) {
-               /* Update route in the RIB too. */
-               SET_FLAG(zl.message, ZAPI_LABELS_FTN);
-               zl.route.prefix = srp->prefix;
-               zl.route.type = ZEBRA_ROUTE_ISIS;
-               zl.route.instance = 0;
-       }
+       zl.local_label = psid->label;
 
        /* Send message to zebra. */
        (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.
  *
@@ -490,7 +460,7 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
 
                count = isis_zebra_add_nexthops(isis, sra->backup_nexthops,
                                                zl.backup_nexthops,
-                                               ISIS_MPLS_NEXTHOP_BACKUP, 0);
+                                               ISIS_NEXTHOP_BACKUP, true, 0);
                if (count > 0) {
                        SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
                        zl.backup_nexthop_num = count;
index 768919ff466bae529e3681c7aeed64bc649e4291..c5c52a6bc6bd262deca9944cd3108d0e86bef968 100644 (file)
@@ -37,7 +37,6 @@ void isis_zebra_init(struct thread_master *master, int instance);
 void isis_zebra_stop(void);
 
 struct isis_route_info;
-struct sr_prefix;
 struct sr_adjacency;
 
 void isis_zebra_route_add_route(struct isis *isis,
@@ -48,7 +47,14 @@ void isis_zebra_route_del_route(struct isis *isis,
                                struct prefix *prefix,
                                struct prefix_ipv6 *src_p,
                                struct isis_route_info *route_info);
-void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp);
+void isis_zebra_prefix_sid_install(struct isis_area *area,
+                                  struct prefix *prefix,
+                                  struct isis_route_info *rinfo,
+                                  struct isis_sr_psid_info *psid);
+void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
+                                    struct prefix *prefix,
+                                    struct isis_route_info *rinfo,
+                                    struct isis_sr_psid_info *psid);
 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);
index 7ac8611bd95bf4c6a791858441289448ae901370..4c89a5be0a267663b79ef741a6fb5f513999e765 100644 (file)
@@ -66,7 +66,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology,
 
        /* Print the SPT and the corresponding routing table. */
        isis_print_spftree(vty, spftree);
-       isis_print_routes(vty, spftree, false);
+       isis_print_routes(vty, spftree, false, false);
 
        /* Cleanup SPF tree. */
        isis_spftree_del(spftree);
@@ -122,7 +122,7 @@ static void test_run_ti_lfa(struct vty *vty,
 
        /* Print the post-convergence SPT and the correspoding routing table. */
        isis_print_spftree(vty, spftree_pc);
-       isis_print_routes(vty, spftree_self, true);
+       isis_print_routes(vty, spftree_self, false, true);
 
        /* Cleanup everything. */
        isis_spftree_del(spftree_self);
index ea7cc14d7aecc91d976c079d4739fb6353cb54ed..0e6ee95686e4ca7be88d995811bba81cba279324 100644 (file)
@@ -18,14 +18,15 @@ rt6                  TE-IS        30     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
-                        -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -46,14 +47,15 @@ rt6                  TE-IS        30     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::2/128  20      -          rt2      -         \r
- 2001:db8::3/128  20      -          rt3      -         \r
- 2001:db8::4/128  30      -          rt2      -         \r
- 2001:db8::5/128  30      -          rt3      -         \r
- 2001:db8::6/128  40      -          rt2      -         \r
-                          -          rt3      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt2      16061          \r
+                          -          rt3      16061          \r
 \r
 test# test isis topology 2 root rt1 spf\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -76,14 +78,15 @@ rt3                  TE-IS        30     rt3                  -         rt1(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  25      -          rt2      -         \r
- 10.0.255.3/32  40      -          rt3      -         \r
- 10.0.255.4/32  20      -          rt4      -         \r
- 10.0.255.5/32  20      -          rt5      -         \r
- 10.0.255.6/32  30      -          rt4      -         \r
-                        -          rt5      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  25      -          rt2      implicit-null  \r
+ 10.0.255.3/32  40      -          rt3      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  20      -          rt5      implicit-null  \r
+ 10.0.255.6/32  30      -          rt4      16060          \r
+                        -          rt5      16060          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -105,14 +108,15 @@ rt3                  TE-IS        30     rt3                  -         rt1(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::2/128  25      -          rt2      -         \r
- 2001:db8::3/128  40      -          rt3      -         \r
- 2001:db8::4/128  20      -          rt4      -         \r
- 2001:db8::5/128  20      -          rt5      -         \r
- 2001:db8::6/128  30      -          rt4      -         \r
-                          -          rt5      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  25      -          rt2      implicit-null  \r
+ 2001:db8::3/128  40      -          rt3      implicit-null  \r
+ 2001:db8::4/128  20      -          rt4      implicit-null  \r
+ 2001:db8::5/128  20      -          rt5      implicit-null  \r
+ 2001:db8::6/128  30      -          rt4      16061          \r
+                          -          rt5      16061          \r
 \r
 test# test isis topology 3 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -132,13 +136,14 @@ rt6                  TE-IS        30     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  40      -          rt2      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  40      -          rt2      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
 \r
 test# test isis topology 4 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -162,15 +167,16 @@ rt8                  TE-IS        40     rt2                  -         rt6(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
- 10.0.255.7/32  40      -          rt3      -         \r
- 10.0.255.8/32  50      -          rt2      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
 \r
 test# test isis topology 5 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -196,16 +202,17 @@ rt8                  TE-IS        40     rt2                  -         rt6(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
- 10.0.255.7/32  40      -          rt3      -         \r
- 10.0.255.8/32  50      -          rt2      -         \r
-                        -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
+                        -          rt3      16080          \r
 \r
 test# test isis topology 6 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -239,20 +246,21 @@ rt7                  TE-IS        50     rt2                  -         rt5(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
-                        -          rt3      -         \r
- 10.0.255.5/32  50      -          rt2      -         \r
-                        -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
-                        -          rt3      -         \r
- 10.0.255.7/32  60      -          rt2      -         \r
-                        -          rt3      -         \r
- 10.0.255.8/32  50      -          rt2      -         \r
-                        -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+                        -          rt3      16040          \r
+ 10.0.255.5/32  50      -          rt2      16050          \r
+                        -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
+ 10.0.255.7/32  60      -          rt2      16070          \r
+                        -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
+                        -          rt3      16080          \r
 \r
 test# test isis topology 7 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -287,19 +295,20 @@ rt12                 TE-IS        50     rt4                  -         rt9(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix          Metric  Interface  Nexthop  Label(s)  \r
- ------------------------------------------------------\r
- 10.0.255.2/32   40      -          rt4      -         \r
- 10.0.255.3/32   50      -          rt4      -         \r
- 10.0.255.4/32   20      -          rt4      -         \r
- 10.0.255.5/32   30      -          rt4      -         \r
- 10.0.255.6/32   40      -          rt4      -         \r
- 10.0.255.7/32   30      -          rt4      -         \r
- 10.0.255.8/32   40      -          rt4      -         \r
- 10.0.255.9/32   50      -          rt4      -         \r
- 10.0.255.10/32  50      -          rt4      -         \r
- 10.0.255.11/32  50      -          rt4      -         \r
- 10.0.255.12/32  60      -          rt4      -         \r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   0       -          -        -              \r
+ 10.0.255.2/32   40      -          rt4      16020          \r
+ 10.0.255.3/32   50      -          rt4      16030          \r
+ 10.0.255.4/32   20      -          rt4      implicit-null  \r
+ 10.0.255.5/32   30      -          rt4      16050          \r
+ 10.0.255.6/32   40      -          rt4      16060          \r
+ 10.0.255.7/32   30      -          rt4      16070          \r
+ 10.0.255.8/32   40      -          rt4      16080          \r
+ 10.0.255.9/32   50      -          rt4      16090          \r
+ 10.0.255.10/32  50      -          rt4      16100          \r
+ 10.0.255.11/32  50      -          rt4      16110          \r
+ 10.0.255.12/32  60      -          rt4      16120          \r
 \r
 test# test isis topology 8 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -333,19 +342,20 @@ rt12                 TE-IS        50     rt2                  -         rt9(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix          Metric  Interface  Nexthop  Label(s)  \r
- ------------------------------------------------------\r
- 10.0.255.2/32   20      -          rt2      -         \r
- 10.0.255.3/32   30      -          rt2      -         \r
- 10.0.255.4/32   20      -          rt4      -         \r
- 10.0.255.5/32   30      -          rt2      -         \r
- 10.0.255.6/32   40      -          rt2      -         \r
- 10.0.255.7/32   30      -          rt4      -         \r
- 10.0.255.8/32   40      -          rt2      -         \r
- 10.0.255.9/32   50      -          rt2      -         \r
- 10.0.255.10/32  40      -          rt4      -         \r
- 10.0.255.11/32  50      -          rt2      -         \r
- 10.0.255.12/32  60      -          rt2      -         \r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   0       -          -        -              \r
+ 10.0.255.2/32   20      -          rt2      implicit-null  \r
+ 10.0.255.3/32   30      -          rt2      16030          \r
+ 10.0.255.4/32   20      -          rt4      implicit-null  \r
+ 10.0.255.5/32   30      -          rt2      16050          \r
+ 10.0.255.6/32   40      -          rt2      16060          \r
+ 10.0.255.7/32   30      -          rt4      16070          \r
+ 10.0.255.8/32   40      -          rt2      16080          \r
+ 10.0.255.9/32   50      -          rt2      16090          \r
+ 10.0.255.10/32  40      -          rt4      16100          \r
+ 10.0.255.11/32  50      -          rt2      16110          \r
+ 10.0.255.12/32  60      -          rt2      16120          \r
 \r
 test# test isis topology 9 root rt1 spf\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -374,16 +384,17 @@ rt8                  TE-IS        50     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  40      -          rt2      -         \r
- 10.0.255.6/32  60      -          rt2      -         \r
- 10.0.255.7/32  60      -          rt2      -         \r
- 10.0.255.8/32  60      -          rt2      -         \r
- 10.0.255.9/32  50      -          rt2      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  40      -          rt2      16050          \r
+ 10.0.255.6/32  60      -          rt2      16060          \r
+ 10.0.255.7/32  60      -          rt2      16070          \r
+ 10.0.255.8/32  60      -          rt2      16080          \r
+ 10.0.255.9/32  50      -          rt2      16090          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -411,16 +422,17 @@ rt8                  TE-IS        50     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::2/128  20      -          rt2      -         \r
- 2001:db8::3/128  20      -          rt3      -         \r
- 2001:db8::4/128  30      -          rt2      -         \r
- 2001:db8::5/128  40      -          rt2      -         \r
- 2001:db8::6/128  60      -          rt2      -         \r
- 2001:db8::7/128  60      -          rt2      -         \r
- 2001:db8::8/128  60      -          rt2      -         \r
- 2001:db8::9/128  50      -          rt2      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  40      -          rt2      16051          \r
+ 2001:db8::6/128  60      -          rt2      16061          \r
+ 2001:db8::7/128  60      -          rt2      16071          \r
+ 2001:db8::8/128  60      -          rt2      16081          \r
+ 2001:db8::9/128  50      -          rt2      16091          \r
 \r
 test# test isis topology 10 root rt1 spf\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -444,15 +456,16 @@ rt8                  TE-IS        30     rt2                  -         rt5(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  30      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt4      -         \r
- 10.0.255.5/32  30      -          rt2      -         \r
- 10.0.255.6/32  40      -          rt3      -         \r
- 10.0.255.7/32  40      -          rt4      -         \r
- 10.0.255.8/32  40      -          rt2      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  30      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt4      implicit-null  \r
+ 10.0.255.5/32  30      -          rt2      16050          \r
+ 10.0.255.6/32  40      -          rt3      20060          \r
+ 10.0.255.7/32  40      -          rt4      16070          \r
+ 10.0.255.8/32  40      -          rt2      16080          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -475,15 +488,16 @@ rt8                  TE-IS        30     rt2                  -         rt5(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::2/128  20      -          rt2      -         \r
- 2001:db8::3/128  30      -          rt3      -         \r
- 2001:db8::4/128  30      -          rt4      -         \r
- 2001:db8::5/128  30      -          rt2      -         \r
- 2001:db8::6/128  40      -          rt3      -         \r
- 2001:db8::7/128  40      -          rt4      -         \r
- 2001:db8::8/128  40      -          rt2      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  30      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt4      implicit-null  \r
+ 2001:db8::5/128  30      -          rt2      16051          \r
+ 2001:db8::6/128  40      -          rt3      20061          \r
+ 2001:db8::7/128  40      -          rt4      16071          \r
+ 2001:db8::8/128  40      -          rt2      16081          \r
 \r
 test# test isis topology 11 root rt1 spf\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -506,14 +520,15 @@ rt6                  TE-IS        30     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
-                        -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -535,14 +550,15 @@ rt6                  TE-IS        30     rt2                  -         rt4(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::2/128  20      -          rt2      -         \r
- 2001:db8::3/128  20      -          rt3      -         \r
- 2001:db8::4/128  30      -          rt2      -         \r
- 2001:db8::5/128  30      -          rt3      -         \r
- 2001:db8::6/128  40      -          rt2      -         \r
-                          -          rt3      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt2      16061          \r
+                          -          rt3      16061          \r
 \r
 test# test isis topology 12 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -570,17 +586,18 @@ rt10                 TE-IS        50     rt2                  -         rt8(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix          Metric  Interface  Nexthop  Label(s)  \r
- ------------------------------------------------------\r
- 10.0.255.2/32   20      -          rt2      -         \r
- 10.0.255.3/32   20      -          rt3      -         \r
- 10.0.255.4/32   30      -          rt2      -         \r
- 10.0.255.5/32   30      -          rt3      -         \r
- 10.0.255.6/32   40      -          rt2      -         \r
- 10.0.255.7/32   40      -          rt3      -         \r
- 10.0.255.8/32   50      -          rt2      -         \r
- 10.0.255.9/32   50      -          rt3      -         \r
- 10.0.255.10/32  60      -          rt2      -         \r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   0       -          -        -              \r
+ 10.0.255.2/32   20      -          rt2      implicit-null  \r
+ 10.0.255.3/32   20      -          rt3      implicit-null  \r
+ 10.0.255.4/32   30      -          rt2      16040          \r
+ 10.0.255.5/32   30      -          rt3      16050          \r
+ 10.0.255.6/32   40      -          rt2      16060          \r
+ 10.0.255.7/32   40      -          rt3      16070          \r
+ 10.0.255.8/32   50      -          rt2      16080          \r
+ 10.0.255.9/32   50      -          rt3      16090          \r
+ 10.0.255.10/32  60      -          rt2      16100          \r
 \r
 test# test isis topology 13 root rt1 spf ipv4-only\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -605,15 +622,16 @@ rt7                  TE-IS        30     rt3                  -         rt5(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
-                        -          rt3      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  30      -          rt3      -         \r
- 10.0.255.7/32  40      -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+                        -          rt3      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  30      -          rt3      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
 \r
 test# \r
 test# test isis topology 4 root rt1 reverse-spf ipv4-only\r
@@ -638,15 +656,16 @@ rt8                  TE-IS        40     rt2                  -         rt6(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt2      -         \r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.4/32  30      -          rt2      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt2      -         \r
- 10.0.255.7/32  40      -          rt3      -         \r
- 10.0.255.8/32  50      -          rt2      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
 \r
 test# test isis topology 11 root rt1 reverse-spf\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -668,11 +687,12 @@ rt6                  TE-IS        30     rt3                  -         rt4(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.3/32  20      -          rt3      -         \r
- 10.0.255.5/32  30      -          rt3      -         \r
- 10.0.255.6/32  40      -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt3      16060          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -693,11 +713,12 @@ rt6                  TE-IS        30     rt3                  -         rt4(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::3/128  20      -          rt3      -         \r
- 2001:db8::5/128  30      -          rt3      -         \r
- 2001:db8::6/128  40      -          rt3      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt3      16061          \r
 \r
 test# \r
 test# test isis topology 1 root rt1 ti-lfa system-id rt2\r
@@ -996,7 +1017,7 @@ IS-IS L1 IPv4 routing table:
  -----------------------------------------------------\r
  10.0.255.1/32  40      -          rt6      16040     \r
  10.0.255.2/32  55      -          rt6      16040     \r
- 10.0.255.4/32  30      -          rt6      -         \r
+ 10.0.255.4/32  30      -          rt6      16040     \r
 \r
 P-space (self):\r
  rt6\r
@@ -1040,7 +1061,7 @@ IS-IS L1 IPv6 routing table:
  -------------------------------------------------------\r
  2001:db8::1/128  40      -          rt6      16041     \r
  2001:db8::2/128  55      -          rt6      16041     \r
- 2001:db8::4/128  30      -          rt6      -         \r
+ 2001:db8::4/128  30      -          rt6      16041     \r
 \r
 test# test isis topology 3 root rt5 ti-lfa system-id rt4 ipv4-only\r
 P-space (self):\r
@@ -1088,10 +1109,10 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.1/32  50      -          rt3      -         \r
-                        -          rt6      -         \r
- 10.0.255.2/32  40      -          rt6      -         \r
- 10.0.255.4/32  30      -          rt6      -         \r
+ 10.0.255.1/32  50      -          rt3      16010     \r
+                        -          rt6      16010     \r
+ 10.0.255.2/32  40      -          rt6      16020     \r
+ 10.0.255.4/32  30      -          rt6      16040     \r
 \r
 test# test isis topology 3 root rt5 ti-lfa system-id rt3 ipv4-only\r
 P-space (self):\r
@@ -1380,13 +1401,13 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.1/32  60      -          rt10     -         \r
+ 10.0.255.1/32  60      -          rt10     16010     \r
  10.0.255.2/32  60      -          rt12     16090     \r
  10.0.255.3/32  70      -          rt12     16090     \r
- 10.0.255.4/32  50      -          rt10     -         \r
+ 10.0.255.4/32  50      -          rt10     16040     \r
  10.0.255.5/32  50      -          rt12     16090     \r
  10.0.255.6/32  60      -          rt12     16090     \r
- 10.0.255.7/32  40      -          rt10     -         \r
+ 10.0.255.7/32  40      -          rt10     16070     \r
  10.0.255.8/32  40      -          rt12     16090     \r
 \r
 test# test isis topology 7 root rt6 ti-lfa system-id rt5 ipv4-only\r
@@ -1463,14 +1484,14 @@ IS-IS L1 IPv4 routing table:
  10.0.255.1/32   60      -          rt3      16020     \r
  10.0.255.4/32   50      -          rt3      16020     \r
  10.0.255.5/32   40      -          rt3      16020     \r
- 10.0.255.7/32   60      -          rt9      -         \r
-                         -          rt3      -         \r
- 10.0.255.8/32   50      -          rt9      -         \r
-                         -          rt3      -         \r
- 10.0.255.10/32  70      -          rt9      -         \r
-                         -          rt3      -         \r
- 10.0.255.11/32  60      -          rt9      -         \r
-                         -          rt3      -         \r
+ 10.0.255.7/32   60      -          rt9      16070     \r
+                         -          rt3      16070     \r
+ 10.0.255.8/32   50      -          rt9      16080     \r
+                         -          rt3      16080     \r
+ 10.0.255.10/32  70      -          rt9      16100     \r
+                         -          rt3      16100     \r
+ 10.0.255.11/32  60      -          rt9      16110     \r
+                         -          rt3      16110     \r
 \r
 test# test isis topology 8 root rt2 ti-lfa system-id rt1 ipv4-only\r
 P-space (self):\r
@@ -2322,13 +2343,13 @@ rt6                  TE-IS        70     rt3                  -         rt5(4)
 \r
 IS-IS L1 IPv4 routing table:\r
 \r
- Prefix         Metric  Interface  Nexthop  Label(s)  \r
- -----------------------------------------------------\r
- 10.0.255.1/32  60      -          rt1      -         \r
- 10.0.255.3/32  60      -          rt3      -         \r
- 10.0.255.4/32  80      -          rt3      16050     \r
- 10.0.255.5/32  70      -          rt3      -         \r
- 10.0.255.6/32  80      -          rt3      -         \r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  60      -          rt1      implicit-null  \r
+ 10.0.255.3/32  60      -          rt3      implicit-null  \r
+ 10.0.255.4/32  80      -          rt3      16050          \r
+ 10.0.255.5/32  70      -          rt3      16050          \r
+ 10.0.255.6/32  80      -          rt3      16060          \r
 \r
 P-space (self):\r
 \r
@@ -2368,13 +2389,13 @@ rt6                  TE-IS        70     rt3                  -         rt5(4)
 \r
 IS-IS L1 IPv6 routing table:\r
 \r
- Prefix           Metric  Interface  Nexthop  Label(s)  \r
- -------------------------------------------------------\r
- 2001:db8::1/128  60      -          rt1      -         \r
- 2001:db8::3/128  60      -          rt3      -         \r
- 2001:db8::4/128  80      -          rt3      16051     \r
- 2001:db8::5/128  70      -          rt3      -         \r
- 2001:db8::6/128  80      -          rt3      -         \r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  60      -          rt1      implicit-null  \r
+ 2001:db8::3/128  60      -          rt3      implicit-null  \r
+ 2001:db8::4/128  80      -          rt3      16051          \r
+ 2001:db8::5/128  70      -          rt3      16051          \r
+ 2001:db8::6/128  80      -          rt3      16061          \r
 \r
 test# test isis topology 12 root rt1 ti-lfa system-id rt3 ipv4-only\r
 P-space (self):\r