isisd: add support for Topology Independent LFA (TI-LFA)

TI-LFA is a modern fast-reroute (FRR) solution that leverages Segment
Routing to pre-compute backup nexthops for all destinations in the
network, helping to reduce traffic restoration times whenever a
failure occurs. The backup nexthops are expected to be installed
in the FIB so that they can be activated as soon as a failure
is detected, making sub-50ms recovery possible (assuming an
hierarchical FIB).

TI-LFA is a huge step forward compared to prior IP-FRR solutions,
like classic LFA and Remote LFA, as it guarantees 100% coverage
for all destinations. This is possible thanks to the source routing
capabilities of SR, which allows the backup nexthops to steer traffic
around the failures (using as many SIDs as necessary). In addition
to that, the repair paths always follow the post-convergence SPF
tree, which prevents transient congestions and suboptimal routing
from happening.

Deploying TI-LFA is very simple as it only requires a single
configuration command for each interface that needs to be protected
(both link protection and node protection are available). In addition
to IPv4 and IPv6 routes, SR Prefix-SIDs and Adj-SIDs are also
protected by the backup nexthops computed by the TI-LFA algorithms.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2020-08-20 19:55:42 -03:00
parent ed5d703279
commit c951ee6eee
16 changed files with 1704 additions and 153 deletions

View File

@ -141,6 +141,8 @@ struct isis_circuit {
bool disable_threeway_adj;
struct bfd_info *bfd_info;
struct ldp_sync_info *ldp_sync_info;
bool tilfa_protection[ISIS_LEVELS];
bool tilfa_node_protection[ISIS_LEVELS];
/*
* Counters as in 10589--11.2.5.9
*/

1087
isisd/isis_lfa.c Normal file

File diff suppressed because it is too large Load Diff

101
isisd/isis_lfa.h Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
* Renato Westphal
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_ISIS_LFA_H
#define _FRR_ISIS_LFA_H
enum isis_tilfa_sid_type {
TILFA_SID_PREFIX = 1,
TILFA_SID_ADJ,
};
struct isis_tilfa_sid {
enum isis_tilfa_sid_type type;
union {
uint32_t index;
mpls_label_t label;
} value;
};
RB_HEAD(isis_spf_nodes, isis_spf_node);
RB_PROTOTYPE(isis_spf_nodes, isis_spf_node, entry, isis_spf_node_compare)
struct isis_spf_node {
RB_ENTRY(isis_spf_node) entry;
/* Node's System ID. */
uint8_t sysid[ISIS_SYS_ID_LEN];
/* Local adjacencies over which this node is reachable. */
struct list *adjacencies;
/* Best metric of all adjacencies used to reach this node. */
uint32_t best_metric;
struct {
/* Node's forward SPT. */
struct isis_spftree *spftree;
/* Node's reverse SPT. */
struct isis_spftree *spftree_reverse;
/* Node's P-space. */
struct isis_spf_nodes p_space;
} lfa;
};
enum lfa_protection_type {
LFA_LINK_PROTECTION = 1,
LFA_NODE_PROTECTION,
};
struct lfa_protected_resource {
/* The protection type. */
enum lfa_protection_type type;
/* The protected adjacency (might be a pseudonode). */
uint8_t adjacency[ISIS_SYS_ID_LEN + 1];
/* List of nodes reachable over the protected interface. */
struct isis_spf_nodes nodes;
};
/* Forward declaration(s). */
struct isis_vertex;
/* Prototypes. */
void isis_spf_node_list_init(struct isis_spf_nodes *nodes);
void isis_spf_node_list_clear(struct isis_spf_nodes *nodes);
struct isis_spf_node *isis_spf_node_new(struct isis_spf_nodes *nodes,
const uint8_t *sysid);
struct isis_spf_node *isis_spf_node_find(const struct isis_spf_nodes *nodes,
const uint8_t *sysid);
bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree,
const uint8_t *id);
bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
const uint8_t *id);
struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree);
int isis_spf_run_neighbors(struct isis_spftree *spftree);
void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree);
int isis_lfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
struct isis_spftree *
isis_tilfa_compute(struct isis_area *area, struct isis_spftree *spftree,
struct isis_spftree *spftree_reverse,
struct lfa_protected_resource *protected_resource);
#endif /* _FRR_ISIS_LFA_H */

View File

@ -39,6 +39,7 @@ DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree")
DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex")
DEFINE_MTYPE(ISISD, ISIS_ROUTE_INFO, "ISIS route info")
DEFINE_MTYPE(ISISD, ISIS_NEXTHOP, "ISIS nexthop")
DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels")
DEFINE_MTYPE(ISISD, ISIS_DICT, "ISIS dictionary")
DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node")
DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")

View File

@ -38,6 +38,7 @@ DECLARE_MTYPE(ISIS_SPFTREE)
DECLARE_MTYPE(ISIS_VERTEX)
DECLARE_MTYPE(ISIS_ROUTE_INFO)
DECLARE_MTYPE(ISIS_NEXTHOP)
DECLARE_MTYPE(ISIS_NEXTHOP_LABELS)
DECLARE_MTYPE(ISIS_DICT)
DECLARE_MTYPE(ISIS_DICT_NODE)
DECLARE_MTYPE(ISIS_EXT_ROUTE)

