diff options
author | Christian Franke <chris@opensourcerouting.org> | 2018-05-10 18:52:17 +0200 |
---|---|---|
committer | Christian Franke <chris@opensourcerouting.org> | 2018-09-05 11:38:13 +0200 |
commit | cbd8e49e3ead018b67f630752a37c44fae0697cc (patch) | |
tree | b7caf2ac4408054be617d344172ec45b4f7d98f2 /isisd | |
parent | fabricd: run a hop-by-hop spf (diff) | |
download | frr-cbd8e49e3ead018b67f630752a37c44fae0697cc.tar.xz frr-cbd8e49e3ead018b67f630752a37c44fae0697cc.zip |
isisd: move spf datastructures to a header, to share with fabricd
By moving the spf datastructures to a header, fabricd can access the
results of the spf run for flooding optimization or fabric locality
calculation.
While this was deemed a sensible choice in this case, when compared with
the option of adding a lot of OpenFabric specific code to isis_spf.c,
the datastructures should still not be accessed randomly all over the
code base. To make this more clear, the new header was called
isis_spf_private.h (Think of a friend class)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r-- | isisd/isis_spf.c | 312 | ||||
-rw-r--r-- | isisd/isis_spf_private.h | 351 | ||||
-rw-r--r-- | isisd/subdir.am | 1 |
3 files changed, 364 insertions, 300 deletions
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1e2052b65..79b310323 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -31,14 +31,10 @@ #include "command.h" #include "memory.h" #include "prefix.h" -#include "hash.h" #include "if.h" #include "table.h" #include "spf_backoff.h" -#include "jhash.h" -#include "skiplist.h" #include "srcdest_table.h" -#include "lib_errors.h" #include "isis_constants.h" #include "isis_common.h" @@ -57,257 +53,10 @@ #include "isis_mt.h" #include "isis_tlvs.h" #include "fabricd.h" +#include "isis_spf_private.h" DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); -enum vertextype { - VTYPE_PSEUDO_IS = 1, - VTYPE_PSEUDO_TE_IS, - VTYPE_NONPSEUDO_IS, - VTYPE_NONPSEUDO_TE_IS, - VTYPE_ES, - VTYPE_IPREACH_INTERNAL, - VTYPE_IPREACH_EXTERNAL, - VTYPE_IPREACH_TE, - VTYPE_IP6REACH_INTERNAL, - VTYPE_IP6REACH_EXTERNAL -}; - -#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS) -#define VTYPE_ES(t) ((t) == VTYPE_ES) -#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) - -struct prefix_pair { - struct prefix dest; - struct prefix_ipv6 src; -}; - -/* - * Triple <N, d(N), {Adj(N)}> - */ -union isis_N { - uint8_t id[ISIS_SYS_ID_LEN + 1]; - struct prefix_pair ip; -}; -struct isis_vertex { - enum vertextype type; - union isis_N N; - uint32_t d_N; /* d(N) Distance from this IS */ - uint16_t depth; /* The depth in the imaginary tree */ - struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ - struct list *parents; /* list of parents for ECMP */ - uint64_t insert_counter; -}; - -/* Vertex Queue and associated functions */ - -struct isis_vertex_queue { - union { - struct skiplist *slist; - struct list *list; - } l; - struct hash *hash; - uint64_t insert_counter; -}; - -static unsigned isis_vertex_queue_hash_key(void *vp) -{ - struct isis_vertex *vertex = vp; - - if (VTYPE_IP(vertex->type)) { - uint32_t key; - - key = prefix_hash_key(&vertex->N.ip.dest); - key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key); - return key; - } - - return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a); -} - -static int isis_vertex_queue_hash_cmp(const void *a, const void *b) -{ - const struct isis_vertex *va = a, *vb = b; - - if (va->type != vb->type) - return 0; - - if (VTYPE_IP(va->type)) { - if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest)) - return 0; - - return prefix_cmp((struct prefix *)&va->N.ip.src, - (struct prefix *)&vb->N.ip.src) == 0; - } - - return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0; -} - -/* - * Compares vertizes for sorting in the TENT list. Returns true - * if candidate should be considered before current, false otherwise. - */ -static int isis_vertex_queue_tent_cmp(void *a, void *b) -{ - struct isis_vertex *va = a; - struct isis_vertex *vb = b; - - if (va->d_N < vb->d_N) - return -1; - - if (va->d_N > vb->d_N) - return 1; - - if (va->type < vb->type) - return -1; - - if (va->type > vb->type) - return 1; - - if (va->insert_counter < vb->insert_counter) - return -1; - - if (va->insert_counter > vb->insert_counter) - return 1; - - return 0; -} - -static struct skiplist *isis_vertex_queue_skiplist(void) -{ - return skiplist_new(0, isis_vertex_queue_tent_cmp, NULL); -} - -static void isis_vertex_queue_init(struct isis_vertex_queue *queue, - const char *name, bool ordered) -{ - if (ordered) { - queue->insert_counter = 1; - queue->l.slist = isis_vertex_queue_skiplist(); - } else { - queue->insert_counter = 0; - queue->l.list = list_new(); - } - queue->hash = hash_create(isis_vertex_queue_hash_key, - isis_vertex_queue_hash_cmp, name); -} - -static void isis_vertex_del(struct isis_vertex *vertex); - -static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) -{ - hash_clean(queue->hash, NULL); - - if (queue->insert_counter) { - struct isis_vertex *vertex; - while (0 == skiplist_first(queue->l.slist, NULL, - (void **)&vertex)) { - isis_vertex_del(vertex); - skiplist_delete_first(queue->l.slist); - } - queue->insert_counter = 1; - } else { - queue->l.list->del = (void (*)(void *))isis_vertex_del; - list_delete_all_node(queue->l.list); - queue->l.list->del = NULL; - } -} - -static void isis_vertex_queue_free(struct isis_vertex_queue *queue) -{ - isis_vertex_queue_clear(queue); - - hash_free(queue->hash); - queue->hash = NULL; - - if (queue->insert_counter) { - skiplist_free(queue->l.slist); - queue->l.slist = NULL; - } else - list_delete_and_null(&queue->l.list); -} - -static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue) -{ - return hashcount(queue->hash); -} - -static void isis_vertex_queue_append(struct isis_vertex_queue *queue, - struct isis_vertex *vertex) -{ - assert(!queue->insert_counter); - - listnode_add(queue->l.list, vertex); - - struct isis_vertex *inserted; - - inserted = hash_get(queue->hash, vertex, hash_alloc_intern); - assert(inserted == vertex); -} - -static void isis_vertex_queue_insert(struct isis_vertex_queue *queue, - struct isis_vertex *vertex) -{ - assert(queue->insert_counter); - vertex->insert_counter = queue->insert_counter++; - assert(queue->insert_counter != (uint64_t)-1); - - skiplist_insert(queue->l.slist, vertex, vertex); - - struct isis_vertex *inserted; - inserted = hash_get(queue->hash, vertex, hash_alloc_intern); - assert(inserted == vertex); -} - -static struct isis_vertex * -isis_vertex_queue_pop(struct isis_vertex_queue *queue) -{ - assert(queue->insert_counter); - - struct isis_vertex *rv; - - if (skiplist_first(queue->l.slist, NULL, (void **)&rv)) - return NULL; - - skiplist_delete_first(queue->l.slist); - hash_release(queue->hash, rv); - - return rv; -} - -static void isis_vertex_queue_delete(struct isis_vertex_queue *queue, - struct isis_vertex *vertex) -{ - assert(queue->insert_counter); - - skiplist_delete(queue->l.slist, vertex, vertex); - hash_release(queue->hash, vertex); -} - -#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \ - ALL_LIST_ELEMENTS_RO((queue)->l.list, node, data) - - -/* End of vertex queue definitions */ - -struct isis_spftree { - struct isis_vertex_queue paths; /* the SPT */ - struct isis_vertex_queue tents; /* TENT */ - struct route_table *route_table; - struct isis_area *area; /* back pointer to area */ - unsigned int runcount; /* number of runs since uptime */ - time_t last_run_timestamp; /* last run timestamp as wall time for display */ - time_t last_run_monotime; /* last run as monotime for scheduling */ - time_t last_run_duration; /* last run duration in msec */ - - uint16_t mtid; - int family; - int level; - enum spf_tree_id tree_id; - bool hopcount_metric; -}; - - /* * supports the given af ? */ @@ -430,20 +179,6 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size) return "UNKNOWN"; } -static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n, - enum vertextype vtype) -{ - vertex->type = vtype; - - if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { - memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1); - } else if (VTYPE_IP(vtype)) { - memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip)); - } else { - flog_err(LIB_ERR_DEVELOPMENT, "Unknown Vertex Type"); - } -} - static struct isis_vertex *isis_vertex_new(union isis_N *n, enum vertextype vtype) { @@ -459,17 +194,6 @@ static struct isis_vertex *isis_vertex_new(union isis_N *n, return vertex; } -static void isis_vertex_del(struct isis_vertex *vertex) -{ - list_delete_and_null(&vertex->Adj_N); - list_delete_and_null(&vertex->parents); - - memset(vertex, 0, sizeof(struct isis_vertex)); - XFREE(MTYPE_ISIS_VERTEX, vertex); - - return; -} - static void isis_vertex_adj_del(struct isis_vertex *vertex, struct isis_adjacency *adj) { @@ -626,16 +350,6 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, return vertex; } -static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, - union isis_N *n, - enum vertextype vtype) -{ - struct isis_vertex querier; - - isis_vertex_id_init(&querier, n, vtype); - return hash_lookup(queue->hash, &querier); -} - /* * Add a vertex to TENT sorted by cost and by vertextype on tie break situation */ @@ -1305,7 +1019,6 @@ 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)) { @@ -1319,19 +1032,18 @@ static void isis_spf_loop(struct isis_spftree *spftree, #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)); - } + if (!VTYPE_IS(vertex->type)) + continue; + + lsp = lsp_for_vertex(spftree, vertex); + if (!lsp) { + zlog_warn("ISIS-Spf: No LSP found for %s", + rawlspid_print(vertex->N.id)); /* FIXME */ + continue; } + + isis_spf_process_lsp(spftree, lsp, vertex->d_N, vertex->depth, + root_sysid, vertex); } } diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h new file mode 100644 index 000000000..3cd6a005b --- /dev/null +++ b/isisd/isis_spf_private.h @@ -0,0 +1,351 @@ +/* + * IS-IS Rout(e)ing protocol - isis_spf_private.h + * + * Copyright (C) 2001,2002 Sampo Saaristo + * Tampere University of Technology + * Institute of Communications Engineering + * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public Licenseas published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef ISIS_SPF_PRIVATE_H +#define ISIS_SPF_PRIVATE_H + +#include "hash.h" +#include "jhash.h" +#include "skiplist.h" +#include "lib_errors.h" + +enum vertextype { + VTYPE_PSEUDO_IS = 1, + VTYPE_PSEUDO_TE_IS, + VTYPE_NONPSEUDO_IS, + VTYPE_NONPSEUDO_TE_IS, + VTYPE_ES, + VTYPE_IPREACH_INTERNAL, + VTYPE_IPREACH_EXTERNAL, + VTYPE_IPREACH_TE, + VTYPE_IP6REACH_INTERNAL, + VTYPE_IP6REACH_EXTERNAL +}; + +#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS) +#define VTYPE_ES(t) ((t) == VTYPE_ES) +#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) + +struct prefix_pair { + struct prefix dest; + struct prefix_ipv6 src; +}; + +/* + * Triple <N, d(N), {Adj(N)}> + */ +union isis_N { + uint8_t id[ISIS_SYS_ID_LEN + 1]; + struct prefix_pair ip; +}; +struct isis_vertex { + enum vertextype type; + union isis_N N; + uint32_t d_N; /* d(N) Distance from this IS */ + uint16_t depth; /* The depth in the imaginary tree */ + struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ + struct list *parents; /* list of parents for ECMP */ + uint64_t insert_counter; +}; + +/* Vertex Queue and associated functions */ + +struct isis_vertex_queue { + union { + struct skiplist *slist; + struct list *list; + } l; + struct hash *hash; + uint64_t insert_counter; +}; + +__attribute__((__unused__)) +static unsigned isis_vertex_queue_hash_key(void *vp) +{ + struct isis_vertex *vertex = vp; + + if (VTYPE_IP(vertex->type)) { + uint32_t key; + + key = prefix_hash_key(&vertex->N.ip.dest); + key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key); + return key; + } + + return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a); +} + +__attribute__((__unused__)) +static int isis_vertex_queue_hash_cmp(const void *a, const void *b) +{ + const struct isis_vertex *va = a, *vb = b; + + if (va->type != vb->type) + return 0; + + if (VTYPE_IP(va->type)) { + if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest)) + return 0; + + return prefix_cmp((struct prefix *)&va->N.ip.src, + (struct prefix *)&vb->N.ip.src) == 0; + } + + return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0; +} + +/* + * Compares vertizes for sorting in the TENT list. Returns true + * if candidate should be considered before current, false otherwise. + */ +__attribute__((__unused__)) +static int isis_vertex_queue_tent_cmp(void *a, void *b) +{ + struct isis_vertex *va = a; + struct isis_vertex *vb = b; + + if (va->d_N < vb->d_N) + return -1; + + if (va->d_N > vb->d_N) + return 1; + + if (va->type < vb->type) + return -1; + + if (va->type > vb->type) + return 1; + + if (va->insert_counter < vb->insert_counter) + return -1; + + if (va->insert_counter > vb->insert_counter) + return 1; + + return 0; +} + +__attribute__((__unused__)) +static struct skiplist *isis_vertex_queue_skiplist(void) +{ + return skiplist_new(0, isis_vertex_queue_tent_cmp, NULL); +} + +__attribute__((__unused__)) +static void isis_vertex_queue_init(struct isis_vertex_queue *queue, + const char *name, bool ordered) +{ + if (ordered) { + queue->insert_counter = 1; + queue->l.slist = isis_vertex_queue_skiplist(); + } else { + queue->insert_counter = 0; + queue->l.list = list_new(); + } + queue->hash = hash_create(isis_vertex_queue_hash_key, + isis_vertex_queue_hash_cmp, name); +} + +__attribute__((__unused__)) +static void isis_vertex_del(struct isis_vertex *vertex) +{ + list_delete_and_null(&vertex->Adj_N); + list_delete_and_null(&vertex->parents); + + memset(vertex, 0, sizeof(struct isis_vertex)); + XFREE(MTYPE_ISIS_VERTEX, vertex); +} + +__attribute__((__unused__)) +static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) +{ + hash_clean(queue->hash, NULL); + + if (queue->insert_counter) { + struct isis_vertex *vertex; + while (0 == skiplist_first(queue->l.slist, NULL, + (void **)&vertex)) { + isis_vertex_del(vertex); + skiplist_delete_first(queue->l.slist); + } + queue->insert_counter = 1; + } else { + queue->l.list->del = (void (*)(void *))isis_vertex_del; + list_delete_all_node(queue->l.list); + queue->l.list->del = NULL; + } +} + +__attribute__((__unused__)) +static void isis_vertex_queue_free(struct isis_vertex_queue *queue) +{ + isis_vertex_queue_clear(queue); + + hash_free(queue->hash); + queue->hash = NULL; + + if (queue->insert_counter) { + skiplist_free(queue->l.slist); + queue->l.slist = NULL; + } else + list_delete_and_null(&queue->l.list); +} + +__attribute__((__unused__)) +static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue) +{ + return hashcount(queue->hash); +} + +__attribute__((__unused__)) +static void isis_vertex_queue_append(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + assert(!queue->insert_counter); + + listnode_add(queue->l.list, vertex); + + struct isis_vertex *inserted; + + inserted = hash_get(queue->hash, vertex, hash_alloc_intern); + assert(inserted == vertex); +} + +__attribute__((__unused__)) +static struct isis_vertex *isis_vertex_queue_last(struct isis_vertex_queue *queue) +{ + assert(!queue->insert_counter); + + return listgetdata(listtail(queue->l.list)); +} + +__attribute__((__unused__)) +static void isis_vertex_queue_insert(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + assert(queue->insert_counter); + vertex->insert_counter = queue->insert_counter++; + assert(queue->insert_counter != (uint64_t)-1); + + skiplist_insert(queue->l.slist, vertex, vertex); + + struct isis_vertex *inserted; + inserted = hash_get(queue->hash, vertex, hash_alloc_intern); + assert(inserted == vertex); +} + +__attribute__((__unused__)) +static struct isis_vertex * +isis_vertex_queue_pop(struct isis_vertex_queue *queue) +{ + assert(queue->insert_counter); + + struct isis_vertex *rv; + + if (skiplist_first(queue->l.slist, NULL, (void **)&rv)) + return NULL; + + skiplist_delete_first(queue->l.slist); + hash_release(queue->hash, rv); + + return rv; +} + +__attribute__((__unused__)) +static void isis_vertex_queue_delete(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + assert(queue->insert_counter); + + skiplist_delete(queue->l.slist, vertex, vertex); + hash_release(queue->hash, vertex); +} + +#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \ + ALL_LIST_ELEMENTS_RO((queue)->l.list, node, data) + +/* End of vertex queue definitions */ + +struct isis_spftree { + struct isis_vertex_queue paths; /* the SPT */ + struct isis_vertex_queue tents; /* TENT */ + struct route_table *route_table; + struct isis_area *area; /* back pointer to area */ + unsigned int runcount; /* number of runs since uptime */ + time_t last_run_timestamp; /* last run timestamp as wall time for display */ + time_t last_run_monotime; /* last run as monotime for scheduling */ + time_t last_run_duration; /* last run duration in msec */ + + uint16_t mtid; + int family; + int level; + enum spf_tree_id tree_id; + bool hopcount_metric; +}; + +__attribute__((__unused__)) +static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n, + enum vertextype vtype) +{ + vertex->type = vtype; + + if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { + memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1); + } else if (VTYPE_IP(vtype)) { + memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip)); + } else { + flog_err(LIB_ERR_DEVELOPMENT, "Unknown Vertex Type"); + } +} + +__attribute__((__unused__)) +static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, + union isis_N *n, + enum vertextype vtype) +{ + struct isis_vertex querier; + + isis_vertex_id_init(&querier, n, vtype); + return hash_lookup(queue->hash, &querier); +} + +__attribute__((__unused__)) +static struct isis_lsp *lsp_for_vertex(struct isis_spftree *spftree, + struct isis_vertex *vertex) +{ + uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; + + assert(VTYPE_IS(vertex->type)); + + memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); + LSP_FRAGMENT(lsp_id) = 0; + + dict_t *lspdb = spftree->area->lspdb[spftree->level - 1]; + struct isis_lsp *lsp = lsp_search(lsp_id, lspdb); + + if (lsp && lsp->hdr.rem_lifetime != 0) + return lsp; + + return NULL; +} + +#endif diff --git a/isisd/subdir.am b/isisd/subdir.am index cd8bfdbdd..792b0df6c 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -37,6 +37,7 @@ noinst_HEADERS += \ isisd/isis_route.h \ isisd/isis_routemap.h \ isisd/isis_spf.h \ + isisd/isis_spf_private.h \ isisd/isis_te.h \ isisd/isis_tlvs.h \ isisd/isis_vty_common.h \ |