]> git.puffer.fish Git - mirror/frr.git/commitdiff
fabricd: implement flooding optimization
authorChristian Franke <chris@opensourcerouting.org>
Thu, 10 May 2018 15:40:04 +0000 (17:40 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Wed, 5 Sep 2018 09:38:13 +0000 (11:38 +0200)
Regular IS-IS will flood any LSP updates out to all circuits except the
one where it was received on. This is done in `lsp_flood`.

Change `lsp_flood` for fabricd to use the optimized flooding algorithm
instead.

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

index 25252a05649afed0b430abf6df90ecdc110da174..95718f3bdd06f265caab439dc7da20cbc594ce8e 100644 (file)
@@ -119,6 +119,45 @@ static int neighbor_entry_list_cmp(void *a, void *b)
        return -memcmp(na->vertex->N.id, nb->vertex->N.id, ISIS_SYS_ID_LEN);
 }
 
+static struct neighbor_entry *neighbor_entry_lookup_list(struct skiplist *list,
+                                                        const uint8_t *id)
+{
+       struct isis_vertex querier;
+       isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
+
+       struct neighbor_entry n = {
+               .vertex = &querier
+       };
+
+       struct neighbor_entry *rv;
+
+       if (skiplist_search(list, &n, (void**)&rv))
+               return NULL;
+
+       if (!rv->present)
+               return NULL;
+
+       return rv;
+}
+
+static struct neighbor_entry *neighbor_entry_lookup_hash(struct hash *hash,
+                                                        const uint8_t *id)
+{
+       struct isis_vertex querier;
+       isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
+
+       struct neighbor_entry n = {
+               .vertex = &querier
+       };
+
+       struct neighbor_entry *rv = hash_lookup(hash, &n);
+
+       if (!rv || !rv->present)
+               return NULL;
+
+       return rv;
+}
+
 static void neighbor_lists_update(struct fabricd *f)
 {
        neighbor_lists_clear(f);
@@ -446,3 +485,120 @@ int fabricd_write_settings(struct isis_area *area, struct vty *vty)
 
        return written;
 }
