]> git.puffer.fish Git - mirror/frr.git/commitdiff
isisd: implement TI-LFA protection for Adj-SIDs
authorRenato Westphal <renato@opensourcerouting.org>
Mon, 31 Aug 2020 18:24:02 +0000 (15:24 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Wed, 14 Oct 2020 19:27:37 +0000 (16:27 -0300)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
isisd/isis_lfa.c
isisd/isis_spf.c
isisd/isis_sr.c
isisd/isis_sr.h
isisd/isis_zebra.c

index e0a58c8f6e1c6faf0574f97bdae8731fe0868b40..8ca432f895d37b7eb15bd2abe63959e14dc34826 100644 (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;
 
index e18f09b66bc8aa7f6180c3335b27e8f841133541..7e46b93aaff723a24d1bcd7e0780be308969250a 100644 (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)
index c2c34c24f353719ac38c3c9fc1f896324aa052d4..842103de1e17502e9adc118a829f0686e21c8d60 100644 (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.
  *
index 4379a1dcba611700c61a37571184f9a7866f37c1..2e4f3a69f79413a75d15c183c8f44b51f895b2e2 100644 (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);
index 26cc175a522ce6a556e3ff529cd0053d4285b29c..0e92dc2a8942e98d7cc461f695d01531cc68f12e 100644 (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);
 }