summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2020-08-31 20:24:02 +0200
committerRenato Westphal <renato@opensourcerouting.org>2020-10-14 21:27:37 +0200
commit054fda12f0ca749e39e1b95409a3aac3aebb3dc9 (patch)
treebf7a4d28a11c33dd554ac01cf6d667ff213d8bcf /isisd
parentisisd: add support for Topology Independent LFA (TI-LFA) (diff)
downloadfrr-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.c18
-rw-r--r--isisd/isis_spf.c24
-rw-r--r--isisd/isis_sr.c84
-rw-r--r--isisd/isis_sr.h13
-rw-r--r--isisd/isis_zebra.c23
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);
}