View File

@ -43,6 +43,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_spf_private.h"
#include "isisd/isis_te.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_mt.h"
@ -2945,15 +2946,24 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
struct isis_area *area;
struct isis_circuit *circuit;
if (args->event != NB_EV_APPLY)
return NB_OK;
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
if (circuit->tilfa_protection[0])
circuit->area->lfa_protected_links[0]++;
else {
assert(circuit->area->lfa_protected_links[0] > 0);
circuit->area->lfa_protected_links[0]--;
}
area = circuit->area;
lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@ -2964,14 +2974,18 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
}
struct isis_area *area;
struct isis_circuit *circuit;
if (args->event != NB_EV_APPLY)
return NB_OK;
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_node_protection[0] =
yang_dnode_get_bool(args->dnode, NULL);
area = circuit->area;
lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@ -2983,15 +2997,24 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
struct isis_area *area;
struct isis_circuit *circuit;
if (args->event != NB_EV_APPLY)
return NB_OK;
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
if (circuit->tilfa_protection[1])
circuit->area->lfa_protected_links[1]++;
else {
assert(circuit->area->lfa_protected_links[1] > 0);
circuit->area->lfa_protected_links[1]--;
}
area = circuit->area;
lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@ -3002,14 +3025,18 @@ int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
}
struct isis_area *area;
struct isis_circuit *circuit;
if (args->event != NB_EV_APPLY)
return NB_OK;
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_node_protection[1] =
yang_dnode_get_bool(args->dnode, NULL);
area = circuit->area;
lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}

View File

