isisd: implement TI-LFA protection for Adj-SIDs

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2020-08-31 15:24:02 -03:00
parent c951ee6eee
commit 054fda12f0
5 changed files with 146 additions and 16 deletions

View File

@ -678,8 +678,24 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
} }
/* /*
* Check if the adjacency was already covered by node protection. * Check if the route/adjacency was already covered by node protection.
*/ */
if (VTYPE_IS(vertex->type)) {
struct isis_adjacency *adj;
adj = isis_adj_find(spftree_pc->area, spftree_pc->level,
vertex->N.id);
if (adj
&& isis_sr_adj_sid_find(adj, spftree_pc->family,
ISIS_SR_LAN_BACKUP)) {
if (IS_DEBUG_TILFA)
zlog_debug(
"ISIS-TI-LFA: %s %s already covered by node protection",
vtype2string(vertex->type), buf);
return -1;
}
}
if (VTYPE_IP(vertex->type)) { if (VTYPE_IP(vertex->type)) {
struct route_table *route_table; struct route_table *route_table;

View File

@ -1236,6 +1236,29 @@ static void add_to_paths(struct isis_spftree *spftree,
vertex->d_N); vertex->d_N);
#endif /* EXTREME_DEBUG */ #endif /* EXTREME_DEBUG */
if (VTYPE_IS(vertex->type)
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
if (listcount(vertex->Adj_N) > 0) {
if (spftree->type == SPF_TYPE_TI_LFA) {
struct isis_adjacency *adj;
if (isis_lfa_check(spftree, vertex) != 0)
return;
adj = isis_adj_find(area, spftree->level,
vertex->N.id);
if (adj)
sr_adj_sid_add_single(
adj, spftree->family, true,
vertex->Adj_N);
}
} else if (IS_DEBUG_SPF_EVENTS)
zlog_debug(
"ISIS-Spf: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d",
vid2string(vertex, buff, sizeof(buff)),
vertex->depth, vertex->d_N);
}
if (VTYPE_IP(vertex->type) if (VTYPE_IP(vertex->type)
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) { && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
if (listcount(vertex->Adj_N) > 0) { if (listcount(vertex->Adj_N) > 0) {
@ -1466,6 +1489,7 @@ static int isis_run_spf_cb(struct thread *thread)
return ISIS_WARNING; return ISIS_WARNING;
} }
isis_area_delete_backup_adj_sids(area, level);
isis_area_invalidate_routes(area, level); isis_area_invalidate_routes(area, level);
if (IS_DEBUG_SPF_EVENTS) if (IS_DEBUG_SPF_EVENTS)

View File

@ -56,6 +56,7 @@ static void sr_local_block_delete(struct isis_area *area);
static int sr_local_block_init(struct isis_area *area); static int sr_local_block_init(struct isis_area *area);
static void sr_adj_sid_update(struct sr_adjacency *sra, static void sr_adj_sid_update(struct sr_adjacency *sra,
struct sr_local_block *srlb); struct sr_local_block *srlb);
static void sr_adj_sid_del(struct sr_adjacency *sra);
/* --- RB-Tree Management functions ----------------------------------------- */ /* --- RB-Tree Management functions ----------------------------------------- */
@ -1254,6 +1255,23 @@ static void process_node_changes(struct isis_area *area, int level,
process_prefix_changes(srn, srp); process_prefix_changes(srn, srp);
} }
/**
* Delete all backup Adj-SIDs.
*
* @param area IS-IS area
* @param level IS-IS level
*/
void isis_area_delete_backup_adj_sids(struct isis_area *area, int level)
{
struct sr_adjacency *sra;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
if (sra->type == ISIS_SR_LAN_BACKUP
&& (sra->adj->level & level))
sr_adj_sid_del(sra);
}
/** /**
* Parse and process all SR-related Sub-TLVs after running the SPF algorithm. * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
* *
@ -1499,12 +1517,13 @@ static int sr_local_block_release_label(struct sr_local_block *srlb,
/** /**
* Add new local Adjacency-SID. * Add new local Adjacency-SID.
* *
* @param adj IS-IS Adjacency * @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6) * @param family Inet Family (IPv4 or IPv6)
* @param backup True to initialize backup Adjacency SID * @param backup True to initialize backup Adjacency SID
* @param nexthops List of backup nexthops (for backup Adj-SIDs only)
*/ */
static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
bool backup) struct list *nexthops)
{ {
struct isis_circuit *circuit = adj->circuit; struct isis_circuit *circuit = adj->circuit;
struct isis_area *area = circuit->area; struct isis_area *area = circuit->area;
@ -1555,9 +1574,25 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra)); sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL; sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
sra->input_label = input_label;
sra->nexthop.family = family; sra->nexthop.family = family;
sra->nexthop.address = nexthop; sra->nexthop.address = nexthop;
sra->nexthop.label = input_label;
if (backup && nexthops) {
struct isis_vertex_adj *vadj;
struct listnode *node;
sra->backup_nexthops = list_new();
for (ALL_LIST_ELEMENTS_RO(nexthops, node, vadj)) {
struct isis_adjacency *adj = vadj->sadj->adj;
struct mpls_label_stack *label_stack;
label_stack = vadj->label_stack;
adjinfo2nexthop(family, sra->backup_nexthops, adj,
label_stack);
}
}
switch (circuit->circ_type) { switch (circuit->circ_type) {
/* LAN Adjacency-SID for Broadcast interface section #2.2.2 */ /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
case CIRCUIT_T_BROADCAST: case CIRCUIT_T_BROADCAST:
@ -1603,8 +1638,7 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
*/ */
static void sr_adj_sid_add(struct isis_adjacency *adj, int family) static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
{ {
sr_adj_sid_add_single(adj, family, false); sr_adj_sid_add_single(adj, family, false, NULL);
sr_adj_sid_add_single(adj, family, true);
} }
static void sr_adj_sid_update(struct sr_adjacency *sra, static void sr_adj_sid_update(struct sr_adjacency *sra,
@ -1616,16 +1650,16 @@ static void sr_adj_sid_update(struct sr_adjacency *sra,
isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra); isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
/* Got new label in the new SRLB */ /* Got new label in the new SRLB */
sra->nexthop.label = sr_local_block_request_label(srlb); sra->input_label = sr_local_block_request_label(srlb);
if (sra->nexthop.label == MPLS_INVALID_LABEL) if (sra->input_label == MPLS_INVALID_LABEL)
return; return;
switch (circuit->circ_type) { switch (circuit->circ_type) {
case CIRCUIT_T_BROADCAST: case CIRCUIT_T_BROADCAST:
sra->u.ladj_sid->sid = sra->nexthop.label; sra->u.ladj_sid->sid = sra->input_label;
break; break;
case CIRCUIT_T_P2P: case CIRCUIT_T_P2P:
sra->u.adj_sid->sid = sra->nexthop.label; sra->u.adj_sid->sid = sra->input_label;
break; break;
default: default:
flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u", flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
@ -1669,12 +1703,38 @@ static void sr_adj_sid_del(struct sr_adjacency *sra)
exit(1); exit(1);
} }
if (sra->type == ISIS_SR_LAN_BACKUP && sra->backup_nexthops) {
sra->backup_nexthops->del =
(void (*)(void *))isis_nexthop_delete;
list_delete(&sra->backup_nexthops);
}
/* Remove Adjacency-SID from the SRDB */ /* Remove Adjacency-SID from the SRDB */
listnode_delete(area->srdb.adj_sids, sra); listnode_delete(area->srdb.adj_sids, sra);
listnode_delete(sra->adj->adj_sids, sra); listnode_delete(sra->adj->adj_sids, sra);
XFREE(MTYPE_ISIS_SR_INFO, sra); XFREE(MTYPE_ISIS_SR_INFO, sra);
} }
/**
* Lookup Segment Routing Adj-SID by family and type.
*
* @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6)
* @param type Adjacency SID type
*/
struct sr_adjacency *isis_sr_adj_sid_find(struct isis_adjacency *adj,
int family, enum sr_adj_type type)
{
struct sr_adjacency *sra;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, node, sra))
if (sra->nexthop.family == family && sra->type == type)
return sra;
return NULL;
}
/** /**
* Remove all Adjacency-SIDs associated to an adjacency that is going down. * Remove all Adjacency-SIDs associated to an adjacency that is going down.
* *

View File

@ -84,13 +84,18 @@ struct sr_adjacency {
/* Adjacency type. */ /* Adjacency type. */
enum sr_adj_type type; enum sr_adj_type type;
/* Adjacency-SID input label. */
mpls_label_t input_label;
/* Adjacency-SID nexthop information. */ /* Adjacency-SID nexthop information. */
struct { struct {
int family; int family;
union g_addr address; union g_addr address;
mpls_label_t label;
} nexthop; } nexthop;
/* Adjacency-SID TI-LFA backup nexthops. */
struct list *backup_nexthops;
/* (LAN-)Adjacency-SID Sub-TLV. */ /* (LAN-)Adjacency-SID Sub-TLV. */
union { union {
struct isis_adj_sid *adj_sid; struct isis_adj_sid *adj_sid;
@ -277,6 +282,12 @@ extern void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg,
extern void isis_sr_nexthop_update(struct sr_nexthop_info *srnh, extern void isis_sr_nexthop_update(struct sr_nexthop_info *srnh,
mpls_label_t label); mpls_label_t label);
extern void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh); 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 void isis_area_verify_sr(struct isis_area *area);
extern int isis_sr_start(struct isis_area *area); extern int isis_sr_start(struct isis_area *area);
extern void isis_sr_stop(struct isis_area *area); extern void isis_sr_stop(struct isis_area *area);

View File

@ -471,6 +471,7 @@ void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
*/ */
void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra) void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
{ {
struct isis *isis = sra->adj->circuit->area->isis;
struct zapi_labels zl; struct zapi_labels zl;
struct zapi_nexthop *znh; struct zapi_nexthop *znh;
@ -482,11 +483,11 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
sr_debug(" |- %s label %u for interface %s", sr_debug(" |- %s label %u for interface %s",
cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
sra->nexthop.label, sra->adj->circuit->interface->name); sra->input_label, sra->adj->circuit->interface->name);
memset(&zl, 0, sizeof(zl)); memset(&zl, 0, sizeof(zl));
zl.type = ZEBRA_LSP_ISIS_SR; zl.type = ZEBRA_LSP_ISIS_SR;
zl.local_label = sra->nexthop.label; zl.local_label = sra->input_label;
zl.nexthop_num = 1; zl.nexthop_num = 1;
znh = &zl.nexthops[0]; znh = &zl.nexthops[0];
znh->gate = sra->nexthop.address; znh->gate = sra->nexthop.address;
@ -497,6 +498,24 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
znh->label_num = 1; znh->label_num = 1;
znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL; znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
/* Set backup nexthops. */
if (sra->type == ISIS_SR_LAN_BACKUP) {
int count;
count = isis_zebra_add_nexthops(isis, sra->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;
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
znh->backup_num = count;
for (int i = 0; i < count; i++)
znh->backup_idx[i] = i;
}
}
(void)zebra_send_mpls_labels(zclient, cmd, &zl); (void)zebra_send_mpls_labels(zclient, cmd, &zl);
} }