+
+static void move_to_dnr(struct isis_lsp *lsp, struct neighbor_entry *n)
+{
+       struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
+
+       n->present = false;
+       if (adj) {
+               isis_tx_queue_add(adj->circuit->tx_queue, lsp,
+                                 TX_LSP_CIRCUIT_SCOPED);
+       }
+}
+
+static void move_to_rf(struct isis_lsp *lsp, struct neighbor_entry *n)
+{
+       struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
+
+       n->present = false;
+       if (adj) {
+               isis_tx_queue_add(adj->circuit->tx_queue, lsp,
+                                 TX_LSP_NORMAL);
+       }
+}
+
+static void mark_neighbor_as_present(struct hash_backet *backet, void *arg)
+{
+       struct neighbor_entry *n = backet->data;
+
+       n->present = true;
+}
+
+static void handle_firsthops(struct hash_backet *backet, void *arg)
+{
+       struct isis_lsp *lsp = arg;
+       struct fabricd *f = lsp->area->fabricd;
+       struct isis_vertex *vertex = backet->data;
+
+       struct neighbor_entry *n;
+
+       n = neighbor_entry_lookup_list(f->neighbors, vertex->N.id);
+       if (n)
+               n->present = false;
+
+       n = neighbor_entry_lookup_hash(f->neighbors_neighbors, vertex->N.id);
+       if (n)
+               n->present = false;
+}
+
+void fabricd_lsp_flood(struct isis_lsp *lsp)
+{
+       struct fabricd *f = lsp->area->fabricd;
+       assert(f);
+
+       void *cursor = NULL;
+       struct neighbor_entry *n;
+
+       /* Mark all elements in NL as present and move T0s into DNR */
+       while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
+               n->present = true;
+
+               struct isis_lsp *lsp = lsp_for_vertex(f->spftree, n->vertex);
+               if (!lsp || !lsp->tlvs || !lsp->tlvs->spine_leaf)
+                       continue;
+
+               if (!lsp->tlvs->spine_leaf->has_tier
+                   || lsp->tlvs->spine_leaf->tier != 0)
+                       continue;
+
+               move_to_dnr(lsp, n);
+       }
+
+       /* Mark all elements in NN as present */
+       hash_iterate(f->neighbors_neighbors, mark_neighbor_as_present, NULL);
+
+       struct isis_vertex *originator = isis_find_vertex(&f->spftree->paths,
+                                                         lsp->hdr.lsp_id,
+                                                         VTYPE_NONPSEUDO_TE_IS);
+
+       /* Remove all IS from NL and NN in the shortest path
+        * to the IS that originated the LSP */
+       if (originator)
+               hash_iterate(originator->firsthops, handle_firsthops, lsp);
+
+       /* Iterate over all remaining IS in NL */
+       cursor = NULL;
+       while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
+               if (!n->present)
+                       continue;
+
+               struct isis_lsp *nlsp = lsp_for_vertex(f->spftree, n->vertex);
+               if (!nlsp || !nlsp->tlvs) {
+                       move_to_dnr(lsp, n);
+                       continue;
+               }
+
+               /* For all neighbors of the NL IS check whether they are present
+                * in NN. If yes, remove from NN and set need_reflood. */
+               bool need_reflood = false;
+               struct isis_extended_reach *er;
+               for (er = (struct isis_extended_reach *)nlsp->tlvs->extended_reach.head;
+                    er; er = er->next) {
+                       struct neighbor_entry *nn;
+
+                       nn = neighbor_entry_lookup_hash(f->neighbors_neighbors,
+                                                       er->id);
+
+                       if (nn) {
+                               nn->present = false;
+                               need_reflood = true;
+                       }
+               }
+
+               if (need_reflood)
+                       move_to_rf(lsp, n);
+               else
+                       move_to_dnr(lsp, n);
+       }
+}
index a6dc9797296e433bacde22e1ddc919e225f18c9a..da07c5d814df033da577e3cde419ccb91b1b3ef2 100644 (file)
@@ -27,6 +27,7 @@ struct fabricd;
 struct isis_circuit;
 struct isis_area;
 struct isis_spftree;
+struct isis_lsp;
 struct vty;
 
 struct fabricd *fabricd_new(struct isis_area *area);
@@ -40,5 +41,6 @@ struct isis_spftree *fabricd_spftree(struct isis_area *area);
 void fabricd_configure_tier(struct isis_area *area, uint8_t tier);
 uint8_t fabricd_tier(struct isis_area *area);
 int fabricd_write_settings(struct isis_area *area, struct vty *vty);
+void fabricd_lsp_flood(struct isis_lsp *lsp);
 
 #endif
index 2598572248901b371b543461568ba81ff6a7821a..dc387379239f865cf0d07e330a1e00db97db935d 100644 (file)
@@ -1972,7 +1972,11 @@ void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
 
 void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit)
 {
-       lsp_set_all_srmflags(lsp);
-       if (circuit)
-               isis_tx_queue_del(circuit->tx_queue, lsp);
+       if (!fabricd) {
+               lsp_set_all_srmflags(lsp, true);
+               if (circuit)
+                       isis_tx_queue_del(circuit->tx_queue, lsp);
+       } else {
+               fabricd_lsp_flood(lsp);
+       }
 }
index 4478c7a997ecf12ab4bee30d44978801c3cf39a7..2c6514d470b48a4c3cf7f3617d188196acbf4e2b 100644 (file)
@@ -309,7 +309,7 @@ struct isis_spftree {
 };
 
 __attribute__((__unused__))
-static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
+static void isis_vertex_id_init(struct isis_vertex *vertex, const union isis_N *n,
                                enum vertextype vtype)
 {
        vertex->type = vtype;