summaryrefslogtreecommitdiffstats
path: root/isisd/isis_spf_private.h
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_spf_private.h')
-rw-r--r--isisd/isis_spf_private.h412
1 files changed, 412 insertions, 0 deletions
diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h
new file mode 100644
index 0000000..7636730
--- /dev/null
+++ b/isisd/isis_spf_private.h
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * 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>
+ */
+#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;
+};
+
+struct isis_vertex_adj {
+ struct isis_spf_adj *sadj;
+ struct isis_sr_psid_info sr;
+ struct mpls_label_stack *label_stack;
+ uint32_t lfa_metric;
+};
+
+/*
+ * Triple <N, d(N), {Adj(N)}>
+ */
+struct isis_vertex {
+ enum vertextype type;
+ union {
+ uint8_t id[ISIS_SYS_ID_LEN + 1];
+ struct {
+ struct prefix_pair p;
+ struct isis_sr_psid_info sr;
+ enum spf_prefix_priority priority;
+ } ip;
+ } 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 */
+ struct hash *firsthops; /* first two hops to neighbor */
+ uint64_t insert_counter;
+ uint8_t flags;
+};
+#define F_ISIS_VERTEX_LFA_PROTECTED 0x01
+
+/* 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(const void *vp)
+{
+ const struct isis_vertex *vertex = vp;
+
+ if (VTYPE_IP(vertex->type)) {
+ uint32_t key;
+
+ key = prefix_hash_key(&vertex->N.ip.p.dest);
+ key = jhash_1word(prefix_hash_key(&vertex->N.ip.p.src), key);
+ return key;
+ }
+
+ return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
+}
+
+__attribute__((__unused__))
+static bool 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 false;
+
+ if (VTYPE_IP(va->type)) {
+ if (prefix_cmp(&va->N.ip.p.dest, &vb->N.ip.p.dest))
+ return false;
+
+ return prefix_cmp((const struct prefix *)&va->N.ip.p.src,
+ (const struct prefix *)&vb->N.ip.p.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(const void *a,
+ const void *b)
+{
+ const struct isis_vertex *va = a;
+ const 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);
+}
+
+void isis_vertex_del(struct isis_vertex *vertex);
+
+bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
+ const struct isis_vertex *vertex,
+ const struct isis_spf_adj *sadj);
+void isis_vertex_adj_free(void *arg);
+struct isis_vertex_adj *
+isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
+ struct list *vadj_list, struct isis_spf_adj *sadj,
+ struct isis_prefix_sid *psid, bool last_hop);
+
+__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(&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)
+{
+ struct listnode *tail;
+
+ assert(!queue->insert_counter);
+ tail = listtail(queue->l.list);
+ assert(tail);
+ return listgetdata(tail);
+}
+
+__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 route_table *route_table_backup;
+ struct lspdb_head *lspdb; /* link-state db */
+ struct hash *prefix_sids; /* SR Prefix-SIDs. */
+ struct list *sadj_list;
+ struct isis_spf_nodes adj_nodes;
+ 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 */
+
+ enum spf_type type;
+ uint8_t sysid[ISIS_SYS_ID_LEN];
+ uint16_t mtid;
+ int family;
+ int level;
+ enum spf_tree_id tree_id;
+ struct {
+ /* Original pre-failure local SPTs. */
+ struct {
+ struct isis_spftree *spftree;
+ struct isis_spftree *spftree_reverse;
+ } old;
+
+ /* Protected resource. */
+ struct lfa_protected_resource protected_resource;
+
+ /* P-space and Q-space. */
+ struct isis_spf_nodes p_space;
+ struct isis_spf_nodes q_space;
+
+ /* Remote LFA related information. */
+ struct {
+ /* List of RLFAs eligible to be installed. */
+ struct rlfa_tree_head rlfas;
+
+ /*
+ * RLFA post-convergence SPTs (needed to activate RLFAs
+ * once label information is received from LDP).
+ */
+ struct list *pc_spftrees;
+
+ /* RLFA maximum metric (or zero if absent). */
+ uint32_t max_metric;
+ } remote;
+
+ /* Protection counters. */
+ struct {
+ uint32_t lfa[SPF_PREFIX_PRIO_MAX];
+ uint32_t rlfa[SPF_PREFIX_PRIO_MAX];
+ uint32_t tilfa[SPF_PREFIX_PRIO_MAX];
+ uint32_t ecmp[SPF_PREFIX_PRIO_MAX];
+ uint32_t total[SPF_PREFIX_PRIO_MAX];
+ } protection_counters;
+ } lfa;
+ uint8_t algorithm;
+ uint8_t flags;
+};
+#define F_SPFTREE_HOPCOUNT_METRIC 0x01
+#define F_SPFTREE_NO_ROUTES 0x02
+#define F_SPFTREE_NO_ADJACENCIES 0x04
+#ifndef FABRICD
+/* flex-algo */
+#define F_SPFTREE_DISABLED 0x08
+#endif /* ifndef FABRICD */
+
+__attribute__((__unused__))
+static void isis_vertex_id_init(struct isis_vertex *vertex, const void *id,
+ enum vertextype vtype)
+{
+ vertex->type = vtype;
+
+ if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
+ memcpy(vertex->N.id, id, ISIS_SYS_ID_LEN + 1);
+ } else if (VTYPE_IP(vtype)) {
+ memcpy(&vertex->N.ip.p, id, sizeof(vertex->N.ip.p));
+ } else {
+ flog_err(EC_LIB_DEVELOPMENT, "Unknown Vertex Type");
+ }
+}
+
+__attribute__((__unused__))
+static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
+ const void *id,
+ enum vertextype vtype)
+{
+ struct isis_vertex querier;
+
+ isis_vertex_id_init(&querier, id, 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;
+
+ struct isis_lsp *lsp = lsp_search(spftree->lspdb, lsp_id);
+
+ if (lsp && lsp->hdr.rem_lifetime != 0)
+ return lsp;
+
+ return NULL;
+}
+
+#define VID2STR_BUFFER SRCDEST2STR_BUFFER
+const char *vtype2string(enum vertextype vtype);
+const char *vid2string(const struct isis_vertex *vertex, char *buff, int size);
+
+#endif