]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: add abiliy to compute the reverse shortest path tree
authorRenato Westphal <renato@opensourcerouting.org>
Mon, 24 Aug 2020 18:27:15 +0000 (15:27 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Wed, 26 Aug 2020 23:16:19 +0000 (20:16 -0300)
RFC 7490 says:
 "The reverse SPF computes the cost from each remote node to root. This
  is achieved by running the normal SPF algorithm but using the link
  cost in the direction from the next hop back towards root in place of
  the link cost in the direction away from root towards the next hop".

Support for reverse SPF will be necessary later as it's one of the
algorithms used to compute R-LFA/TI-LFA repair paths.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
isisd/fabricd.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_spf_private.h
tests/isisd/test_isis_spf.c
tests/isisd/test_isis_spf.in
tests/isisd/test_isis_spf.refout

index 2953ee681ca3c02976b269fe6b757ccb7b0be7a0..1a081bbea669e4a8526b472b977af6d3c2e802cb 100644 (file)
@@ -221,9 +221,10 @@ struct fabricd *fabricd_new(struct isis_area *area)
        rv->area = area;
        rv->initial_sync_state = FABRICD_SYNC_PENDING;
 
-       rv->spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1],
-                                      area->isis->sysid, ISIS_LEVEL2,
-                                      SPFTREE_IPV4, F_SPFTREE_HOPCOUNT_METRIC);
+       rv->spftree =
+               isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1],
+                                area->isis->sysid, ISIS_LEVEL2, SPFTREE_IPV4,
+                                SPF_TYPE_FORWARD, F_SPFTREE_HOPCOUNT_METRIC);
        rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp,
                                     neighbor_entry_del_void);
        rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key,
index 19a373791e76c14c58fafe0d7abb1fdf7655fc55..dd0a6ec824ff344562e2174d1c1c02eaf2d428e3 100644 (file)
@@ -276,7 +276,8 @@ static void isis_spf_adj_free(void *arg)
 struct isis_spftree *isis_spftree_new(struct isis_area *area,
                                      struct lspdb_head *lspdb,
                                      const uint8_t *sysid, int level,
-                                     enum spf_tree_id tree_id, uint8_t flags)
+                                     enum spf_tree_id tree_id,
+                                     enum spf_type type, uint8_t flags)
 {
        struct isis_spftree *tree;
 
@@ -293,6 +294,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
        tree->last_run_monotime = 0;
        tree->last_run_duration = 0;
        tree->runcount = 0;
+       tree->type = type;
        memcpy(tree->sysid, sysid, ISIS_SYS_ID_LEN);
        tree->level = level;
        tree->tree_id = tree_id;
@@ -336,9 +338,10 @@ void spftree_area_init(struct isis_area *area)
                        if (area->spftree[tree][level - 1])
                                continue;
 
-                       area->spftree[tree][level - 1] = isis_spftree_new(
-                               area, &area->lspdb[level - 1],
-                               area->isis->sysid, level, tree, 0);
+                       area->spftree[tree][level - 1] =
+                               isis_spftree_new(area, &area->lspdb[level - 1],
+                                                area->isis->sysid, level, tree,
+                                                SPF_TYPE_FORWARD, 0);
                }
        }
 }
@@ -956,6 +959,76 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree,
        }
 }
 
+struct spf_adj_find_reverse_metric_args {
+       const uint8_t *id_self;
+       uint32_t reverse_metric;
+};
+
+static int spf_adj_find_reverse_metric_cb(const uint8_t *id, uint32_t metric,
+                                         bool oldmetric,
+                                         struct isis_ext_subtlvs *subtlvs,
+                                         void *arg)
+{
+       struct spf_adj_find_reverse_metric_args *args = arg;
+
+       if (memcmp(id, args->id_self, ISIS_SYS_ID_LEN))
+               return LSP_ITER_CONTINUE;
+
+       args->reverse_metric = metric;
+
+       return LSP_ITER_STOP;
+}
+
+/*
+ * Change all SPF adjacencies to use the link cost in the direction from the
+ * next hop back towards root in place of the link cost in the direction away
+ * from root towards the next hop.
+ */
+static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree)
+{
+       struct isis_spf_adj *sadj;
+       struct listnode *node, *nnode;
+
+       for (ALL_LIST_ELEMENTS(spftree->sadj_list, node, nnode, sadj)) {
+               uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+               struct isis_lsp *lsp_adj;
+               const uint8_t *id_self;
+               struct spf_adj_find_reverse_metric_args args;
+
+               /* Skip pseudonodes. */
+               if (LSP_PSEUDO_ID(sadj->id))
+                       continue;
+
+               /* Find LSP of the corresponding adjacency. */
+               memcpy(lspid, sadj->id, ISIS_SYS_ID_LEN);
+               LSP_PSEUDO_ID(lspid) = 0;
+               LSP_FRAGMENT(lspid) = 0;
+               lsp_adj = lsp_search(spftree->lspdb, lspid);
+               if (lsp_adj == NULL || lsp_adj->hdr.rem_lifetime == 0) {
+                       /* Delete one-way adjacency. */
+                       listnode_delete(spftree->sadj_list, sadj);
+                       continue;
+               }
+
+               /* Find root node in the LSP of the adjacent router. */
+               if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST))
+                       id_self = sadj->lan.desig_is_id;
+               else
+                       id_self = spftree->sysid;
+               args.id_self = id_self;
+               args.reverse_metric = UINT32_MAX;
+               isis_lsp_iterate_is_reach(lsp_adj, spftree->mtid,
+                                         spf_adj_find_reverse_metric_cb,
+                                         &args);
+               if (args.reverse_metric == UINT32_MAX) {
+                       /* Delete one-way adjacency. */
+                       listnode_delete(spftree->sadj_list, sadj);
+                       continue;
+               }
+               sadj->metric = args.reverse_metric;
+       }
+}
+
 static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
                                   struct list *adj_list, const uint8_t *id,
                                   const uint8_t *desig_is_id,
