diff options
Diffstat (limited to 'isisd/isis_spf.c')
| -rw-r--r-- | isisd/isis_spf.c | 84 |
1 files changed, 76 insertions, 8 deletions
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 690ea9f1a5..58b0cf2684 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -33,11 +33,13 @@ #include "memory.h" #include "prefix.h" #include "if.h" +#include "hash.h" #include "table.h" #include "spf_backoff.h" #include "srcdest_table.h" #include "vrf.h" +#include "isis_errors.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" @@ -184,6 +186,36 @@ const char *vid2string(const struct isis_vertex *vertex, char *buff, int size) return "UNKNOWN"; } +static bool prefix_sid_cmp(const void *value1, const void *value2) +{ + const struct isis_vertex *c1 = value1; + const struct isis_vertex *c2 = value2; + + if (CHECK_FLAG(c1->N.ip.sr.sid.flags, + ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL) + != CHECK_FLAG(c2->N.ip.sr.sid.flags, + ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) + return false; + + return c1->N.ip.sr.sid.value == c2->N.ip.sr.sid.value; +} + +static unsigned int prefix_sid_key_make(const void *value) +{ + const struct isis_vertex *vertex = value; + + return jhash_1word(vertex->N.ip.sr.sid.value, 0); +} + +struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree, + struct isis_prefix_sid *psid) +{ + struct isis_vertex lookup = {}; + + lookup.N.ip.sr.sid = *psid; + return hash_lookup(spftree->prefix_sids, &lookup); +} + static void isis_vertex_adj_free(void *arg) { struct isis_vertex_adj *vadj = arg; @@ -310,6 +342,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area, tree->route_table_backup->cleanup = isis_route_node_cleanup; tree->area = area; tree->lspdb = lspdb; + tree->prefix_sids = hash_create(prefix_sid_key_make, prefix_sid_cmp, + "SR Prefix-SID Entries"); tree->sadj_list = list_new(); tree->sadj_list->del = isis_spf_adj_free; tree->last_run_timestamp = 0; @@ -332,6 +366,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area, void isis_spftree_del(struct isis_spftree *spftree) { + hash_clean(spftree->prefix_sids, NULL); + hash_free(spftree->prefix_sids); if (spftree->type == SPF_TYPE_TI_LFA) { isis_spf_node_list_clear(&spftree->lfa.q_space); isis_spf_node_list_clear(&spftree->lfa.p_space); @@ -515,14 +551,39 @@ isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id, vertex->d_N = cost; vertex->depth = depth; if (VTYPE_IP(vtype) && psid) { - bool local; + struct isis_area *area = spftree->area; + struct isis_vertex *vertex_psid; + + /* + * Check if the Prefix-SID is already in use by another prefix. + */ + vertex_psid = isis_spf_prefix_sid_lookup(spftree, psid); + if (vertex_psid + && !prefix_same(&vertex_psid->N.ip.p.dest, + &vertex->N.ip.p.dest)) { + flog_warn( + EC_ISIS_SID_COLLISION, + "ISIS-Sr (%s): collision detected, prefixes %pFX and %pFX share the same SID %s (%u)", + area->area_tag, &vertex->N.ip.p.dest, + &vertex_psid->N.ip.p.dest, + CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE) + ? "label" + : "index", + psid->value); + psid = NULL; + } else { + bool local; + + local = (vertex->depth == 1); + vertex->N.ip.sr.sid = *psid; + vertex->N.ip.sr.label = + sr_prefix_in_label(area, psid, local); + if (vertex->N.ip.sr.label != MPLS_INVALID_LABEL) + vertex->N.ip.sr.present = true; - local = (vertex->depth == 1); - vertex->N.ip.sr.sid = *psid; - vertex->N.ip.sr.label = - sr_prefix_in_label(spftree->area, psid, local); - if (vertex->N.ip.sr.label != MPLS_INVALID_LABEL) - vertex->N.ip.sr.present = true; + hash_get(spftree->prefix_sids, vertex, + hash_alloc_intern); + } } if (parent) { @@ -1352,6 +1413,7 @@ static void add_to_paths(struct isis_spftree *spftree, static void init_spt(struct isis_spftree *spftree, int mtid) { /* Clear data from previous run. */ + hash_clean(spftree->prefix_sids, NULL); isis_spf_node_list_clear(&spftree->adj_nodes); list_delete_all_node(spftree->sadj_list); isis_vertex_queue_clear(&spftree->tents); @@ -1665,6 +1727,11 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level) return run; } +void isis_spf_timer_free(void *run) +{ + XFREE(MTYPE_ISIS_SPF_RUN, run); +} + int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line) { @@ -1744,7 +1811,8 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, "Vertex Type Metric Next-Hop Interface Parent\n"); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { - if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { + if (VTYPE_IS(vertex->type) + && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { vty_out(vty, "%-20s %-12s %-6s", print_sys_hostname(root_sysid), "", ""); vty_out(vty, "%-30s\n", ""); |