@ -76,8 +76,9 @@ static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
return nexthop;
}
static void isis_nexthop_delete(struct isis_nexthop *nexthop)
void isis_nexthop_delete(struct isis_nexthop *nexthop)
{
XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
}
@ -115,8 +116,9 @@ static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
return NULL;
}
static void adjinfo2nexthop(int family, struct list *nexthops,
struct isis_adjacency *adj)
void adjinfo2nexthop(int family, struct list *nexthops,
struct isis_adjacency *adj,
struct mpls_label_stack *label_stack)
{
struct isis_nexthop *nh;
union g_addr ip = {};
@ -132,6 +134,7 @@ static void adjinfo2nexthop(int family, struct list *nexthops,
AF_INET, &ip,
adj->circuit->interface->ifindex);
memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
nh->label_stack = label_stack;
listnode_add(nexthops, nh);
break;
}
@ -147,6 +150,7 @@ static void adjinfo2nexthop(int family, struct list *nexthops,
AF_INET6, &ip,
adj->circuit->interface->ifindex);
memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
nh->label_stack = label_stack;
listnode_add(nexthops, nh);
break;
}
@ -160,13 +164,15 @@ static void adjinfo2nexthop(int family, struct list *nexthops,
}
static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
const uint8_t *sysid)
const uint8_t *sysid,
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->label_stack = label_stack;
listnode_add(rinfo->nexthops, nh);
}
@ -186,13 +192,15 @@ 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 mpls_label_stack *label_stack = vadj->label_stack;
/*
* Create dummy nexthops when running SPF on a testing
* 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,
label_stack);
continue;
}
@ -219,7 +227,8 @@ 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,
label_stack);
}
rinfo->cost = cost;
@ -239,6 +248,12 @@ static void isis_route_info_delete(struct isis_route_info *route_info)
XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
}
void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
{
if (node->info)
isis_route_info_delete(node->info);
}
static int isis_route_info_same(struct isis_route_info *new,
struct isis_route_info *old, char *buf,
size_t buf_size)
@ -412,6 +427,7 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
static void _isis_route_verify_table(struct isis_area *area,
struct route_table *table,
struct route_table *table_backup,
struct route_table **tables)
{
struct route_node *rnode, *drnode;
@ -433,6 +449,19 @@ static void _isis_route_verify_table(struct isis_area *area,
(const struct prefix **)&dst_p,
(const struct prefix **)&src_p);
/* Link primary route to backup route. */
if (table_backup) {
struct route_node *rnode_bck;
rnode_bck = srcdest_rnode_lookup(table_backup, dst_p,
src_p);
if (rnode_bck) {
rinfo->backup = rnode_bck->info;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
}
#ifdef EXTREME_DEBUG
if (IS_DEBUG_RTE_EVENTS) {
srcdest2str(dst_p, src_p, buff, sizeof(buff));
@ -490,9 +519,10 @@ static void _isis_route_verify_table(struct isis_area *area,
}
}
void isis_route_verify_table(struct isis_area *area, struct route_table *table)
void isis_route_verify_table(struct isis_area *area, struct route_table *table,
struct route_table *table_backup)
{
_isis_route_verify_table(area, table, NULL);
_isis_route_verify_table(area, table, table_backup, NULL);
}
/* Function to validate route tables for L1L2 areas. In this case we can't use
@ -507,9 +537,13 @@ void isis_route_verify_table(struct isis_area *area, struct route_table *table)
* to the RIB with different zebra route types and let RIB handle this? */
void isis_route_verify_merge(struct isis_area *area,
struct route_table *level1_table,
struct route_table *level2_table)
struct route_table *level1_table_backup,
struct route_table *level2_table,
struct route_table *level2_table_backup)
{
struct route_table *tables[] = { level1_table, level2_table };
struct route_table *tables[] = {level1_table, level2_table};
struct route_table *tables_backup[] = {level1_table_backup,
level2_table_backup};
struct route_table *merge;
struct route_node *rnode, *mrnode;
@ -519,6 +553,8 @@ void isis_route_verify_merge(struct isis_area *area,
for (rnode = route_top(tables[level - 1]); rnode;
rnode = srcdest_route_next(rnode)) {
struct isis_route_info *rinfo = rnode->info;
struct route_node *rnode_bck;
if (!rinfo)
continue;
@ -528,6 +564,16 @@ void isis_route_verify_merge(struct isis_area *area,
srcdest_rnode_prefixes(rnode,
(const struct prefix **)&prefix,
(const struct prefix **)&src_p);
/* Link primary route to backup route. */
rnode_bck = srcdest_rnode_lookup(
tables_backup[level - 1], prefix, src_p);
if (rnode_bck) {
rinfo->backup = rnode_bck->info;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
mrnode = srcdest_rnode_get(merge, prefix, src_p);
struct isis_route_info *mrinfo = mrnode->info;
if (mrinfo) {
@ -566,7 +612,7 @@ void isis_route_verify_merge(struct isis_area *area,
}
}
_isis_route_verify_table(area, merge, tables);
_isis_route_verify_table(area, merge, NULL, tables);
route_table_finish(merge);
}
@ -580,6 +626,14 @@ void isis_route_invalidate_table(struct isis_area *area,
continue;
rinfo = rode->info;
if (rinfo->backup) {
rinfo->backup = NULL;
/*
* For now, always force routes that have backup
* nexthops to be reinstalled.
*/
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
}
}

View File

@ -33,6 +33,7 @@ struct isis_nexthop {
union g_addr ip;
uint8_t sysid[ISIS_SYS_ID_LEN];
struct sr_nexthop_info sr;
struct mpls_label_stack *label_stack;
};
struct isis_route_info {
@ -43,6 +44,7 @@ struct isis_route_info {
uint32_t cost;
uint32_t depth;
struct list *nexthops;
struct isis_route_info *backup;
};
DECLARE_HOOK(isis_route_update_hook,
@ -50,6 +52,10 @@ DECLARE_HOOK(isis_route_update_hook,
struct isis_route_info *route_info),
(area, prefix, route_info))
void isis_nexthop_delete(struct isis_nexthop *nexthop);
void adjinfo2nexthop(int family, struct list *nexthops,
struct isis_adjacency *adj,
struct mpls_label_stack *label_stack);
struct isis_route_info *isis_route_create(struct prefix *prefix,
struct prefix_ipv6 *src_p,
uint32_t cost,
@ -60,16 +66,22 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
/* Walk the given table and install new routes to zebra and remove old ones.
* route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
void isis_route_verify_table(struct isis_area *area,
struct route_table *table);
void isis_route_verify_table(struct isis_area *area, struct route_table *table,
struct route_table *table_backup);
/* Same as isis_route_verify_table, but merge L1 and L2 routes before */
void isis_route_verify_merge(struct isis_area *area,
struct route_table *level1_table,
struct route_table *level2_table);
struct route_table *level1_table_backup,
struct route_table *level2_table,
struct route_table *level2_table_backup);
/* Unset ISIS_ROUTE_FLAG_ACTIVE on all routes. Used before running spf. */
void isis_route_invalidate_table(struct isis_area *area,
struct route_table *table);
/* Cleanup route node when freeing routing table. */
void isis_route_node_cleanup(struct route_table *table,
struct route_node *node);
#endif /* _ZEBRA_ISIS_ROUTE_H */

View File

@ -138,7 +138,7 @@ static void remove_excess_adjs(struct list *adjs)
return;
}
static const char *vtype2string(enum vertextype vtype)
const char *vtype2string(enum vertextype vtype)
{
switch (vtype) {
case VTYPE_PSEUDO_IS:
@ -167,7 +167,7 @@ static const char *vtype2string(enum vertextype vtype)
return NULL; /* Not reached */
}
const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
const char *vid2string(const struct isis_vertex *vertex, char *buff, int size)
{
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
const char *hostname = print_sys_hostname(vertex->N.id);
@ -286,6 +286,9 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
tree->route_table = srcdest_table_init();
tree->route_table->cleanup = isis_route_node_cleanup;
tree->route_table_backup = srcdest_table_init();
tree->route_table_backup->cleanup = isis_route_node_cleanup;
tree->area = area;
tree->lspdb = lspdb;
tree->sadj_list = list_new();
@ -300,16 +303,26 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
tree->tree_id = tree_id;
tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
tree->flags = flags;
if (tree->type == SPF_TYPE_TI_LFA) {
isis_spf_node_list_init(&tree->lfa.p_space);
isis_spf_node_list_init(&tree->lfa.q_space);
}
return tree;
}
void isis_spftree_del(struct isis_spftree *spftree)
{
if (spftree->type == SPF_TYPE_TI_LFA) {
isis_spf_node_list_clear(&spftree->lfa.q_space);
isis_spf_node_list_clear(&spftree->lfa.p_space);
}
isis_spf_node_list_clear(&spftree->adj_nodes);
list_delete(&spftree->sadj_list);
isis_vertex_queue_free(&spftree->tents);
isis_vertex_queue_free(&spftree->paths);
route_table_finish(spftree->route_table);
route_table_finish(spftree->route_table_backup);
spftree->route_table = NULL;
XFREE(MTYPE_ISIS_SPFTREE, spftree);
@ -389,8 +402,8 @@ static int spf_adj_state_change(struct isis_adjacency *adj)
* Find the system LSP: returns the LSP in our LSP database
* associated with the given system ID.
*/
static struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb,
uint8_t *sysid)
struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb,
const uint8_t *sysid)
{
struct isis_lsp *lsp;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
@ -663,6 +676,13 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
struct isis_mt_router_info *mt_router_info = NULL;
struct prefix_pair ip_info;
if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) {
if (IS_DEBUG_TILFA)
zlog_debug("ISIS-LFA: excising node %s",
print_sys_hostname(lsp->hdr.lsp_id));
return ISIS_OK;
}
if (!lsp->tlvs)
return ISIS_OK;
@ -940,8 +960,22 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree,
/* Iterate over adjacencies. */
for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, node, sadj)) {
const uint8_t *adj_id;
uint32_t metric;
if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST))
adj_id = sadj->lan.desig_is_id;
else
adj_id = sadj->id;
if (isis_lfa_excise_adj_check(spftree, adj_id)) {
if (IS_DEBUG_TILFA)
zlog_debug("ISIS-Spf: excising adjacency %s",
isis_format_id(sadj->id,
ISIS_SYS_ID_LEN + 1));
continue;
}
metric = CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)
? 1
: sadj->metric;
@ -1076,6 +1110,17 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
/* Add adjacency to the list. */
listnode_add(spftree->sadj_list, sadj);
if (!LSP_PSEUDO_ID(id)) {
struct isis_spf_node *node;
node = isis_spf_node_find(&spftree->adj_nodes, id);
if (!node)
node = isis_spf_node_new(&spftree->adj_nodes, id);
if (node->best_metric == 0 || sadj->metric < node->best_metric)
node->best_metric = sadj->metric;
listnode_add(node->adjacencies, sadj);
}
/* Parse pseudonode LSP too. */
if (LSP_PSEUDO_ID(id)) {
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
@ -1177,6 +1222,7 @@ static void isis_spf_build_adj_list(struct isis_spftree *spftree,
static void add_to_paths(struct isis_spftree *spftree,
struct isis_vertex *vertex)
{
struct isis_area *area = spftree->area;
char buff[VID2STR_BUFFER];
if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
@ -1192,14 +1238,23 @@ static void add_to_paths(struct isis_spftree *spftree,
if (VTYPE_IP(vertex->type)
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
if (listcount(vertex->Adj_N) > 0)
if (listcount(vertex->Adj_N) > 0) {
struct route_table *route_table;
if (spftree->type == SPF_TYPE_TI_LFA) {
if (isis_lfa_check(spftree, vertex) != 0)
return;
route_table = spftree->lfa.old.spftree
->route_table_backup;
} else
route_table = spftree->route_table;
isis_route_create(&vertex->N.ip.dest, &vertex->N.ip.src,
vertex->d_N, vertex->depth,
vertex->Adj_N, spftree->area,
spftree->route_table);
else if (IS_DEBUG_SPF_EVENTS)
vertex->Adj_N, area, route_table);
} else if (IS_DEBUG_SPF_EVENTS)
zlog_debug(
"ISIS-Spf: no adjacencies do not install route for %s depth %d dist %d",
"ISIS-Spf: no adjacencies, do not install route for %s depth %d dist %d",
vid2string(vertex, buff, sizeof(buff)),
vertex->depth, vertex->d_N);
}
@ -1210,6 +1265,7 @@ static void add_to_paths(struct isis_spftree *spftree,
static void init_spt(struct isis_spftree *spftree, int mtid)
{
/* Clear data from previous run. */
isis_spf_node_list_clear(&spftree->adj_nodes);
list_delete_all_node(spftree->sadj_list);
isis_vertex_queue_clear(&spftree->tents);
isis_vertex_queue_clear(&spftree->paths);
@ -1356,28 +1412,48 @@ void isis_run_spf(struct isis_spftree *spftree)
+ (time_end.tv_usec - time_start.tv_usec);
}
static void isis_run_spf_with_protection(struct isis_area *area,
struct isis_spftree *spftree)
{
/* Run forward SPF locally. */
memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
isis_run_spf(spftree);
/* Run LFA protection if configured. */
if (area->lfa_protected_links[spftree->level - 1] > 0)
isis_spf_run_lfa(area, spftree);
}
void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
{
if (area->is_type == IS_LEVEL_1) {
isis_route_verify_table(area, trees[0]->route_table);
isis_route_verify_table(area, trees[0]->route_table,
trees[0]->route_table_backup);
} else if (area->is_type == IS_LEVEL_2) {
isis_route_verify_table(area, trees[1]->route_table);
isis_route_verify_table(area, trees[1]->route_table,
trees[1]->route_table_backup);
} else {
isis_route_verify_merge(area, trees[0]->route_table,
trees[1]->route_table);
trees[0]->route_table_backup,
trees[1]->route_table,
trees[1]->route_table_backup);
}
}
void isis_spf_invalidate_routes(struct isis_spftree *tree)
{
isis_route_invalidate_table(tree->area, tree->route_table);
/* Delete backup routes. */
route_table_finish(tree->route_table_backup);
tree->route_table_backup = srcdest_table_init();
tree->route_table_backup->cleanup = isis_route_node_cleanup;
}
static int isis_run_spf_cb(struct thread *thread)
{
struct isis_spf_run *run = THREAD_ARG(thread);
struct isis_area *area = run->area;
struct isis_spftree *spftree;
int level = run->level;
XFREE(MTYPE_ISIS_SPF_RUN, run);
@ -1396,21 +1472,15 @@ static int isis_run_spf_cb(struct thread *thread)
zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
area->area_tag, level);
if (area->ip_circuits) {
spftree = area->spftree[SPFTREE_IPV4][level - 1];
memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
isis_run_spf(spftree);
}
if (area->ipv6_circuits) {
spftree = area->spftree[SPFTREE_IPV6][level - 1];
memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
isis_run_spf(spftree);
}
if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) {
spftree = area->spftree[SPFTREE_DSTSRC][level - 1];
memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
isis_run_spf(spftree);
}
if (area->ip_circuits)
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_IPV4][level - 1]);
if (area->ipv6_circuits)
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_IPV6][level - 1]);
if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_DSTSRC][level - 1]);
isis_area_verify_routes(area);
@ -1706,8 +1776,10 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
return CMD_SUCCESS;
}
void isis_print_routes(struct vty *vty, struct isis_spftree *spftree)
void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
bool backup)
{
struct route_table *route_table;
struct ttable *tt;
struct route_node *rn;
const char *tree_id_text = NULL;
@ -1741,7 +1813,9 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree)
ttable_restyle(tt);
ttable_rowseps(tt, 0, BOTTOM, true, '-');
for (rn = route_top(spftree->route_table); rn; rn = route_next(rn)) {
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;
@ -1779,7 +1853,22 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree)
strlcpy(buf_iface, "-", sizeof(buf_iface));
}
if (nexthop->sr.label != MPLS_INVALID_LABEL)
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
@ -1808,7 +1897,7 @@ 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)
struct isis *isis, bool backup)
{
struct listnode *node;
struct isis_area *area;
@ -1827,17 +1916,20 @@ static void show_isis_route_common(struct vty *vty, int levels,
if (area->ip_circuits > 0) {
isis_print_routes(
vty,
area->spftree[SPFTREE_IPV4][level - 1]);
area->spftree[SPFTREE_IPV4][level - 1],
backup);
}
if (area->ipv6_circuits > 0) {
isis_print_routes(
vty,
area->spftree[SPFTREE_IPV6][level - 1]);
area->spftree[SPFTREE_IPV6][level - 1],
backup);
}
if (isis_area_ipv6_dstsrc_enabled(area)) {
isis_print_routes(vty,
area->spftree[SPFTREE_DSTSRC]
[level - 1]);
[level - 1],
backup);
}
}
}
@ -1849,20 +1941,21 @@ DEFUN(show_isis_route, show_isis_route_cmd,
#ifndef FABRICD
" [<level-1|level-2>]"
#endif
,
" [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 backup routes\n")
{
int levels;
struct isis *isis;
struct listnode *node;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
bool backup = false;
int idx = 0;
if (argv_find(argv, argc, "level-1", &idx))
@ -1878,15 +1971,19 @@ DEFUN(show_isis_route, show_isis_route_cmd,
}
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, node, isis))
show_isis_route_common(vty, levels, isis);
show_isis_route_common(vty, levels, isis,
backup);
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis != NULL)
show_isis_route_common(vty, levels, isis);
show_isis_route_common(vty, levels, isis, backup);
}
return CMD_SUCCESS;

