Signed-off-by: Christian Franke <chris@opensourcerouting.org>
+bool
+adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
+{
+ for (unsigned int i = 0; i < adj->mt_count; i++)
+ if (adj->mt_set[i] == mtid)
+ return true;
+ return false;
+}
+
void
adj_mt_finish(struct isis_adjacency *adj)
{
void
adj_mt_finish(struct isis_adjacency *adj)
{
+/* TLV Router info api */
+struct mt_router_info*
+tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
+{
+ return lookup_mt_setting(tlvs->mt_router_info, mtid);
+}
+
/* TLV MT Neighbors api */
struct tlv_mt_neighbors*
tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
/* TLV MT Neighbors api */
struct tlv_mt_neighbors*
tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
uint16_t isis_area_ipv6_topology(struct isis_area *area);
uint16_t isis_area_ipv6_topology(struct isis_area *area);
+struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid);
+
struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
unsigned int *mt_count);
bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
struct isis_adjacency *adj);
unsigned int *mt_count);
bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
struct isis_adjacency *adj);
+bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
void adj_mt_finish(struct isis_adjacency *adj);
void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
int level, struct te_is_neigh *neigh);
void adj_mt_finish(struct isis_adjacency *adj);
void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
int level, struct te_is_neigh *neigh);
#include "isis_spf.h"
#include "isis_route.h"
#include "isis_csm.h"
#include "isis_spf.h"
#include "isis_route.h"
#include "isis_csm.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
struct prefix prefix;
struct ipv6_reachability *ip6reach;
static const u_char null_sysid[ISIS_SYS_ID_LEN];
struct prefix prefix;
struct ipv6_reachability *ip6reach;
static const u_char null_sysid[ISIS_SYS_ID_LEN];
+ struct mt_router_info *mt_router_info = NULL;
- if (!pseudo_lsp && !speaks (lsp->tlv_data.nlpids, spftree->family))
+ if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
+ mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, spftree->mtid);
+
+ if (!pseudo_lsp
+ && (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks(lsp->tlv_data.nlpids, spftree->family))
+ && !mt_router_info)
return ISIS_OK;
lspfragloop:
return ISIS_OK;
lspfragloop:
#endif /* EXTREME_DEBUG */
/* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
#endif /* EXTREME_DEBUG */
/* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
- if (pseudo_lsp || !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+ if (pseudo_lsp
+ || (spftree->mtid == ISIS_MT_IPV4_UNICAST && !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+ || (mt_router_info && !mt_router_info->overload))
+
- if (lsp->tlv_data.is_neighs)
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
{
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
{
{
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
{
(void *) is_neigh->neigh_id, dist, depth + 1, parent);
}
}
(void *) is_neigh->neigh_id, dist, depth + 1, parent);
}
}
- if (lsp->tlv_data.te_is_neighs)
- {
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
- te_is_neigh))
+
+ struct list *te_is_neighs = NULL;
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ te_is_neighs = lsp->tlv_data.te_is_neighs;
+ }
+ else
+ {
+ struct tlv_mt_neighbors *mt_neighbors;
+ mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, spftree->mtid);
+ if (mt_neighbors)
+ te_is_neighs = mt_neighbors->list;
+ }
+ for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
{
if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
{
if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
: VTYPE_NONPSEUDO_TE_IS,
(void *) te_is_neigh->neigh_id, dist, depth + 1, parent);
}
: VTYPE_NONPSEUDO_TE_IS,
(void *) te_is_neigh->neigh_id, dist, depth + 1, parent);
}
- if (!pseudo_lsp && spftree->family == AF_INET)
+ if (!pseudo_lsp
+ && spftree->family == AF_INET
+ && spftree->mtid == ISIS_MT_IPV4_UNICAST)
{
struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
lsp->tlv_data.ipv4_ext_reachs};
{
struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
lsp->tlv_data.ipv4_ext_reachs};
+ }
+
+ if (!pseudo_lsp && spftree->family == AF_INET)
+ {
+ struct list *ipv4reachs = NULL;
+
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv4_reachs *mt_reachs;
+ mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, spftree->mtid);
+ if (mt_reachs)
+ ipv4reachs = mt_reachs->list;
+ }
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
- node, te_ipv4_reach))
+ prefix.family = AF_INET;
+ for (ALL_LIST_ELEMENTS_RO (ipv4reachs, node, te_ipv4_reach))
{
assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
{
assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
- if (!pseudo_lsp && spftree->family == AF_INET6)
+ if (!pseudo_lsp
+ && spftree->family == AF_INET6)
+ struct list *ipv6reachs = NULL;
+
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ {
+ ipv6reachs = lsp->tlv_data.ipv6_reachs;
+ }
+ else
+ {
+ struct tlv_mt_ipv6_reachs *mt_reachs;
+ mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, spftree->mtid);
+ if (mt_reachs)
+ ipv6reachs = mt_reachs->list;
+ }
+
prefix.family = AF_INET6;
prefix.family = AF_INET6;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
+ for (ALL_LIST_ELEMENTS_RO (ipv6reachs, node, ip6reach))
{
assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
{
assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
struct prefix_ipv6 *ipv6;
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
struct prefix_ipv6 *ipv6;
+ struct isis_circuit_mt_setting *circuit_mt;
for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
{
for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
{
+ circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
+ if (circuit_mt && !circuit_mt->enabled)
+ continue;
if (circuit->state != C_STATE_UP)
continue;
if (!(circuit->is_type & spftree->level))
if (circuit->state != C_STATE_UP)
continue;
if (!(circuit->is_type & spftree->level))
}
for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
{
}
for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
{
- if (!speaks (&adj->nlpids, spftree->family))
- continue;
+ if (!adj_has_mt(adj, spftree->mtid))
+ continue;
+ if (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks (&adj->nlpids, spftree->family))
+ continue;
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
adj = circuit->u.p2p.neighbor;
if (!adj)
continue;
adj = circuit->u.p2p.neighbor;
if (!adj)
continue;
+ if (!adj_has_mt(adj, spftree->mtid))
+ continue;
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (lsp_id) = 0;
LSP_FRAGMENT (lsp_id) = 0;
memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (lsp_id) = 0;
LSP_FRAGMENT (lsp_id) = 0;
- if (speaks (&adj->nlpids, spftree->family))
+ if (spftree->mtid != ISIS_MT_IPV4_UNICAST || speaks (&adj->nlpids, spftree->family))
isis_spf_add_local (spftree,
spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS,
isis_spf_add_local (spftree,
spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS,
-init_spt (struct isis_spftree *spftree, int level, int family)
+init_spt (struct isis_spftree *spftree, int mtid, int level, int family)
{
spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
list_delete_all_node (spftree->tents);
list_delete_all_node (spftree->paths);
spftree->tents->del = spftree->paths->del = NULL;
{
spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
list_delete_all_node (spftree->tents);
list_delete_all_node (spftree->paths);
spftree->tents->del = spftree->paths->del = NULL;
spftree->level = level;
spftree->family = family;
return;
spftree->level = level;
spftree->family = family;
return;
struct route_table *table = NULL;
struct timeval time_now;
unsigned long long start_time, end_time;
struct route_table *table = NULL;
struct timeval time_now;
unsigned long long start_time, end_time;
/* Get time that can't roll backwards. */
monotime(&time_now);
/* Get time that can't roll backwards. */
monotime(&time_now);
isis_route_invalidate_table (area, table);
isis_route_invalidate_table (area, table);
+ /* We only support ipv4-unicast and ipv6-unicast as topologies for now */
+ if (family == AF_INET6)
+ mtid = isis_area_ipv6_topology(area);
+ else
+ mtid = ISIS_MT_IPV4_UNICAST;
+
- init_spt (spftree, level, family);
+ init_spt (spftree, mtid, level, family);
/* a) */
root_vertex = isis_spf_add_root (spftree, sysid);
/* b) */
/* a) */
root_vertex = isis_spf_add_root (spftree, sysid);
/* b) */
time_t last_run_timestamp; /* last run timestamp for scheduling */
time_t last_run_duration; /* last run duration in msec */
time_t last_run_timestamp; /* last run timestamp for scheduling */
time_t last_run_duration; /* last run duration in msec */
int family;
int level;
};
int family;
int level;
};