@@ -1092,6 +1165,9 @@ static void isis_spf_build_adj_list(struct isis_spftree *spftree,
 
        if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
                list_delete(&adj_list);
+
+       if (spftree->type == SPF_TYPE_REVERSE)
+               spf_adj_get_reverse_metrics(spftree);
 }
 
 /*
@@ -1181,6 +1257,7 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
        if (!spftree)
                spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1],
                                           sysid, ISIS_LEVEL2, SPFTREE_IPV4,
+                                          SPF_TYPE_FORWARD,
                                           F_SPFTREE_HOPCOUNT_METRIC);
 
        init_spt(spftree, ISIS_MT_IPV4_UNICAST);
index 61a107bea26f37b0da1f00fc8d627929ba288f5c..b2dc23496f3e356bd2572045896397539f0de636 100644 (file)
 
 struct isis_spftree;
 
+enum spf_type {
+       SPF_TYPE_FORWARD = 1,
+       SPF_TYPE_REVERSE,
+};
+
 struct isis_spf_adj {
        uint8_t id[ISIS_SYS_ID_LEN + 1];
        struct isis_adjacency *adj;
@@ -43,7 +48,8 @@ struct isis_spf_adj {
 struct isis_spftree *isis_spftree_new(struct isis_area *area,
                                      struct lspdb_head *lspdb,
                                      const uint8_t *sysid, int level,
-                                     enum spf_tree_id tree_id, uint8_t flags);
+                                     enum spf_tree_id tree_id,
+                                     enum spf_type type, uint8_t flags);
 void isis_spf_invalidate_routes(struct isis_spftree *tree);
 void isis_spf_verify_routes(struct isis_area *area,
                            struct isis_spftree **trees);
index 6bdf900d1cb049eb55fae88c6ba838a61a929f51..1e61bf0f4855d0c1f11a97154532057b53334e52 100644 (file)
@@ -314,6 +314,7 @@ struct isis_spftree {
        time_t last_run_monotime;  /* last run as monotime for scheduling */
        time_t last_run_duration;  /* last run duration in msec */
 
+       enum spf_type type;
        uint8_t sysid[ISIS_SYS_ID_LEN];
        uint16_t mtid;
        int family;
index 4e1d7b050f4fcebadbb636eadd3801d1c6a06fb6..dae906b956c7f7974833b2474dfe02d69f1246ec 100644 (file)
@@ -38,6 +38,7 @@
 
 enum test_type {
        TEST_SPF = 1,
+       TEST_REVERSE_SPF,
 };
 
 #define F_DISPLAY_LSPDB 0x01
@@ -51,13 +52,15 @@ static struct isis *isis;
 static void test_run_spf(struct vty *vty, const struct isis_topology *topology,
                         const struct isis_test_node *root,
                         struct isis_area *area, struct lspdb_head *lspdb,
-                        int level, int tree)
+                        int level, int tree, bool reverse)
 {
        struct isis_spftree *spftree;
+       enum spf_type spf_type;
 
        /* Run SPF. */
+       spf_type = reverse ? SPF_TYPE_REVERSE : SPF_TYPE_FORWARD;
        spftree = isis_spftree_new(area, lspdb, root->sysid, level, tree,
-                                  F_SPFTREE_NO_ADJACENCIES);
+                                  spf_type, F_SPFTREE_NO_ADJACENCIES);
        isis_run_spf(spftree);
 
        /* Print the SPT and the corresponding routing table. */
@@ -110,7 +113,12 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
                        case TEST_SPF:
                                test_run_spf(vty, topology, root, area,
                                             &area->lspdb[level - 1], level,
-                                            tree);
+                                            tree, false);
+                               break;
+                       case TEST_REVERSE_SPF:
+                               test_run_spf(vty, topology, root, area,
+                                            &area->lspdb[level - 1], level,
+                                            tree, true);
                                break;
                        }
                }
