]> git.puffer.fish Git - mirror/frr.git/commitdiff
fabricd: run a hop-by-hop spf
authorChristian Franke <chris@opensourcerouting.org>
Mon, 2 Apr 2018 16:39:46 +0000 (18:39 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Wed, 5 Sep 2018 09:38:13 +0000 (11:38 +0200)
OpenFabric uses an spf with the metric for all links set to one,
both for flooding optimization and for fabric locality detection.

So extend isisd's spf code to allow running it with such a metric
and have it run whenever normal spf runs.

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
isisd/fabricd.c
isisd/fabricd.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isisd.c

index d37e6a71d87031428f3becfca9f75af25fc9c2b2..853b672075a8852e3b4b3f8b80052b3a3cef09e5 100644 (file)
@@ -26,6 +26,7 @@
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_adjacency.h"
+#include "isisd/isis_spf.h"
 
 DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
 
@@ -45,16 +46,27 @@ struct fabricd {
        time_t initial_sync_start;
        struct isis_circuit *initial_sync_circuit;
        struct thread *initial_sync_timeout;
+
+       struct isis_spftree *spftree;
 };
 
-struct fabricd *fabricd_new(void)
+struct fabricd *fabricd_new(struct isis_area *area)
 {
        struct fabricd *rv = XCALLOC(MTYPE_FABRICD_STATE, sizeof(*rv));
 
        rv->initial_sync_state = FABRICD_SYNC_PENDING;
+       rv->spftree = isis_spftree_new(area);
        return rv;
 };
 
+void fabricd_finish(struct fabricd *f)
+{
+       if (f->initial_sync_timeout)
+               thread_cancel(f->initial_sync_timeout);
+
+       isis_spftree_del(f->spftree);
+}
+
 static int fabricd_initial_sync_timeout(struct thread *thread)
 {
        struct fabricd *f = THREAD_ARG(thread);
@@ -134,3 +146,23 @@ void fabricd_initial_sync_finish(struct isis_area *area)
        thread_cancel(f->initial_sync_timeout);
        f->initial_sync_timeout = NULL;
 }
+
+void fabricd_run_spf(struct isis_area *area)
+{
+       struct fabricd *f = area->fabricd;
+
+       if (!f)
+               return;
+
+       isis_run_hopcount_spf(area, isis->sysid, f->spftree);
+}
+
+struct isis_spftree *fabricd_spftree(struct isis_area *area)
+{
+       struct fabricd *f = area->fabricd;
+
+       if (!f)
+               return NULL;
+
+       return f->spftree;
+}
index 35a5bb6a3b2661649d822adc49319ba333bd19f5..1707adf36eb45b78ef7084b91cca97e855ab6c9f 100644 (file)
@@ -26,11 +26,15 @@ struct fabricd;
 
 struct isis_circuit;
 struct isis_area;
+struct isis_spftree;
 
-struct fabricd *fabricd_new(void);
+struct fabricd *fabricd_new(struct isis_area *area);
+void fabricd_finish(struct fabricd *f);
 void fabricd_initial_sync_hello(struct isis_circuit *circuit);
 bool fabricd_initial_sync_is_in_progress(struct isis_area *area);
 struct isis_circuit *fabricd_initial_sync_circuit(struct isis_area *area);
 void fabricd_initial_sync_finish(struct isis_area *area);
+void fabricd_run_spf(struct isis_area *area);
+struct isis_spftree *fabricd_spftree(struct isis_area *area);
 
 #endif
index 5b47d3e684f503db84017266ceed9dfd40d11c30..1e2052b652c675f08e614c41b696e0b7726e29b9 100644 (file)
@@ -56,6 +56,7 @@
 #include "isis_csm.h"
 #include "isis_mt.h"
 #include "isis_tlvs.h"
+#include "fabricd.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
 
@@ -303,6 +304,7 @@ struct isis_spftree {
        int family;
        int level;
        enum spf_tree_id tree_id;
+       bool hopcount_metric;
 };
 
 
@@ -563,6 +565,9 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
                                             adj);
                }
        }
+
+       if (fabricd_spftree(area) != NULL)
+               isis_spftree_adj_del(fabricd_spftree(area), adj);
 }
 
 /*
@@ -722,6 +727,10 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
 
        assert(spftree && parent);
 
+       if (spftree->hopcount_metric
+           && !VTYPE_IS(vtype))
+               return;
+
        struct prefix_pair p;
        if (vtype >= VTYPE_IPREACH_INTERNAL) {
                memcpy(&p, id, sizeof(p));
@@ -889,7 +898,7 @@ lspfragloop:
                        if (!pseudo_lsp
                            && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
                                continue;
-                       dist = cost + er->metric;
+                       dist = cost + (spftree->hopcount_metric ? 1 : er->metric);
                        process_N(spftree,
                                  LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
                                                        : VTYPE_NONPSEUDO_TE_IS,
@@ -1037,7 +1046,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                /*
                 * Add IP(v6) addresses of this circuit
                 */
