diff options
author | Renato Westphal <renato@opensourcerouting.org> | 2020-08-31 20:24:02 +0200 |
---|---|---|
committer | Renato Westphal <renato@opensourcerouting.org> | 2020-10-14 21:27:37 +0200 |
commit | 054fda12f0ca749e39e1b95409a3aac3aebb3dc9 (patch) | |
tree | bf7a4d28a11c33dd554ac01cf6d667ff213d8bcf /isisd | |
parent | isisd: add support for Topology Independent LFA (TI-LFA) (diff) | |
download | frr-054fda12f0ca749e39e1b95409a3aac3aebb3dc9.tar.xz frr-054fda12f0ca749e39e1b95409a3aac3aebb3dc9.zip |
isisd: implement TI-LFA protection for Adj-SIDs
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r-- | isisd/isis_lfa.c | 18 | ||||
-rw-r--r-- | isisd/isis_spf.c | 24 | ||||
-rw-r--r-- | isisd/isis_sr.c | 84 | ||||
-rw-r--r-- | isisd/isis_sr.h | 13 | ||||
-rw-r--r-- | isisd/isis_zebra.c | 23 |
5 files changed, 146 insertions, 16 deletions
diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index e0a58c8f6..8ca432f89 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -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; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index e18f09b66..7e46b93aa 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -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) diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index c2c34c24f..842103de1 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -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 ----------------------------------------- */ @@ -1255,6 +1256,23 @@ static void process_node_changes(struct isis_area *area, int level, } /** + * 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. * * @param area IS-IS area @@ -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,6 +1703,12 @@ 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); @@ -1676,6 +1716,26 @@ static void sr_adj_sid_del(struct sr_adjacency *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. * * @param adj IS-IS Adjacency diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h index 4379a1dcb..2e4f3a69f 100644 --- a/isisd/isis_sr.h +++ b/isisd/isis_sr.h @@ -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); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 26cc175a5..0e92dc2a8 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -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); } |