View File

@ -24,11 +24,14 @@
#ifndef _ZEBRA_ISIS_SPF_H
#define _ZEBRA_ISIS_SPF_H
#include "isisd/isis_lfa.h"
struct isis_spftree;
enum spf_type {
SPF_TYPE_FORWARD = 1,
SPF_TYPE_REVERSE,
SPF_TYPE_TI_LFA,
};
struct isis_spf_adj {
@ -56,17 +59,21 @@ void isis_spf_verify_routes(struct isis_area *area,
void isis_spftree_del(struct isis_spftree *spftree);
void spftree_area_init(struct isis_area *area);
void spftree_area_del(struct isis_area *area);
struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb,
const uint8_t *sysid);
#define isis_spf_schedule(area, level) \
_isis_spf_schedule((area), (level), __func__, \
__FILE__, __LINE__)
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);
void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
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);
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
uint8_t *sysid,
struct isis_spftree *spftree);
#endif /* _ZEBRA_ISIS_SPF_H */

View File

@ -306,8 +306,10 @@ struct isis_spftree {
struct isis_vertex_queue paths; /* the SPT */
struct isis_vertex_queue tents; /* TENT */
struct route_table *route_table;
struct route_table *route_table_backup;
struct lspdb_head *lspdb; /* link-state db */
struct list *sadj_list;
struct isis_spf_nodes adj_nodes;
struct isis_area *area; /* back pointer to area */
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp as wall time for display */
@ -320,7 +322,20 @@ struct isis_spftree {
int family;
int level;
enum spf_tree_id tree_id;
bool hopcount_metric;
struct {
/* Original pre-failure local SPTs. */
struct {
struct isis_spftree *spftree;
struct isis_spftree *spftree_reverse;
} old;
/* Protected resource. */
struct lfa_protected_resource protected_resource;
/* P-space and Q-space. */
struct isis_spf_nodes p_space;
struct isis_spf_nodes q_space;
} lfa;
uint8_t flags;
};
#define F_SPFTREE_HOPCOUNT_METRIC 0x01
@ -373,6 +388,7 @@ static struct isis_lsp *lsp_for_vertex(struct isis_spftree *spftree,
}
#define VID2STR_BUFFER SRCDEST2STR_BUFFER
const char *vid2string(struct isis_vertex *vertex, char *buff, int size);
const char *vtype2string(enum vertextype vtype);
const char *vid2string(const struct isis_vertex *vertex, char *buff, int size);
#endif

View File

@ -1792,15 +1792,17 @@ static int sr_if_new_hook(struct interface *ifp)
/**
* Show LFIB operation in human readable format.
*
* @param buf Buffer to store string output. Must be pre-allocate
* @param size Size of the buffer
* @param label_in Input Label
* @param label_out Output Label
* @param buf Buffer to store string output. Must be pre-allocate
* @param size Size of the buffer
* @param label_in Input Label
* @param label_out Output Label
* @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)
mpls_label_t label_out,
const struct mpls_label_stack *label_stack)
{
if (size < 24)
return NULL;
@ -1810,6 +1812,16 @@ 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);
@ -1859,7 +1871,7 @@ static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
snprintf(buf_uptime, sizeof(buf_uptime), "-");
}
sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
MPLS_LABEL_IMPLICIT_NULL);
MPLS_LABEL_IMPLICIT_NULL, NULL);
ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
@ -1876,7 +1888,7 @@ static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
*/
static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
const struct isis_area *area,
const struct sr_prefix *srp)
const struct sr_prefix *srp, bool backup)
{
struct isis_nexthop *nexthop;
struct listnode *node;
@ -1886,19 +1898,22 @@ static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
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));
if (!srp->u.remote.rinfo) {
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));
MPLS_LABEL_IMPLICIT_NULL, NULL));
return;
}
for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
nexthop)) {
for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
struct interface *ifp;
inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
@ -1915,7 +1930,7 @@ static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
log_uptime(nexthop->sr.uptime, buf_uptime,
sizeof(buf_uptime));
sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
nexthop->sr.label);
nexthop->sr.label, nexthop->label_stack);
if (first)
ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", buf_prefix,
@ -1935,7 +1950,8 @@ static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
* @param area IS-IS area
* @param level IS-IS level
*/
static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level,
bool backup)
{
struct sr_prefix *srp;
struct ttable *tt;
@ -1960,7 +1976,7 @@ static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
show_prefix_sid_local(vty, tt, area, srp);
break;
case ISIS_SR_PREFIX_REMOTE:
show_prefix_sid_remote(vty, tt, area, srp);
show_prefix_sid_remote(vty, tt, area, srp, backup);
break;
}
}
@ -1980,20 +1996,25 @@ static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
* Declaration of new show commands.
*/
DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
"show isis [vrf <NAME|all>] segment-routing prefix-sids",
"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")
"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;
int idx_vrf = 0;
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;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (vrf_name) {
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
@ -2005,7 +2026,7 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
for (int level = ISIS_LEVEL1;
level <= ISIS_LEVELS; level++)
show_prefix_sids(vty, area,
level);
level, backup);
}
}
return 0;
@ -2019,7 +2040,8 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
: "null");
for (int level = ISIS_LEVEL1;
level <= ISIS_LEVELS; level++)
show_prefix_sids(vty, area, level);
show_prefix_sids(vty, area, level,
backup);
}
}
}