-               if (spftree->family == AF_INET) {
+               if (spftree->family == AF_INET && !spftree->hopcount_metric) {
                        memset(&ip_info, 0, sizeof(ip_info));
                        ip_info.dest.family = AF_INET;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
@@ -1050,7 +1059,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                                   &ip_info, NULL, 0, parent);
                        }
                }
-               if (spftree->family == AF_INET6) {
+               if (spftree->family == AF_INET6 && !spftree->hopcount_metric) {
                        memset(&ip_info, 0, sizeof(ip_info));
                        ip_info.dest.family = AF_INET6;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
@@ -1094,6 +1103,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                        LSP_PSEUDO_ID(lsp_id) = 0;
                                        isis_spf_add_local(
                                                spftree, VTYPE_ES, lsp_id, adj,
+                                               spftree->hopcount_metric ? 1 :
                                                circuit->te_metric
                                                        [spftree->level - 1],
                                                parent);
@@ -1111,6 +1121,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                                        ? VTYPE_NONPSEUDO_IS
                                                        : VTYPE_NONPSEUDO_TE_IS,
                                                lsp_id, adj,
+                                               spftree->hopcount_metric ? 1 :
                                                circuit->te_metric
                                                        [spftree->level - 1],
                                                parent);
@@ -1180,10 +1191,10 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                        circuit->circuit_id);
                                continue;
                        }
-                       isis_spf_process_lsp(
-                               spftree, lsp,
-                               circuit->te_metric[spftree->level - 1], 0,
-                               root_sysid, parent);
+                       isis_spf_process_lsp(spftree, lsp,
+                                            spftree->hopcount_metric ?
+                                            1 : circuit->te_metric[spftree->level - 1],
+                                            0, root_sysid, parent);
                } else if (circuit->circ_type == CIRCUIT_T_P2P) {
                        adj = circuit->u.p2p.neighbor;
                        if (!adj || adj->adj_state != ISIS_ADJ_UP)
@@ -1196,6 +1207,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                LSP_PSEUDO_ID(lsp_id) = 0;
                                isis_spf_add_local(
                                        spftree, VTYPE_ES, lsp_id, adj,
+                                       spftree->hopcount_metric ? 1 :
                                        circuit->te_metric[spftree->level - 1],
                                        parent);
                                break;
@@ -1215,6 +1227,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                                        ? VTYPE_NONPSEUDO_IS
                                                        : VTYPE_NONPSEUDO_TE_IS,
                                                lsp_id, adj,
+                                               spftree->hopcount_metric ? 1 :
                                                circuit->te_metric
                                                        [spftree->level - 1],
                                                parent);
