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)) {
struct route_table *route_table;

View File

@ -1236,6 +1236,29 @@ static void add_to_paths(struct isis_spftree *spftree,
vertex->d_N);
#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)
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
if (listcount(vertex->Adj_N) > 0) {
@ -1466,6 +1489,7 @@ static int isis_run_spf_cb(struct thread *thread)
return ISIS_WARNING;
}
isis_area_delete_backup_adj_sids(area, level);
isis_area_invalidate_routes(area, level);
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 void sr_adj_sid_update(struct sr_adjacency *sra,
struct sr_local_block *srlb);
static void sr_adj_sid_del(struct sr_adjacency *sra);
/* --- RB-Tree Management functions ----------------------------------------- */
@ -1254,6 +1255,23 @@ static void process_node_changes(struct isis_area *area, int level,
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.
*
@ -1499,12 +1517,13 @@ static int sr_local_block_release_label(struct sr_local_block *srlb,
/**
* Add new local Adjacency-SID.
*
* @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6)
* @param backup True to initialize backup Adjacency SID
* @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6)
* @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,
bool backup)
void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
struct list *nexthops)
{
struct isis_circuit *circuit = adj->circuit;
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->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
sra->input_label = input_label;
sra->nexthop.family = family;
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) {
/* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
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)
{
sr_adj_sid_add_single(adj, family, false);
sr_adj_sid_add_single(adj, family, true);
sr_adj_sid_add_single(adj, family, false, NULL);
}
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);
/* Got new label in the new SRLB */
sra->nexthop.label = sr_local_block_request_label(srlb);
if (sra->nexthop.label == MPLS_INVALID_LABEL)
sra->input_label = sr_local_block_request_label(srlb);
if (sra->input_label == MPLS_INVALID_LABEL)
return;
switch (circuit->circ_type) {
case CIRCUIT_T_BROADCAST:
sra->u.ladj_sid->sid = sra->nexthop.label;
sra->u.ladj_sid->sid = sra->input_label;
break;
case CIRCUIT_T_P2P:
sra->u.adj_sid->sid = sra->nexthop.label;
sra->u.adj_sid->sid = sra->input_label;
break;
default:
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);
}
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 */
listnode_delete(area->srdb.adj_sids, sra);
listnode_delete(sra->adj->adj_sids, 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.
*

View File

@ -84,13 +84,18 @@ struct sr_adjacency {
/* Adjacency type. */
enum sr_adj_type type;
/* Adjacency-SID input label. */
mpls_label_t input_label;
/* Adjacency-SID nexthop information. */
struct {
int family;
union g_addr address;
mpls_label_t label;
} nexthop;
/* Adjacency-SID TI-LFA backup nexthops. */
struct list *backup_nexthops;
/* (LAN-)Adjacency-SID Sub-TLV. */
union {
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,
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 int isis_sr_start(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)
{
struct isis *isis = sra->adj->circuit->area->isis;
struct zapi_labels zl;
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",
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));
zl.type = ZEBRA_LSP_ISIS_SR;
zl.local_label = sra->nexthop.label;
zl.local_label = sra->input_label;
zl.nexthop_num = 1;
znh = &zl.nexthops[0];
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->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);
}