View File

@ -168,42 +168,29 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
return 0;
}
void isis_zebra_route_add_route(struct isis *isis,
struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
enum isis_zebra_nexthop_type {
ISIS_ROUTE_NEXTHOP_MAIN = 0,
ISIS_ROUTE_NEXTHOP_BACKUP,
ISIS_MPLS_NEXTHOP_MAIN,
ISIS_MPLS_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)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
struct isis_nexthop *nexthop;
struct listnode *node;
int count = 0;
if (zclient->sock < 0)
return;
memset(&api, 0, sizeof(api));
api.vrf_id = isis->vrf_id;
api.type = PROTO_TYPE;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
if (src_p && src_p->prefixlen) {
api.src_prefix = *src_p;
SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
}
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = route_info->cost;
#if 0
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = route_info->depth;
#endif
/* Nexthops */
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, nexthop)) {
for (ALL_LIST_ELEMENTS_RO(nexthops, node, nexthop)) {
struct zapi_nexthop *api_nh;
if (count >= MULTIPATH_NUM)
break;
api_nh = &api.nexthops[count];
api_nh = &zapi_nexthops[count];
if (fabricd)
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
api_nh->vrf_id = isis->vrf_id;
@ -234,11 +221,98 @@ void isis_zebra_route_add_route(struct isis *isis,
}
api_nh->ifindex = nexthop->ifindex;
/* 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) {
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;
}
break;
case ISIS_MPLS_NEXTHOP_BACKUP:
if (nexthop->label_stack) {
api_nh->label_num =
nexthop->label_stack->num_labels;
memcpy(api_nh->labels,
nexthop->label_stack->label,
sizeof(mpls_label_t)
* api_nh->label_num);
} else {
api_nh->label_num = 1;
api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
}
break;
}
/* Backup nexthop handling. */
if (backup_nhs) {
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
/*
* If the backup has multiple nexthops, all of them
* protect the same primary nexthop since ECMP routes
* have no backups.
*/
api_nh->backup_num = backup_nhs;
for (int i = 0; i < backup_nhs; i++)
api_nh->backup_idx[i] = i;
}
count++;
}
if (!count)
return count;
}
void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
struct zapi_route api;
int count = 0;
if (zclient->sock < 0)
return;
memset(&api, 0, sizeof(api));
api.vrf_id = isis->vrf_id;
api.type = PROTO_TYPE;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
if (src_p && src_p->prefixlen) {
api.src_prefix = *src_p;
SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
}
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = route_info->cost;
/* Add backup nexthops first. */
if (route_info->backup) {
count = isis_zebra_add_nexthops(
isis, route_info->backup->nexthops, api.backup_nexthops,
ISIS_ROUTE_NEXTHOP_BACKUP, 0);
if (count > 0) {
SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
api.backup_nexthop_num = count;
}
}
/* Add primary nexthops. */
count = isis_zebra_add_nexthops(isis, route_info->nexthops,
api.nexthops, ISIS_ROUTE_NEXTHOP_MAIN,
count);
if (!count)
return;
api.nexthop_num = count;
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
@ -274,11 +348,12 @@ void isis_zebra_route_del_route(struct isis *isis,
*/
static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
{
struct isis *isis = srp->srn->area->isis;
struct zapi_labels zl;
struct zapi_nexthop *znh;
struct listnode *node;
struct isis_nexthop *nexthop;
struct interface *ifp;
struct isis_route_info *rinfo;
int count = 0;
/* Prepare message. */
memset(&zl, 0, sizeof(zl));
@ -308,23 +383,27 @@ static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
zl.route.type = ZEBRA_ROUTE_ISIS;
zl.route.instance = 0;
for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
nexthop)) {
if (nexthop->sr.label == MPLS_INVALID_LABEL)
continue;
rinfo = srp->u.remote.rinfo;
if (zl.nexthop_num >= MULTIPATH_NUM)
break;
znh = &zl.nexthops[zl.nexthop_num++];
znh->type = (srp->prefix.family == AF_INET)
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX;
znh->gate = nexthop->ip;
znh->ifindex = nexthop->ifindex;
znh->label_num = 1;
znh->labels[0] = nexthop->sr.label;
/* Add backup nexthops first. */
if (rinfo->backup) {
count = isis_zebra_add_nexthops(
isis, rinfo->backup->nexthops,
zl.backup_nexthops, ISIS_MPLS_NEXTHOP_BACKUP,
0);
if (count > 0) {
SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
zl.backup_nexthop_num = count;
}
}
/* Add primary nexthops. */
count = isis_zebra_add_nexthops(isis, rinfo->nexthops,
zl.nexthops,
ISIS_MPLS_NEXTHOP_MAIN, count);
if (!count)
return;
zl.nexthop_num = count;
break;
}