@@ -1275,7 +1288,8 @@ static void add_to_paths(struct isis_spftree *spftree,
 }
 
 static void init_spt(struct isis_spftree *spftree, int mtid, int level,
-                    int family, enum spf_tree_id tree_id)
+                    int family, enum spf_tree_id tree_id,
+                    bool hopcount_metric)
 {
        isis_vertex_queue_clear(&spftree->tents);
        isis_vertex_queue_clear(&spftree->paths);
@@ -1284,7 +1298,64 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
        spftree->level = level;
        spftree->family = family;
        spftree->tree_id = tree_id;
-       return;
+       spftree->hopcount_metric = hopcount_metric;
+}
+
+static void isis_spf_loop(struct isis_spftree *spftree,
+                         uint8_t *root_sysid)
+{
+       struct isis_vertex *vertex;
+       uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
+       struct isis_lsp *lsp;
+
+       while (isis_vertex_queue_count(&spftree->tents)) {
+               vertex = isis_vertex_queue_pop(&spftree->tents);
+
+#ifdef EXTREME_DEBUG
+               zlog_debug(
+                       "ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
+                       print_sys_hostname(vertex->N.id),
+                       vtype2string(vertex->type), vertex->depth, vertex->d_N);
+#endif /* EXTREME_DEBUG */
+
+               add_to_paths(spftree, vertex);
+               if (VTYPE_IS(vertex->type)) {
+                       memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
+                       LSP_FRAGMENT(lsp_id) = 0;
+                       lsp = lsp_search(lsp_id, spftree->area->lspdb[spftree->level - 1]);
+                       if (lsp && lsp->hdr.rem_lifetime != 0) {
+                               isis_spf_process_lsp(spftree, lsp, vertex->d_N,
+                                                    vertex->depth, root_sysid,
+                                                    vertex);
+                       } else {
+                               zlog_warn("ISIS-Spf: No LSP found for %s",
+                                         rawlspid_print(lsp_id));
+                       }
+               }
+       }
+}
+
+struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
+                                          uint8_t *sysid,
+                                          struct isis_spftree *spftree)
+{
+       if (!spftree)
+               spftree = isis_spftree_new(area);
+
+       init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2,
+                AF_INET, SPFTREE_IPV4, true);
+       if (!memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN)) {
+               /* If we are running locally, initialize with information from adjacencies */
+               struct isis_vertex *root = isis_spf_add_root(spftree, sysid);
+               isis_spf_preload_tent(spftree, sysid, root);
+       } else {
+               isis_vertex_queue_insert(&spftree->tents, isis_vertex_new(
+                                        sysid, VTYPE_NONPSEUDO_TE_IS));
+       }
+
+       isis_spf_loop(spftree, sysid);
+
+       return spftree;
 }
 
 static int isis_run_spf(struct isis_area *area, int level,
@@ -1292,11 +1363,8 @@ static int isis_run_spf(struct isis_area *area, int level,
                        uint8_t *sysid, struct timeval *nowtv)
 {
        int retval = ISIS_OK;
-       struct isis_vertex *vertex;
        struct isis_vertex *root_vertex;
        struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
-       uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
-       struct isis_lsp *lsp;
        struct timeval time_now;
        unsigned long long start_time, end_time;
        uint16_t mtid = 0;
@@ -1330,7 +1398,7 @@ static int isis_run_spf(struct isis_area *area, int level,
        /*
         * C.2.5 Step 0
         */
-       init_spt(spftree, mtid, level, family, tree_id);
+       init_spt(spftree, mtid, level, family, tree_id, false);
        /*              a) */
        root_vertex = isis_spf_add_root(spftree, sysid);
        /*              b) */
@@ -1350,32 +1418,7 @@ static int isis_run_spf(struct isis_area *area, int level,
                          print_sys_hostname(sysid));
        }
 
-       while (isis_vertex_queue_count(&spftree->tents)) {
-               vertex = isis_vertex_queue_pop(&spftree->tents);
-
-#ifdef EXTREME_DEBUG
-               zlog_debug(
-                       "ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
-                       print_sys_hostname(vertex->N.id),
-                       vtype2string(vertex->type), vertex->depth, vertex->d_N);
-#endif /* EXTREME_DEBUG */
-
-               add_to_paths(spftree, vertex);
-               if (VTYPE_IS(vertex->type)) {
-                       memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
-                       LSP_FRAGMENT(lsp_id) = 0;
-                       lsp = lsp_search(lsp_id, area->lspdb[level - 1]);
-                       if (lsp && lsp->hdr.rem_lifetime != 0) {
-                               isis_spf_process_lsp(spftree, lsp, vertex->d_N,
-                                                    vertex->depth, sysid,
-                                                    vertex);
-                       } else {
-                               zlog_warn("ISIS-Spf: No LSP found for %s",
-                                         rawlspid_print(lsp_id));
-                       }
-               }
-       }
-
+       isis_spf_loop(spftree, sysid);
 out:
        spftree->runcount++;
        spftree->last_run_timestamp = time(NULL);
@@ -1446,6 +1489,8 @@ static int isis_run_spf_cb(struct thread *thread)
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
                UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
 
+       fabricd_run_spf(area);
+
        return retval;
 }
 
@@ -1666,6 +1711,13 @@ DEFUN (show_isis_topology,
                        }
                }
 
+               if (fabricd_spftree(area)) {
+                       vty_out(vty,
+                               "IS-IS paths to level-2 routers with hop-by-hop metric\n");
+                       isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid);
+                       vty_out(vty, "\n");
+               }
+
                vty_out(vty, "\n");
        }
 
index 9a73ca8783dd3b6d766eb2b73b21fe45692773b0..0532bd5465fe8c4f680f9cc4b131561869275b32 100644 (file)
@@ -37,4 +37,8 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj);
 int isis_spf_schedule(struct isis_area *area, int level);
 void isis_spf_cmds_init(void);
 void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
+struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
+                                          uint8_t *sysid,
+                                          struct isis_spftree *spftree);
+
 #endif /* _ZEBRA_ISIS_SPF_H */
index e8efa391e0dee3dd2ef20035c37916a65896ab3e..cc5463ffe7a0855c08a058220e99bd3da11eb336 100644 (file)
@@ -159,7 +159,7 @@ struct isis_area *isis_area_create(const char *area_tag)
        area->isis = isis;
 
        if (fabricd)
-               area->fabricd = fabricd_new();
+               area->fabricd = fabricd_new(area);
        QOBJ_REG(area, isis_area);
 
        return area;
@@ -216,6 +216,9 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
 
        QOBJ_UNREG(area);
 
+       if (fabricd)
+               fabricd_finish(area->fabricd);
+
        if (area->circuit_list) {
                for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
                                       circuit)) {