summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorChristian Franke <chris@opensourcerouting.org>2017-04-27 13:56:41 +0200
committerChristian Franke <chris@opensourcerouting.org>2017-04-28 12:03:23 +0200
commitd8fba7d9742b93545a49b5e280825ecdf083d1a0 (patch)
tree035f80aeb7c4c32c4f498c49e935474d8e0f9118 /isisd
parentisisd: announce MT capabilities in IIH and LSP (diff)
downloadfrr-d8fba7d9742b93545a49b5e280825ecdf083d1a0.tar.xz
frr-d8fba7d9742b93545a49b5e280825ecdf083d1a0.zip
isisd: track intersecting set of supported MTs for each adj
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_adjacency.c19
-rw-r--r--isisd/isis_adjacency.h3
-rw-r--r--isisd/isis_mt.c84
-rw-r--r--isisd/isis_mt.h5
-rw-r--r--isisd/isis_pdu.c14
5 files changed, 124 insertions, 1 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index f55092487..c6fc6b008 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -148,6 +148,8 @@ isis_delete_adj (void *arg)
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
+ adj_mt_finish(adj);
+
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
@@ -521,3 +523,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)
return;
}
+
+int
+isis_adj_usage2levels(enum isis_adj_usage usage)
+{
+ switch (usage)
+ {
+ case ISIS_ADJ_LEVEL1:
+ return IS_LEVEL_1;
+ case ISIS_ADJ_LEVEL2:
+ return IS_LEVEL_2;
+ case ISIS_ADJ_LEVEL1AND2:
+ return IS_LEVEL_1 | IS_LEVEL_2;
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 8539b03d6..4f89e3096 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -97,6 +97,8 @@ struct isis_adjacency
int flaps; /* number of adjacency flaps */
struct thread *t_expire; /* expire after hold_time */
struct isis_circuit *circuit; /* back pointer */
+ uint16_t *mt_set; /* Topologies this adjacency is valid for */
+ unsigned int mt_count; /* Number of entries in mt_set */
};
struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb);
@@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);
void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
void isis_adj_build_up_list (struct list *adjdb, struct list *list);
+int isis_adj_usage2levels(enum isis_adj_usage usage);
#endif /* ISIS_ADJACENCY_H */
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index 6d43fdf03..4e36b9143 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -24,14 +24,19 @@
#include "isisd/isisd.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_tlv.h"
#include "isisd/isis_mt.h"
DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
/* MT naming api */
const char *isis_mtid2str(uint16_t mtid)
{
+ static char buf[sizeof("65535")];
+
switch(mtid)
{
case ISIS_MT_IPV4_UNICAST:
@@ -47,7 +52,8 @@ const char *isis_mtid2str(uint16_t mtid)
case ISIS_MT_IPV6_MGMT:
return "ipv6-mgmt";
default:
- return NULL;
+ snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
+ return buf;
}
}
@@ -355,3 +361,79 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
*mt_count = count;
return rv;
}
+
+static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
+ uint16_t mtid)
+{
+ if (adj->mt_count < index + 1)
+ {
+ adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
+ (index + 1) * sizeof(*adj->mt_set));
+ adj->mt_count = index + 1;
+ }
+ adj->mt_set[index] = mtid;
+}
+
+bool
+tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+ struct isis_adjacency *adj)
+{
+ struct isis_circuit_mt_setting **mt_settings;
+ unsigned int circuit_mt_count;
+
+ unsigned int intersect_count = 0;
+
+ uint16_t *old_mt_set;
+ unsigned int old_mt_count;
+
+ old_mt_count = adj->mt_count;
+ if (old_mt_count)
+ {
+ old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
+ memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
+ }
+
+ mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
+ for (unsigned int i = 0; i < circuit_mt_count; i++)
+ {
+ if (!tlvs->mt_router_info)
+ {
+ /* Other end does not have MT enabled */
+ if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST)
+ adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
+ }
+ else
+ {
+ struct listnode *node;
+ struct mt_router_info *info;
+ for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
+ {
+ if (mt_settings[i]->mtid == info->mtid)
+ adj_mt_set(adj, intersect_count++, info->mtid);
+ }
+ }
+ }
+ adj->mt_count = intersect_count;
+
+ bool changed = false;
+
+ if (adj->mt_count != old_mt_count)
+ changed = true;
+
+ if (!changed && old_mt_count
+ && memcmp(adj->mt_set, old_mt_set,
+ old_mt_count * sizeof(*old_mt_set)))
+ changed = true;
+
+ if (old_mt_count)
+ XFREE(MTYPE_TMP, old_mt_set);
+
+ return changed;
+}
+
+void
+adj_mt_finish(struct isis_adjacency *adj)
+{
+ XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
+ adj->mt_count = 0;
+}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index 6b1711f4c..3ad8c05e4 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -67,8 +67,10 @@ struct isis_circuit_mt_setting {
const char *isis_mtid2str(uint16_t mtid);
uint16_t isis_str2mtid(const char *name);
+struct isis_adjacency;
struct isis_area;
struct isis_circuit;
+struct tlvs;
struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
uint16_t mtid);
@@ -102,4 +104,7 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting(
int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
unsigned int *mt_count);
+bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+ struct isis_adjacency *adj);
+void adj_mt_finish(struct isis_adjacency *adj);
#endif
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 8909eb31e..9e90acf2e 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -635,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit)
if (found & TLVFLAG_IPV6_ADDR)
tlvs_to_adj_ipv6_addrs (&tlvs, adj);
+ bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -871,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit)
/* down - area mismatch */
isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
}
+
+ if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+ {
+ lsp_regenerate_schedule(adj->circuit->area,
+ isis_adj_usage2levels(adj->adj_usage), 0);
+ }
+
/* 8.2.5.2 c) if the action was up - comparing circuit IDs */
/* FIXME - Missing parts */
@@ -1226,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
adj->circuit_t = hdr.circuit_t;
+ bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -1269,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
"no LAN Neighbours TLV found");
}
+ if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+ lsp_regenerate_schedule(adj->circuit->area, level, 0);
+
out:
if (isis->debugs & DEBUG_ADJ_PACKETS)
{