View File

@ -77,6 +77,7 @@ unsigned long debug_bfd;
unsigned long debug_tx_queue;
unsigned long debug_sr;
unsigned long debug_ldp_sync;
unsigned long debug_tilfa;
DEFINE_QOBJ_TYPE(isis_area)
@ -1191,6 +1192,8 @@ void print_debug(struct vty *vty, int flags, int onoff)
if (flags & DEBUG_SR)
vty_out(vty, "IS-IS Segment Routing events debugging is %s\n",
onoffs);
if (flags & DEBUG_TILFA)
vty_out(vty, "IS-IS TI-LFA events debugging is %s\n", onoffs);
if (flags & DEBUG_UPDATE_PACKETS)
vty_out(vty, "IS-IS Update related packet debugging is %s\n",
onoffs);
@ -1285,6 +1288,10 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug " PROTO_NAME " sr-events\n");
write++;
}
if (IS_DEBUG_TILFA) {
vty_out(vty, "debug " PROTO_NAME " ti-lfa\n");
write++;
}
if (IS_DEBUG_UPDATE_PACKETS) {
vty_out(vty, "debug " PROTO_NAME " update-packets\n");
write++;
@ -1515,6 +1522,33 @@ DEFUN (no_debug_isis_srevents,
return CMD_SUCCESS;
}
DEFUN (debug_isis_tilfa,
debug_isis_tilfa_cmd,
"debug " PROTO_NAME " ti-lfa",
DEBUG_STR
PROTO_HELP
"IS-IS TI-LFA Events\n")
{
debug_tilfa |= DEBUG_TILFA;
print_debug(vty, DEBUG_TILFA, 1);
return CMD_SUCCESS;
}
DEFUN (no_debug_isis_tilfa,
no_debug_isis_tilfa_cmd,
"no debug " PROTO_NAME " ti-lfa",
NO_STR
UNDEBUG_STR
PROTO_HELP
"IS-IS TI-LFA Events\n")
{
debug_tilfa &= ~DEBUG_TILFA;
print_debug(vty, DEBUG_TILFA, 0);
return CMD_SUCCESS;
}
DEFUN (debug_isis_rtevents,
debug_isis_rtevents_cmd,
"debug " PROTO_NAME " route-events",
@ -2848,6 +2882,8 @@ void isis_init(void)
install_element(ENABLE_NODE, &no_debug_isis_spfevents_cmd);
install_element(ENABLE_NODE, &debug_isis_srevents_cmd);
install_element(ENABLE_NODE, &no_debug_isis_srevents_cmd);
install_element(ENABLE_NODE, &debug_isis_tilfa_cmd);
install_element(ENABLE_NODE, &no_debug_isis_tilfa_cmd);
install_element(ENABLE_NODE, &debug_isis_rtevents_cmd);
install_element(ENABLE_NODE, &no_debug_isis_rtevents_cmd);
install_element(ENABLE_NODE, &debug_isis_events_cmd);
@ -2877,6 +2913,8 @@ void isis_init(void)
install_element(CONFIG_NODE, &no_debug_isis_spfevents_cmd);
install_element(CONFIG_NODE, &debug_isis_srevents_cmd);
install_element(CONFIG_NODE, &no_debug_isis_srevents_cmd);
install_element(CONFIG_NODE, &debug_isis_tilfa_cmd);
install_element(CONFIG_NODE, &no_debug_isis_tilfa_cmd);
install_element(CONFIG_NODE, &debug_isis_rtevents_cmd);
install_element(CONFIG_NODE, &no_debug_isis_rtevents_cmd);
install_element(CONFIG_NODE, &debug_isis_events_cmd);

View File

@ -188,6 +188,8 @@ struct isis_area {
struct isis_sr_db srdb;
int ipv6_circuits;
bool purge_originator;
/* Fast Re-Route information. */
size_t lfa_protected_links[ISIS_LEVELS];
/* Counters */
uint32_t circuit_state_changes;
struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
@ -278,6 +280,7 @@ extern unsigned long debug_bfd;
extern unsigned long debug_tx_queue;
extern unsigned long debug_sr;
extern unsigned long debug_ldp_sync;
extern unsigned long debug_tilfa;
#define DEBUG_ADJ_PACKETS (1<<0)
#define DEBUG_SNP_PACKETS (1<<1)
@ -292,7 +295,8 @@ extern unsigned long debug_ldp_sync;
#define DEBUG_BFD (1<<10)
#define DEBUG_TX_QUEUE (1<<11)
#define DEBUG_SR (1<<12)
#define DEBUG_LDP_SYNC (1 << 13)
#define DEBUG_LDP_SYNC (1<<13)
#define DEBUG_TILFA (1<<14)
/* Debug related macro. */
#define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@ -309,6 +313,7 @@ extern unsigned long debug_ldp_sync;
#define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE)
#define IS_DEBUG_SR (debug_sr & DEBUG_SR)
#define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
#define IS_DEBUG_TILFA (debug_tilfa & DEBUG_TILFA)
#define lsp_debug(...) \
do { \

View File

@ -52,6 +52,7 @@ noinst_HEADERS += \
isisd/isis_events.h \
isisd/isis_flags.h \
isisd/isis_ldp_sync.h \
isisd/isis_lfa.h \
isisd/isis_lsp.h \
isisd/isis_memory.h \
isisd/isis_misc.h \
@ -86,6 +87,7 @@ LIBISIS_SOURCES = \
isisd/isis_events.c \
isisd/isis_flags.c \
isisd/isis_ldp_sync.c \
isisd/isis_lfa.c \
isisd/isis_lsp.c \
isisd/isis_memory.c \
isisd/isis_misc.c \