@@ -126,7 +134,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
 }
 
 DEFUN(test_isis, test_isis_cmd,
-      "test isis topology (1-13) root HOSTNAME spf\
+      "test isis topology (1-13) root HOSTNAME\
+         <\
+          spf\
+          |reverse-spf\
+        >\
         [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
       "Test command\n"
       "IS-IS routing protocol\n"
@@ -135,6 +147,7 @@ DEFUN(test_isis, test_isis_cmd,
       "SPF root\n"
       "SPF root hostname\n"
       "Normal Shortest Path First\n"
+      "Reverse Shortest Path First\n"
       "Display the LSPDB\n"
       "Do IPv4 processing only\n"
       "Do IPv6 processing only\n"
@@ -144,6 +157,7 @@ DEFUN(test_isis, test_isis_cmd,
        uint16_t topology_number;
        const struct isis_topology *topology;
        const struct isis_test_node *root;
+       enum test_type test_type;
        uint8_t flags = 0;
        int idx = 0;
 
@@ -165,6 +179,14 @@ DEFUN(test_isis, test_isis_cmd,
                return CMD_WARNING;
        }
 
+       /* Parse test information. */
+       if (argv_find(argv, argc, "spf", &idx))
+               test_type = TEST_SPF;
+       else if (argv_find(argv, argc, "reverse-spf", &idx))
+               test_type = TEST_REVERSE_SPF;
+       else
+               return CMD_WARNING;
+
        /* Parse control flags. */
        if (argv_find(argv, argc, "display-lspdb", &idx))
                SET_FLAG(flags, F_DISPLAY_LSPDB);
@@ -177,7 +199,7 @@ DEFUN(test_isis, test_isis_cmd,
        else if (argv_find(argv, argc, "level-2-only", &idx))
                SET_FLAG(flags, F_LEVEL2_ONLY);
 
-       return test_run(vty, topology, root, TEST_SPF, flags);
+       return test_run(vty, topology, root, test_type, flags);
 }
 
 static void vty_do_exit(int isexit)
index 28d3c59e1ec22baf09571a8e734a5256a33cd45f..d9a61782e99551d5d21d682b19852f0f72c0d622 100644 (file)
@@ -11,3 +11,6 @@ test isis topology 10 root rt1 spf
 test isis topology 11 root rt1 spf
 test isis topology 12 root rt1 spf ipv4-only
 test isis topology 13 root rt1 spf ipv4-only
+
+test isis topology 4 root rt1 reverse-spf ipv4-only
+test isis topology 11 root rt1 reverse-spf
index ee82926197c69840ff5649e11bda7332808b416e..ed0569947cc056ad189ddc24bceccfe76c22aa01 100644 (file)
@@ -615,5 +615,89 @@ IS-IS L1 IPv4 routing table:
  10.0.255.6/32  30      -          rt3      -         \r
  10.0.255.7/32  40      -          rt3      -         \r
 \r
+test# \r
+test# test isis topology 4 root rt1 reverse-spf ipv4-only\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt8                  TE-IS        40     rt2                  -         rt6(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+10.0.255.8/32        IP TE        50     rt2                  -         rt8(4)\r
+\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.2/32  20      -          rt2      -         \r
+ 10.0.255.3/32  20      -          rt3      -         \r
+ 10.0.255.4/32  30      -          rt2      -         \r
+ 10.0.255.5/32  30      -          rt3      -         \r
+ 10.0.255.6/32  40      -          rt2      -         \r
+ 10.0.255.7/32  40      -          rt3      -         \r
+ 10.0.255.8/32  50      -          rt2      -         \r
+\r
+test# test isis topology 11 root rt1 reverse-spf\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10                                    rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt2                  pseudo_TE-IS 20     rt3                  -         rt3(4)\r
+rt4                  TE-IS        20                                    rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20                                    rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt4(4)\r
+                                                                        rt5(4)\r
+10.0.255.4/32        IP TE        30                                    rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt3                  -         rt6(4)\r
+\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.3/32  20      -          rt3      -         \r
+ 10.0.255.5/32  30      -          rt3      -         \r
+ 10.0.255.6/32  40      -          rt3      -         \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt2                  TE-IS        10                                    rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt2                  pseudo_TE-IS 20     rt3                  -         rt3(4)\r
+rt4                  TE-IS        20                                    rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 20                                    rt2(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt4(4)\r
+                                                                        rt5(4)\r
+2001:db8::4/128      IP6 internal 30                                    rt4(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 40     rt3                  -         rt6(4)\r
+\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::3/128  20      -          rt3      -         \r
+ 2001:db8::5/128  30      -          rt3      -         \r
+ 2001:db8::6/128  40      -          rt3      -         \r
+\r
 test# 
 end.