summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2022-01-18 16:12:08 +0100
committerGitHub <noreply@github.com>2022-01-18 16:12:08 +0100
commit18ed776ca29533f6c49479b1a0dd95d36bb6b5ec (patch)
tree2b03c65d7b92d5988f660f4f477191e14e6a3cc8 /isisd
parentMerge pull request #9644 from opensourcerouting/ospf-opaque-attrs (diff)
parenttopotests: Add new IS-IS Traffic Engineering tests (diff)
downloadfrr-18ed776ca29533f6c49479b1a0dd95d36bb6b5ec.tar.xz
frr-18ed776ca29533f6c49479b1a0dd95d36bb6b5ec.zip
Merge pull request #9938 from Orange-OpenSource/isis_ls
isisd: Add Link State Traffic Engineering support
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_adjacency.c23
-rw-r--r--isisd/isis_adjacency.h12
-rw-r--r--isisd/isis_bfd.c11
-rw-r--r--isisd/isis_circuit.c10
-rw-r--r--isisd/isis_cli.c71
-rw-r--r--isisd/isis_lfa.c5
-rw-r--r--isisd/isis_lsp.c67
-rw-r--r--isisd/isis_mt.c11
-rw-r--r--isisd/isis_mt.h2
-rw-r--r--isisd/isis_nb.c15
-rw-r--r--isisd/isis_nb.h10
-rw-r--r--isisd/isis_nb_config.c94
-rw-r--r--isisd/isis_pdu.c5
-rw-r--r--isisd/isis_route.c4
-rw-r--r--isisd/isis_snmp.c7
-rw-r--r--isisd/isis_sr.c18
-rw-r--r--isisd/isis_te.c1370
-rw-r--r--isisd/isis_te.h21
-rw-r--r--isisd/isis_tlvs.c349
-rw-r--r--isisd/isis_tlvs.h8
-rw-r--r--isisd/isis_zebra.c28
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c42
-rw-r--r--isisd/isisd.h9
24 files changed, 2024 insertions, 169 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 9529adb09..d75613f30 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -168,7 +168,7 @@ void isis_delete_adj(void *arg)
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
- XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
+ XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs);
adj_mt_finish(adj);
list_delete(&adj->adj_sids);
@@ -420,11 +420,11 @@ void isis_adj_print(struct isis_adjacency *adj)
zlog_debug("%pI4", &adj->ipv4_addresses[i]);
}
- if (adj->ipv6_address_count) {
+ if (adj->ll_ipv6_count) {
zlog_debug("IPv6 Address(es):");
- for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+ for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
char buf[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf,
+ inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
sizeof(buf));
zlog_debug("%s", buf);
}
@@ -583,12 +583,21 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, " %pI4\n",
&adj->ipv4_addresses[i]);
}
- if (adj->ipv6_address_count) {
+ if (adj->ll_ipv6_count) {
vty_out(vty, " IPv6 Address(es):\n");
- for (unsigned int i = 0; i < adj->ipv6_address_count;
+ for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i],
+ buf, sizeof(buf));
+ vty_out(vty, " %s\n", buf);
+ }
+ }
+ if (adj->global_ipv6_count) {
+ vty_out(vty, " Global IPv6 Address(es):\n");
+ for (unsigned int i = 0; i < adj->global_ipv6_count;
i++) {
char buf[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &adj->ipv6_addresses[i],
+ inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
buf, sizeof(buf));
vty_out(vty, " %s\n", buf);
}
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 4aa553e30..af70775a8 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -88,8 +88,10 @@ struct isis_adjacency {
struct in_addr *ipv4_addresses;
unsigned int ipv4_address_count;
struct in_addr router_address;
- struct in6_addr *ipv6_addresses;
- unsigned int ipv6_address_count;
+ struct in6_addr *ll_ipv6_addrs; /* Link local IPv6 neighbor address */
+ unsigned int ll_ipv6_count;
+ struct in6_addr *global_ipv6_addrs; /* Global IPv6 neighbor address */
+ unsigned int global_ipv6_count;
struct in6_addr router_address6;
uint8_t prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */
int circuit_t; /* from hello PDU hdr */
@@ -127,9 +129,11 @@ void isis_adj_process_threeway(struct isis_adjacency *adj,
enum isis_adj_usage adj_usage);
DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
DECLARE_HOOK(isis_adj_ip_enabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family));
+ (struct isis_adjacency * adj, int family, bool global),
+ (adj, family, global));
DECLARE_HOOK(isis_adj_ip_disabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family));
+ (struct isis_adjacency * adj, int family, bool global),
+ (adj, family, global));
void isis_log_adj_change(struct isis_adjacency *adj,
enum isis_adj_state old_state,
enum isis_adj_state new_state, const char *reason);
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index a7548e2f1..1f50fb934 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -81,7 +81,7 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj)
*/
if (circuit->ipv6_router
&& (listcount(circuit->ipv6_link) == 0
- || adj->ipv6_address_count == 0)) {
+ || adj->ll_ipv6_count == 0)) {
if (IS_DEBUG_BFD)
zlog_debug(
"ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
@@ -93,9 +93,9 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj)
* If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
* creating a BFD session over IPv6.
*/
- if (circuit->ipv6_router && adj->ipv6_address_count) {
+ if (circuit->ipv6_router && adj->ll_ipv6_count) {
family = AF_INET6;
- dst_ip.ipv6 = adj->ipv6_addresses[0];
+ dst_ip.ipv6 = adj->ll_ipv6_addrs[0];
local_ips = circuit->ipv6_link;
if (!local_ips || list_isempty(local_ips)) {
if (IS_DEBUG_BFD)
@@ -181,10 +181,11 @@ void isis_bfd_circuit_cmd(struct isis_circuit *circuit)
}
}
-static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family)
+static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family,
+ bool global)
{
- if (family != AF_INET6)
+ if (family != AF_INET6 || global)
return 0;
if (adj->bfd_session)
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index a91bbd0b9..0ad6190ba 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -335,8 +335,16 @@ void isis_circuit_add_addr(struct isis_circuit *circuit,
if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix))
listnode_add(circuit->ipv6_link, ipv6);
- else
+ else {
listnode_add(circuit->ipv6_non_link, ipv6);
+ /* Update Local IPv6 address param. if MPLS TE is on */
+ if (circuit->ext && circuit->area
+ && IS_MPLS_TE(circuit->area->mta)) {
+ IPV6_ADDR_COPY(&circuit->ext->local_addr6,
+ &ipv6->prefix);
+ SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR6);
+ }
+ }
if (circuit->area)
lsp_regenerate_schedule(circuit->area, circuit->is_type,
0);
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 21162045a..9feabfa01 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1140,6 +1140,43 @@ void cli_show_isis_mpls_te_router_addr(struct vty *vty,
yang_dnode_get_string(dnode, NULL));
}
+/*
+ * XPath: /frr-isisd:isis/instance/mpls-te/router-address-v6
+ */
+DEFPY_YANG(isis_mpls_te_router_addr_v6, isis_mpls_te_router_addr_v6_cmd,
+ "mpls-te router-address ipv6 X:X::X:X",
+ MPLS_TE_STR
+ "Stable IP address of the advertising router\n"
+ "IPv6 address\n"
+ "MPLS-TE router address in IPv6 address format\n")
+{
+ nb_cli_enqueue_change(vty, "./mpls-te/router-address-v6", NB_OP_MODIFY,
+ ipv6_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_isis_mpls_te_router_addr_v6, no_isis_mpls_te_router_addr_v6_cmd,
+ "no mpls-te router-address ipv6 [X:X::X:X]",
+ NO_STR MPLS_TE_STR
+ "Delete IP address of the advertising router\n"
+ "IPv6 address\n"
+ "MPLS-TE router address in IPv6 address format\n")
+{
+ nb_cli_enqueue_change(vty, "./mpls-te/router-address-v6", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_te_router_addr_ipv6(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " mpls-te router-address ipv6 %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
DEFPY_YANG(isis_mpls_te_inter_as, isis_mpls_te_inter_as_cmd,
"[no] mpls-te inter-as [level-1|level-1-2|level-2-only]",
NO_STR MPLS_TE_STR
@@ -1153,6 +1190,36 @@ DEFPY_YANG(isis_mpls_te_inter_as, isis_mpls_te_inter_as_cmd,
}
/*
+ * XPath: /frr-isisd:isis/instance/mpls-te/export
+ */
+DEFPY_YANG(isis_mpls_te_export, isis_mpls_te_export_cmd, "mpls-te export",
+ MPLS_TE_STR "Enable export of MPLS-TE Link State information\n")
+{
+ nb_cli_enqueue_change(vty, "./mpls-te/export", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_isis_mpls_te_export, no_isis_mpls_te_export_cmd,
+ "no mpls-te export",
+ NO_STR MPLS_TE_STR
+ "Disable export of MPLS-TE Link State information\n")
+{
+ nb_cli_enqueue_change(vty, "./mpls-te/export", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_te_export(struct vty *vty, const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (!yang_dnode_get_bool(dnode, NULL))
+ vty_out(vty, " no");
+
+ vty_out(vty, " mpls-te export\n");
+}
+
+/*
* XPath: /frr-isisd:isis/instance/default-information-originate
*/
DEFPY_YANG(isis_default_originate, isis_default_originate_cmd,
@@ -3125,7 +3192,11 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &no_isis_mpls_te_on_cmd);
install_element(ISIS_NODE, &isis_mpls_te_router_addr_cmd);
install_element(ISIS_NODE, &no_isis_mpls_te_router_addr_cmd);
+ install_element(ISIS_NODE, &isis_mpls_te_router_addr_v6_cmd);
+ install_element(ISIS_NODE, &no_isis_mpls_te_router_addr_v6_cmd);
install_element(ISIS_NODE, &isis_mpls_te_inter_as_cmd);
+ install_element(ISIS_NODE, &isis_mpls_te_export_cmd);
+ install_element(ISIS_NODE, &no_isis_mpls_te_export_cmd);
install_element(ISIS_NODE, &isis_default_originate_cmd);
install_element(ISIS_NODE, &isis_redistribute_cmd);
diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c
index e033c28fe..84aac24d5 100644
--- a/isisd/isis_lfa.c
+++ b/isisd/isis_lfa.c
@@ -1443,9 +1443,8 @@ static mpls_label_t rlfa_nexthop_label(struct isis_spftree *spftree,
}
break;
case AF_INET6:
- for (unsigned int j = 0; j < adj->ipv6_address_count;
- j++) {
- struct in6_addr addr = adj->ipv6_addresses[j];
+ for (unsigned int j = 0; j < adj->ll_ipv6_count; j++) {
+ struct in6_addr addr = adj->ll_ipv6_addrs[j];
if (!IPV6_ADDR_SAME(
&addr,
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index e3de6f08c..92d329f03 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -124,6 +124,8 @@ static void lsp_destroy(struct isis_lsp *lsp)
ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
+ isis_te_lsp_event(lsp, LSP_DEL);
+
lsp_clear_data(lsp);
if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
@@ -335,6 +337,7 @@ void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
lsp_pack_pdu(lsp);
isis_spf_schedule(lsp->area, lsp->level);
+ isis_te_lsp_event(lsp, LSP_INC);
}
static void lsp_purge_add_poi(struct isis_lsp *lsp,
@@ -570,8 +573,10 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
lsp_link_fragment(lsp, lsp0);
}
- if (lsp->hdr.seqno)
+ if (lsp->hdr.seqno) {
isis_spf_schedule(lsp->area, lsp->level);
+ isis_te_lsp_event(lsp, LSP_UPD);
+ }
}
/* creation of LSP directly from what we received */
@@ -636,8 +641,10 @@ struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
{
lspdb_add(head, lsp);
- if (lsp->hdr.seqno)
+ if (lsp->hdr.seqno) {
isis_spf_schedule(lsp->area, lsp->level);
+ isis_te_lsp_event(lsp, LSP_ADD);
+ }
}
/*
@@ -1030,6 +1037,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
cap.srlb.lower_bound = srdb->config.srlb_lower_bound;
/* And finally MSD */
cap.msd = srdb->config.msd;
+ } else {
+ /* Disable SR Algorithm */
+ cap.algo[0] = SR_ALGORITHM_UNSET;
+ cap.algo[1] = SR_ALGORITHM_UNSET;
}
isis_tlvs_set_router_capability(lsp->tlvs, &cap);
@@ -1067,6 +1078,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
area->area_tag);
}
+ if (IS_MPLS_TE(area->mta)
+ && !IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
+ lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
+ area->area_tag);
+ isis_tlvs_set_te_router_id_ipv6(lsp->tlvs,
+ &area->mta->router_id_ipv6);
+ }
+
lsp_debug("ISIS (%s): Adding circuit specific information.",
area->area_tag);
@@ -1601,6 +1620,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
struct list *adj_list;
struct listnode *node;
struct isis_area *area = circuit->area;
+ uint16_t mtid;
lsp_clear_data(lsp);
lsp->tlvs = isis_alloc_tlvs();
@@ -1630,8 +1650,11 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
LSP_PSEUDO_ID(ne_id));
}
if (circuit->area->newmetric) {
- isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
- ne_id, 0, NULL);
+ if (area_is_mt(circuit->area))
+ mtid = ISIS_MT_IPV4_UNICAST;
+ else
+ mtid = ISIS_MT_DISABLE;
+ isis_tlvs_add_extended_reach(lsp->tlvs, mtid, ne_id, 0, NULL);
lsp_debug(
"ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
area->area_tag, sysid_print(ne_id),
@@ -2000,6 +2023,7 @@ int lsp_tick(struct thread *thread)
/* 7.3.16.4 c) record the time to purge
* FIXME */
isis_spf_schedule(lsp->area, lsp->level);
+ isis_te_lsp_event(lsp, LSP_TICK);
}
if (lsp->age_out == 0) {
@@ -2154,7 +2178,7 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
return LSP_ITER_CONTINUE;
- /* Parse main LSP. */
+ /* Parse LSP */
if (lsp->tlvs) {
if (!fabricd && !pseudo_lsp && family == AF_INET
&& mtid == ISIS_MT_IPV4_UNICAST) {
@@ -2224,13 +2248,17 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
}
}
- /* Parse LSP fragments. */
- for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
- if (!frag->tlvs)
- continue;
+ /* Parse LSP fragments if it is not a fragment itself */
+ if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
+ for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
+ if (!frag->tlvs)
+ continue;
- isis_lsp_iterate_ip_reach(frag, family, mtid, cb, arg);
- }
+ if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
+ arg)
+ == LSP_ITER_STOP)
+ return LSP_ITER_STOP;
+ }
return LSP_ITER_CONTINUE;
}
@@ -2251,7 +2279,7 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
return LSP_ITER_CONTINUE;
- /* Parse main LSP. */
+ /* Parse LSP */
if (lsp->tlvs) {
if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) {
head = lsp->tlvs->oldstyle_reach.head;
@@ -2283,13 +2311,16 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
}
}
- /* Parse LSP fragments. */
- for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
- if (!frag->tlvs)
- continue;
+ /* Parse LSP fragments if it not a fragment itself. */
+ if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
+ for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
+ if (!frag->tlvs)
+ continue;
- isis_lsp_iterate_is_reach(frag, mtid, cb, arg);
- }
+ if (isis_lsp_iterate_is_reach(frag, mtid, cb, arg)
+ == LSP_ITER_STOP)
+ return LSP_ITER_STOP;
+ }
return LSP_ITER_CONTINUE;
}
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index c024549fc..f937bdf55 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -515,6 +515,17 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
uint8_t *id, uint32_t metric,
struct isis_ext_subtlvs *ext)
{
+ /* Check if MT is enable for this area */
+ if (!area_is_mt(area)) {
+ lsp_debug(
+ "ISIS (%s): Adding %s.%02x as te-style neighbor (MT disable)",
+ area->area_tag, sysid_print(id), LSP_PSEUDO_ID(id));
+ isis_tlvs_add_extended_reach(tlvs, ISIS_MT_DISABLE, id, metric,
+ ext);
+ return;
+ }
+
+ /* Process Multi-Topology */
for (unsigned int i = 0; i < mt_count; i++) {
uint16_t mtid = mt_set[i];
if (mt_set[i] == ISIS_MT_IPV4_UNICAST) {
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index fd9ee133c..2952a2f17 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -33,6 +33,8 @@
#define ISIS_MT_IPV6_MULTICAST 4
#define ISIS_MT_IPV6_MGMT 5
#define ISIS_MT_IPV6_DSTSRC 3996 /* FIXME: IANA */
+/* Use first Reserved Flag to indicate that there is no MT Topology active */
+#define ISIS_MT_DISABLE 4096
#define ISIS_MT_NAMES \
"<ipv4-unicast" \
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index f62a8d481..20e480652 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -567,6 +567,21 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-isisd:isis/instance/mpls-te/router-address-v6",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_te_router_addr_ipv6,
+ .destroy = isis_instance_mpls_te_router_address_ipv6_destroy,
+ .modify = isis_instance_mpls_te_router_address_ipv6_modify,
+ }
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/mpls-te/export",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_te_export,
+ .modify = isis_instance_mpls_te_export_modify,
+ },
+ },
+ {
.xpath = "/frr-isisd:isis/instance/segment-routing/enabled",
.cbs = {
.modify = isis_instance_segment_routing_enabled_modify,
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index ee7904163..96de64a68 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -211,6 +211,11 @@ int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args);
int isis_instance_mpls_te_router_address_modify(struct nb_cb_modify_args *args);
int isis_instance_mpls_te_router_address_destroy(
struct nb_cb_destroy_args *args);
+int isis_instance_mpls_te_router_address_ipv6_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_mpls_te_router_address_ipv6_destroy(
+ struct nb_cb_destroy_args *args);
+int isis_instance_mpls_te_export_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_create(struct nb_cb_create_args *args);
int lib_interface_isis_destroy(struct nb_cb_destroy_args *args);
int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args);
@@ -463,6 +468,11 @@ void cli_show_isis_mpls_te(struct vty *vty, const struct lyd_node *dnode,
void cli_show_isis_mpls_te_router_addr(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_mpls_te_router_addr_ipv6(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_te_export(struct vty *vty, const struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_isis_def_origin_ipv4(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 3674d6937..b1c796668 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -33,6 +33,7 @@
#include "lib_errors.h"
#include "vrf.h"
#include "ldp_sync.h"
+#include "link_state.h"
#include "isisd/isisd.h"
#include "isisd/isis_nb.h"
@@ -51,6 +52,7 @@
#include "isisd/isis_redist.h"
#include "isisd/isis_ldp_sync.h"
#include "isisd/isis_dr.h"
+#include "isisd/isis_zebra.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters");
DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
@@ -1827,12 +1829,19 @@ int isis_instance_mpls_te_create(struct nb_cb_create_args *args)
new->inter_as = off;
new->interas_areaid.s_addr = 0;
new->router_id.s_addr = 0;
+ new->ted = ls_ted_new(1, "ISIS", 0);
+ if (!new->ted)
+ zlog_warn("Unable to create Link State Data Base");
area->mta = new;
} else {
area->mta->status = enable;
}
+ /* Initialize Link State Database */
+ if (area->mta->ted)
+ isis_te_init_ted(area);
+
/* Update Extended TLVs according to Interface link parameters */
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
isis_link_params_update(circuit, circuit->interface);
@@ -1858,6 +1867,9 @@ int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args)
else
return NB_OK;
+ /* Remove Link State Database */
+ ls_ted_del_all(area->mta->ted);
+
/* Flush LSP if circuit engage */
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if (!IS_EXT_TE(circuit->ext))
@@ -1930,6 +1942,88 @@ int isis_instance_mpls_te_router_address_destroy(
}
/*
+ * XPath: /frr-isisd:isis/instance/mpls-te/router-address-v6
+ */
+int isis_instance_mpls_te_router_address_ipv6_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct in6_addr value;
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ /* only proceed if MPLS-TE is enabled */
+ if (!IS_MPLS_TE(area->mta))
+ return NB_OK;
+
+ yang_dnode_get_ipv6(&value, args->dnode, NULL);
+ /* Update Area IPv6 Router ID if different */
+ if (!IPV6_ADDR_SAME(&area->mta->router_id_ipv6, &value)) {
+ IPV6_ADDR_COPY(&area->mta->router_id_ipv6, &value);
+
+ /* And re-schedule LSP update */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
+
+ return NB_OK;
+}
+
+int isis_instance_mpls_te_router_address_ipv6_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ /* only proceed if MPLS-TE is enabled */
+ if (!IS_MPLS_TE(area->mta))
+ return NB_OK;
+
+ /* Reset Area Router ID */
+ IPV6_ADDR_COPY(&area->mta->router_id_ipv6, &in6addr_any);
+
+ /* And re-schedule LSP update */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/mpls-te/export
+ */
+int isis_instance_mpls_te_export_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ /* only proceed if MPLS-TE is enabled */
+ if (!IS_MPLS_TE(area->mta))
+ return NB_OK;
+
+ area->mta->export = yang_dnode_get_bool(args->dnode, NULL);
+ if (area->mta->export) {
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("MPLS-TE: Enabled Link State export");
+ if (isis_zebra_ls_register(true) != 0)
+ zlog_warn("Unable to register Link State\n");
+ } else {
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("MPLS-TE: Disable Link State export");
+ if (isis_zebra_ls_register(false) != 0)
+ zlog_warn("Unable to register Link State\n");
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-isisd:isis/instance/segment-routing/enabled
*/
int isis_instance_segment_routing_enabled_modify(
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 7256fcbbc..0814f3eea 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -1971,6 +1971,11 @@ int send_hello(struct isis_circuit *circuit, int level)
if (circuit->ipv6_router && circuit->ipv6_link)
isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link);
+ /* RFC6119 section 4 define TLV 233 to provide Global IPv6 address */
+ if (circuit->ipv6_router && circuit->ipv6_non_link)
+ isis_tlvs_add_global_ipv6_addresses(tlvs,
+ circuit->ipv6_non_link);
+
if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
circuit->pad_hellos, false)) {
isis_free_tlvs(tlvs);
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index bf0079d81..764a0b0cd 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -145,8 +145,8 @@ void adjinfo2nexthop(int family, struct list *nexthops,
}
break;
case AF_INET6:
- for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
- ip.ipv6 = adj->ipv6_addresses[i];
+ for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
+ ip.ipv6 = adj->ll_ipv6_addrs[i];
if (!nexthoplookup(nexthops, AF_INET6, &ip,
adj->circuit->interface->ifindex)) {
diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c
index c530eb916..319977f41 100644
--- a/isisd/isis_snmp.c
+++ b/isisd/isis_snmp.c
@@ -1186,14 +1186,13 @@ static int isis_snmp_adj_helper(struct isis_adjacency *adj, int data_id,
break;
case ISIS_SNMP_ADJ_DATA_IP_ADDR:
- if (data_off
- >= (adj->ipv4_address_count + adj->ipv6_address_count))
+ if (data_off >= (adj->ipv4_address_count + adj->ll_ipv6_count))
return 0;
if (data_off >= adj->ipv4_address_count) {
- data = (uint8_t *)&adj->ipv6_addresses
+ data = (uint8_t *)&adj->ll_ipv6_addrs
[data_off - adj->ipv4_address_count];
- data_len = sizeof(adj->ipv6_addresses[0]);
+ data_len = sizeof(adj->ll_ipv6_addrs[0]);
} else {
data = (uint8_t *)&adj->ipv4_addresses[data_off];
data_len = sizeof(adj->ipv4_addresses[0]);
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index 54e31f004..18a727add 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -661,10 +661,10 @@ void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
nexthop.ipv4 = adj->ipv4_addresses[0];
break;
case AF_INET6:
- if (!circuit->ipv6_router || !adj->ipv6_address_count)
+ if (!circuit->ipv6_router || !adj->ll_ipv6_count)
return;
- nexthop.ipv6 = adj->ipv6_addresses[0];
+ nexthop.ipv6 = adj->ll_ipv6_addrs[0];
break;
default:
flog_err(EC_LIB_DEVELOPMENT,
@@ -880,12 +880,14 @@ static int sr_adj_state_change(struct isis_adjacency *adj)
*
* @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6)
+ * @param global Indicate if it concerns the Local or Global IPv6 addresses
*
* @return 0
*/
-static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
+static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family,
+ bool global)
{
- if (!adj->circuit->area->srdb.enabled)
+ if (!adj->circuit->area->srdb.enabled || global)
return 0;
sr_adj_sid_add(adj, family);
@@ -899,15 +901,17 @@ static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
*
* @param adj IS-IS Adjacency
* @param family Inet Family (IPv4 or IPv6)
+ * @param global Indicate if it concerns the Local or Global IPv6 addresses
*
* @return 0
*/
-static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
+static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family,
+ bool global)
{
struct sr_adjacency *sra;
struct listnode *node, *nnode;
- if (!adj->circuit->area->srdb.enabled)
+ if (!adj->circuit->area->srdb.enabled || global)
return 0;
for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
@@ -1148,7 +1152,7 @@ int isis_sr_start(struct isis_area *area)
for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
if (adj->ipv4_address_count > 0)
sr_adj_sid_add(adj, AF_INET);
- if (adj->ipv6_address_count > 0)
+ if (adj->ll_ipv6_count > 0)
sr_adj_sid_add(adj, AF_INET6);
}
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 8daa2b36b..93be70036 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -43,6 +43,8 @@
#include "sockunion.h"
#include "network.h"
#include "sbuf.h"
+#include "link_state.h"
+#include "lib/json.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
@@ -57,6 +59,8 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
+#include "isisd/isis_tlvs.h"
+#include "isisd/isis_mt.h"
#include "isisd/isis_te.h"
#include "isisd/isis_zebra.h"
@@ -82,14 +86,14 @@ void isis_link_params_update(struct isis_circuit *circuit,
if ((ifp == NULL) || (circuit->state != C_STATE_UP))
return;
- zlog_debug("TE(%s): Update circuit parameters for interface %s",
- circuit->area->area_tag, ifp->name);
+ te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
+ circuit->area->area_tag, ifp->name);
/* Check if MPLS TE Circuit context has not been already created */
if (circuit->ext == NULL) {
circuit->ext = isis_alloc_ext_subtlvs();
- zlog_debug(" |- Allocated new Ext-subTLVs for interface %s",
- ifp->name);
+ te_debug(" |- Allocated new Ext-subTLVs for interface %s",
+ ifp->name);
}
ext = circuit->ext;
@@ -113,19 +117,6 @@ void isis_link_params_update(struct isis_circuit *circuit,
} else
UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
- /* Same for Remote IPv4 address */
- if (circuit->circ_type == CIRCUIT_T_P2P) {
- struct isis_adjacency *adj = circuit->u.p2p.neighbor;
-
- if (adj && adj->adj_state == ISIS_ADJ_UP
- && adj->ipv4_address_count) {
- IPV4_ADDR_COPY(&ext->neigh_addr,
- &adj->ipv4_addresses[0]);
- SET_SUBTLV(ext, EXT_NEIGH_ADDR);
- }
- } else
- UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
-
/* If known, register local IPv6 addr from ip_addr list */
if (circuit->ipv6_non_link != NULL
&& listcount(circuit->ipv6_non_link) != 0) {
@@ -137,18 +128,12 @@ void isis_link_params_update(struct isis_circuit *circuit,
} else
UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
- /* Same for Remote IPv6 address */
- if (circuit->circ_type == CIRCUIT_T_P2P) {
- struct isis_adjacency *adj = circuit->u.p2p.neighbor;
-
- if (adj && adj->adj_state == ISIS_ADJ_UP
- && adj->ipv6_address_count) {
- IPV6_ADDR_COPY(&ext->neigh_addr6,
- &adj->ipv6_addresses[0]);
- SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
- }
- } else
- UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+ /*
+ * Remote IPv4 and IPv6 addresses are now added in
+ * isis_mpls_te_adj_ip_enabled() to get the right IP address
+ * in particular for IPv6 to get the global IPv6 address and
+ * not the link-local IPv6 address.
+ */
if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
ext->max_bw = ifp->link_params->max_bw;
@@ -231,11 +216,11 @@ void isis_link_params_update(struct isis_circuit *circuit,
UNSET_SUBTLV(ext, EXT_RMT_AS);
UNSET_SUBTLV(ext, EXT_RMT_IP);
}
- zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
- ext->status);
+ te_debug(" |- New MPLS-TE link parameters status 0x%x",
+ ext->status);
} else {
- zlog_debug(" |- Reset Extended subTLVs status 0x%x",
- ext->status);
+ te_debug(" |- Reset Extended subTLVs status 0x%x",
+ ext->status);
/* Reset TE subTLVs keeping SR one's */
if (IS_SUBTLV(ext, EXT_ADJ_SID))
ext->status = EXT_ADJ_SID;
@@ -248,29 +233,95 @@ void isis_link_params_update(struct isis_circuit *circuit,
return;
}
-static int isis_link_update_adj_hook(struct isis_adjacency *adj)
+static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
+ bool global)
{
+ struct isis_circuit *circuit;
+ struct isis_ext_subtlvs *ext;
- struct isis_circuit *circuit = adj->circuit;
+ /* Sanity Check */
+ if (!adj || !adj->circuit)
+ return 0;
- /* Update MPLS TE Remote IP address parameter if possible */
- if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
+ circuit = adj->circuit;
+
+ /* Check that MPLS TE is enabled */
+ if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext)
return 0;
- /* IPv4 first */
- if (adj->ipv4_address_count > 0) {
- IPV4_ADDR_COPY(&circuit->ext->neigh_addr,
- &adj->ipv4_addresses[0]);
- SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR);
+ ext = circuit->ext;
+
+ /* Determine nexthop IP address */
+ switch (family) {
+ case AF_INET:
+ if (!circuit->ip_router || !adj->ipv4_address_count)
+ UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
+ else {
+ IPV4_ADDR_COPY(&ext->neigh_addr,
+ &adj->ipv4_addresses[0]);
+ SET_SUBTLV(ext, EXT_NEIGH_ADDR);
+ }
+ break;
+ case AF_INET6:
+ if (!global)
+ return 0;
+
+ if (!circuit->ipv6_router || !adj->global_ipv6_count)
+ UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+ else {
+ IPV6_ADDR_COPY(&ext->neigh_addr6,
+ &adj->global_ipv6_addrs[0]);
+ SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+ }
+ break;
+ default:
+ return 0;
}
- /* and IPv6 */
- if (adj->ipv6_address_count > 0) {
- IPV6_ADDR_COPY(&circuit->ext->neigh_addr6,
- &adj->ipv6_addresses[0]);
- SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6);
+ /* Update LSP */
+ lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
+
+ return 0;
+}
+
+static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
+ bool global)
+{
+ struct isis_circuit *circuit;
+ struct isis_ext_subtlvs *ext;
+
+ /* Sanity Check */
+ if (!adj || !adj->circuit || !adj->circuit->ext)
+ return 0;
+
+ circuit = adj->circuit;
+
+ /* Check that MPLS TE is enabled */
+ if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext)
+ return 0;
+
+ ext = circuit->ext;
+
+ /* Update MPLS TE IP address parameters if possible */
+ if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(ext))
+ return 0;
+
+ /* Determine nexthop IP address */
+ switch (family) {
+ case AF_INET:
+ UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
+ break;
+ case AF_INET6:
+ if (global)
+ UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+ break;
+ default:
+ return 0;
}
+ /* Update LSP */
+ lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
+
return 0;
}
@@ -299,9 +350,908 @@ int isis_mpls_te_update(struct interface *ifp)
return rc;
}
+
+/**
+ * Export Link State information to consumer daemon through ZAPI Link State
+ * Opaque Message.
+ *
+ * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
+ * @param link_state Pointer to Link State Vertex, Edge or Subnet
+ *
+ * @return 0 if success, -1 otherwise
+ */
+static int isis_te_export(uint8_t type, void *link_state)
+{
+ struct ls_message msg = {};
+ int rc = 0;
+
+ switch (type) {
+ case LS_MSG_TYPE_NODE:
+ ls_vertex2msg(&msg, (struct ls_vertex *)link_state);
+ rc = ls_send_msg(zclient, &msg, NULL);
+ break;
+ case LS_MSG_TYPE_ATTRIBUTES:
+ ls_edge2msg(&msg, (struct ls_edge *)link_state);
+ rc = ls_send_msg(zclient, &msg, NULL);
+ break;
+ case LS_MSG_TYPE_PREFIX:
+ ls_subnet2msg(&msg, (struct ls_subnet *)link_state);
+ rc = ls_send_msg(zclient, &msg, NULL);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
+ * Link State Database it is created otherwise updated.
+ *
+ * @param ted Traffic Engineering Link State Database
+ * @param lsp IS-IS Link State PDU
+ *
+ * @return Link State Vertex or NULL in case of error
+ */
+static struct ls_vertex *lsp_to_vertex(struct ls_ted *ted, struct isis_lsp *lsp)
+{
+ struct ls_vertex *vertex = NULL;
+ struct ls_node *old, lnode = {};
+ struct isis_tlvs *tlvs;
+ const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
+
+ /* Sanity check */
+ if (!ted || !lsp)
+ return NULL;
+
+ /* Compute Link State Node ID from IS-IS sysID ... */
+ if (lsp->level == ISIS_LEVEL1)
+ lnode.adv.origin = ISIS_L1;
+ else
+ lnode.adv.origin = ISIS_L2;
+ memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN);
+ lnode.adv.id.iso.level = lsp->level;
+ /* ... and search the corresponding vertex */
+ vertex = ls_find_vertex_by_id(ted, lnode.adv);
+ /* Create a new one if not found */
+ if (!vertex) {
+ old = ls_node_new(lnode.adv, inaddr_any, in6addr_any);
+ old->type = STANDARD;
+ vertex = ls_vertex_add(ted, old);
+ }
+ old = vertex->node;
+ te_debug(" |- %s Vertex (%" PRIu64 ") for node %s",
+ vertex->status == NEW ? "Create" : "Found", vertex->key,
+ print_sys_hostname(old->adv.id.iso.sys_id));
+
+ /* Fulfill Link State Node information */
+ tlvs = lsp->tlvs;
+ if (tlvs) {
+ if (tlvs->te_router_id) {
+ IPV4_ADDR_COPY(&lnode.router_id, tlvs->te_router_id);
+ SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID);
+ }
+ if (tlvs->te_router_id_ipv6) {
+ IPV6_ADDR_COPY(&lnode.router_id6,
+ tlvs->te_router_id_ipv6);
+ SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID6);
+ }
+ if (tlvs->hostname) {
+ memcpy(&lnode.name, tlvs->hostname, MAX_NAME_LENGTH);
+ SET_FLAG(lnode.flags, LS_NODE_NAME);
+ }
+ if (tlvs->router_cap) {
+ struct isis_router_cap *cap = tlvs->router_cap;
+
+ if (cap->srgb.lower_bound != 0
+ && cap->srgb.range_size != 0) {
+ SET_FLAG(lnode.flags, LS_NODE_SR);
+ lnode.srgb.flag = cap->srgb.flags;
+ lnode.srgb.lower_bound = cap->srgb.lower_bound;
+ lnode.srgb.range_size = cap->srgb.range_size;
+ for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+ lnode.algo[i] = cap->algo[i];
+ }
+
+ if (cap->srlb.lower_bound != 0
+ && cap->srlb.range_size != 0) {
+ lnode.srlb.lower_bound = cap->srlb.lower_bound;
+ lnode.srlb.range_size = cap->srlb.range_size;
+ SET_FLAG(lnode.flags, LS_NODE_SRLB);
+ }
+ if (cap->msd != 0) {
+ lnode.msd = cap->msd;
+ SET_FLAG(lnode.flags, LS_NODE_MSD);
+ }
+ }
+ }
+
+ /* Update Link State Node information */
+ if (!ls_node_same(old, &lnode)) {
+ te_debug(" |- Update Link State Node information");
+ memcpy(old, &lnode, sizeof(struct ls_node));
+ if (vertex->status != NEW)
+ vertex->status = UPDATE;
+ }
+
+ /* Set self TED vertex if LSP corresponds to the own router */
+ if (lsp->own_lsp)
+ ted->self = vertex;
+
+ return vertex;
+}
+
+/**
+ * Get Link State Edge from Link State Attributes in TE Database.
+ * Edge structure is dynamically allocated and fulfill with Link State
+ * Attributes if not found.
+ *
+ * @param ted Link State Database
+ * @param attr Link State Attributes
+ *
+ * @return New Link State Edge if success, NULL otherwise
+ */
+static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_attributes *attr)
+{
+ struct ls_edge *edge;
+ struct ls_standard *std;
+ uint64_t key = 0;
+
+ /* Check parameters */
+ if (!ted || !attr)
+ return NULL;
+
+ std = &attr->standard;
+
+ /* Compute keys in function of local address (IPv4/v6) or identifier */
+ if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
+ key = ((uint64_t)ntohl(std->local.s_addr)) & 0xffffffff;
+ else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
+ key = ((uint64_t)ntohl(std->local6.s6_addr32[2]) << 32
+ | (uint64_t)ntohl(std->local6.s6_addr32[3]));
+ else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
+ key = ((uint64_t)std->remote_id << 32)
+ | (((uint64_t)std->local_id) & 0xffffffff);
+ else
+ key = 0;
+
+ /* Stop here if we don't got a valid key */
+ if (key == 0)
+ return NULL;
+
+ /* Get corresponding Edge by key from Link State Data Base */
+ edge = ls_find_edge_by_key(ted, key);
+
+ /* and create new one if not exist */
+ if (!edge) {
+ edge = ls_edge_add(ted, attr);
+ /*
+ * Edge could be Null if no local ID is found in Attributes.
+ * Stop the processing as without any local ID it is not
+ * possible to store Edge in the TED.
+ */
+ if (!edge)
+ return NULL;
+ }
+
+ if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR))
+ te_debug(" |- %s Edge (%" PRIu64
+ ") from Extended Reach. %pI4",
+ edge->status == NEW ? "Create" : "Found", edge->key,
+ &attr->standard.local);
+ else if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR6))
+ te_debug(" |- %s Edge (%" PRIu64
+ ") from Extended Reach. %pI6",
+ edge->status == NEW ? "Create" : "Found", edge->key,
+ &attr->standard.local6);
+ else
+ te_debug(" |- %s Edge (%" PRIu64 ")",
+ edge->status == NEW ? "Create" : "Found", edge->key);
+
+ return edge;
+}
+
+/**
+ * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
+ * allocated and should be free once not use anymore.
+ *
+ * @param adv Link State Node ID
+ * @param tlvs IS-IS Sub TLVs
+ *
+ * @return New Link State attributes if success, NULL otherwise
+ */
+static struct ls_attributes *get_attributes(struct ls_node_id adv,
+ struct isis_ext_subtlvs *tlvs)
+{
+ struct ls_attributes *attr;
+ struct in_addr local = {.s_addr = INADDR_ANY};
+ struct in6_addr local6 = in6addr_any;
+ uint32_t local_id = 0;
+
+ /* Got Local identifier */
+ if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR))
+ local.s_addr = tlvs->local_addr.s_addr;
+
+ if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR6))
+ memcpy(&local6, &tlvs->local_addr6, IPV6_MAX_BYTELEN);
+
+ if (CHECK_FLAG(tlvs->status, EXT_LLRI))
+ local_id = tlvs->local_llri;
+
+ /* Create LS Attributes */
+ attr = ls_attributes_new(adv, local, local6, local_id);
+ if (!attr)
+ return NULL;
+
+ /* Browse sub-TLV and fulfill Link State Attributes */
+ if (CHECK_FLAG(tlvs->status, EXT_ADM_GRP)) {
+ attr->standard.admin_group = tlvs->adm_group;
+ SET_FLAG(attr->flags, LS_ATTR_ADM_GRP);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_LLRI)) {
+ attr->standard.local_id = tlvs->local_llri;
+ attr->standard.remote_id = tlvs->remote_llri;
+ SET_FLAG(attr->flags, LS_ATTR_LOCAL_ID);
+ SET_FLAG(attr->flags, LS_ATTR_NEIGH_ID);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR)) {
+ attr->standard.remote.s_addr = tlvs->neigh_addr.s_addr;
+ SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR6)) {
+ memcpy(&attr->standard.remote6, &tlvs->neigh_addr6,
+ IPV6_MAX_BYTELEN);
+ SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_MAX_BW)) {
+ attr->standard.max_bw = tlvs->max_bw;
+ SET_FLAG(attr->flags, LS_ATTR_MAX_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_MAX_RSV_BW)) {
+ attr->standard.max_rsv_bw = tlvs->max_rsv_bw;
+ SET_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_UNRSV_BW)) {
+ memcpy(&attr->standard.unrsv_bw, tlvs->unrsv_bw,
+ ISIS_SUBTLV_UNRSV_BW_SIZE);
+ SET_FLAG(attr->flags, LS_ATTR_UNRSV_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_TE_METRIC)) {
+ attr->standard.te_metric = tlvs->te_metric;
+ SET_FLAG(attr->flags, LS_ATTR_TE_METRIC);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_RMT_AS)) {
+ attr->standard.remote_as = tlvs->remote_as;
+ SET_FLAG(attr->flags, LS_ATTR_REMOTE_AS);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_RMT_IP)) {
+ attr->standard.remote_addr = tlvs->remote_ip;
+ SET_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_DELAY)) {
+ attr->extended.delay = tlvs->delay;
+ SET_FLAG(attr->flags, LS_ATTR_DELAY);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_MM_DELAY)) {
+ attr->extended.min_delay = tlvs->min_delay;
+ attr->extended.max_delay = tlvs->max_delay;
+ SET_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_DELAY_VAR)) {
+ attr->extended.jitter = tlvs->delay_var;
+ SET_FLAG(attr->flags, LS_ATTR_JITTER);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_PKT_LOSS)) {
+ attr->extended.pkt_loss = tlvs->pkt_loss;
+ SET_FLAG(attr->flags, LS_ATTR_PACKET_LOSS);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_AVA_BW)) {
+ attr->extended.ava_bw = tlvs->ava_bw;
+ SET_FLAG(attr->flags, LS_ATTR_AVA_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_RES_BW)) {
+ attr->extended.rsv_bw = tlvs->res_bw;
+ SET_FLAG(attr->flags, LS_ATTR_RSV_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_USE_BW)) {
+ attr->extended.used_bw = tlvs->use_bw;
+ SET_FLAG(attr->flags, LS_ATTR_USE_BW);
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_ADJ_SID)) {
+ struct isis_adj_sid *adj =
+ (struct isis_adj_sid *)tlvs->adj_sid.head;
+ int i;
+ for (; adj; adj = adj->next) {
+ i = adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0;
+ i += adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0;
+ attr->adj_sid[i].flags = adj->flags;
+ attr->adj_sid[i].weight = adj->weight;
+ attr->adj_sid[i].sid = adj->sid;
+ switch (i) {
+ case ADJ_PRI_IPV4:
+ SET_FLAG(attr->flags, LS_ATTR_ADJ_SID);
+ break;
+ case ADJ_BCK_IPV4:
+ SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID);
+ break;
+ case ADJ_PRI_IPV6:
+ SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6);
+ break;
+ case ADJ_BCK_IPV6:
+ SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6);
+ break;
+ }
+ }
+ }
+ if (CHECK_FLAG(tlvs->status, EXT_LAN_ADJ_SID)) {
+ struct isis_lan_adj_sid *ladj =
+ (struct isis_lan_adj_sid *)tlvs->lan_sid.head;
+ int i;
+ for (; ladj; ladj = ladj->next) {
+ i = ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0;
+ i += ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0;
+ attr->adj_sid[i].flags = ladj->flags;
+ attr->adj_sid[i].weight = ladj->weight;
+ attr->adj_sid[i].sid = ladj->sid;
+ memcpy(&attr->adj_sid[i].neighbor.sysid,
+ &ladj->neighbor_id, ISIS_SYS_ID_LEN);
+ switch (i) {
+ case ADJ_PRI_IPV4:
+ SET_FLAG(attr->flags, LS_ATTR_ADJ_SID);
+ break;
+ case ADJ_BCK_IPV4:
+ SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID);
+ break;
+ case ADJ_PRI_IPV6:
+ SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6);
+ break;
+ case ADJ_BCK_IPV6:
+ SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6);
+ break;
+ }
+ }
+ }
+
+ return attr;
+}
+
+/**
+ * Parse Extended Reachability TLVs and create or update the corresponding
+ * Link State Edge and Attributes. Vertex connections are also updated if
+ * needed based on the remote IP address of the Edge and existing reverse Edge.
+ *
+ * @param id ID of Extended IS
+ * @param metric Metric of the link
+ * @param old_metric Boolean that indicate if it is an old metric (no TE)
+ * @param tlvs SubTlvs that contains TE information
+ * @param arg IS-IS TE argument (TED, Vertex, and export indication)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+static int lsp_to_edge_cb(const uint8_t *id, uint32_t metric, bool old_metric,
+ struct isis_ext_subtlvs *tlvs, void *arg)
+{
+ struct isis_te_args *args = (struct isis_te_args *)arg;
+ struct ls_vertex *vertex;
+ struct ls_edge *edge, *dst;
+ struct ls_attributes *attr;
+
+ te_debug(" |- Process Extended IS for %s", sysid_print(id));
+
+ /* Check parameters */
+ if (old_metric || !args || !tlvs)
+ return LSP_ITER_CONTINUE;
+
+ /* Initialize Link State Attributes */
+ vertex = args->vertex;
+ attr = get_attributes(vertex->node->adv, tlvs);
+ /*
+ * Attributes may be Null if no local ID has been found in the LSP.
+ * Stop processing here as without any local ID it is not possible to
+ * create corresponding Edge in the TED.
+ */
+ if (!attr)
+ return LSP_ITER_CONTINUE;
+
+ attr->metric = metric;
+
+ /* Get corresponding Edge from Link State Data Base */
+ edge = get_edge(args->ted, attr);
+ /*
+ * Edge could be Null if no local ID has been found in Attributes.
+ * Stop processing here as without any local ID it is not possible to
+ * create corresponding Edge in the TED.
+ */
+ if (!edge) {
+ ls_attributes_del(attr);
+ return LSP_ITER_CONTINUE;
+ }
+
+ /* Update Attribute fields if there are different */
+ if (edge->status != NEW) {
+ if (!ls_attributes_same(edge->attributes, attr)) {
+ te_debug(" |- Update Edge Attributes information");
+ ls_attributes_del(edge->attributes);
+ edge->attributes = attr;
+ edge->status = UPDATE;
+ } else {
+ if (edge->attributes != attr)
+ ls_attributes_del(attr);
+ edge->status = SYNC;
+ }
+ }
+
+ /* Try to update remote Link from remote address or reachability ID */
+ te_debug(" |- Link Edge (%" PRIu64 ") to destination vertex (%s)",
+ edge->key, print_sys_hostname(id));
+ dst = ls_find_edge_by_destination(args->ted, edge->attributes);
+ if (dst) {
+ /* Attach remote link if not set */
+ if (edge->source && dst->destination == NULL) {
+ vertex = edge->source;
+ if (vertex->incoming_edges)
+ listnode_add_sort_nodup(vertex->incoming_edges,
+ dst);
+ dst->destination = vertex;
+ }
+ /* and destination vertex to this edge if not set */
+ if (dst->source && edge->destination == NULL) {
+ vertex = dst->source;
+ if (vertex->incoming_edges)
+ listnode_add_sort_nodup(vertex->incoming_edges,
+ edge);
+ edge->destination = vertex;
+ }
+ } else {
+ /* Search dst. Vertex by Extended Reach. ID if not found */
+ if (edge->destination == NULL) {
+ vertex = ls_find_vertex_by_key(args->ted,
+ sysid_to_key(id));
+ if (vertex && vertex->incoming_edges)
+ listnode_add_sort_nodup(vertex->incoming_edges,
+ edge);
+ edge->destination = vertex;
+ }
+ }
+
+ /* Update status and Export Link State Edge if needed */
+ if (edge->status != SYNC) {
+ if (args->export)
+ isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
+ edge->status = SYNC;
+ }
+
+ return LSP_ITER_CONTINUE;
+}
+
+/**
+ * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
+ * update the corresponding Link State Subnet and Prefix.
+ *
+ * @param prefix Prefix associated to this subnet
+ * @param metric Metric of this prefix
+ * @param external Boolean to indicate if the prefix is external
+ * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
+ * @param arg IS-IS TE argument (TED, Vertex, and export indication)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric,
+ bool external, struct isis_subtlvs *subtlvs,
+ void *arg)
+{
+ struct isis_te_args *args = (struct isis_te_args *)arg;
+ struct ls_vertex *vertex;
+ struct ls_subnet *subnet;
+ struct ls_prefix *ls_pref;
+ struct listnode *node;
+ struct ls_edge *edge;
+ struct ls_standard *std = NULL;
+ struct prefix p;
+
+ /* Sanity Check */
+ if (!args || !prefix)
+ return LSP_ITER_CONTINUE;
+
+ te_debug(" |- Process Extended %s Reachability %pFX",
+ prefix->family == AF_INET ? "IP" : "IPv6", prefix);
+
+ vertex = args->vertex;
+
+ /*
+ * Prefix with mask different from /32 or /128 are advertised by at
+ * least 2 nodes. To avoid subnet attached to undetermined vertex, and
+ * gives the possibility to send the information to client e.g. BGP for
+ * Link State advertisement, we adjust the prefix with the corresponding
+ * IP address of the belonging interface when it is available. Other
+ * prefixes are kept unchanged.
+ */
+ if (prefix->family == AF_INET && prefix->prefixlen < IPV4_MAX_BITLEN) {
+ std = NULL;
+ for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
+ if (!CHECK_FLAG(edge->attributes->flags,
+ LS_ATTR_LOCAL_ADDR))
+ continue;
+
+ p.u.prefix4 = edge->attributes->standard.local;
+ p.family = AF_INET;
+ p.prefixlen = prefix->prefixlen;
+ apply_mask_ipv4((struct prefix_ipv4 *)&p);
+ if (IPV4_ADDR_SAME(&p.u.prefix4, &prefix->u.prefix4)) {
+ std = &edge->attributes->standard;
+ break;
+ }
+ }
+ if (std)
+ p.u.prefix4 = std->local;
+
+ } else if (prefix->family == AF_INET6
+ && prefix->prefixlen < IPV6_MAX_BITLEN) {
+ std = NULL;
+ for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
+ if (!CHECK_FLAG(edge->attributes->flags,
+ LS_ATTR_LOCAL_ADDR6))
+ continue;
+
+ p.u.prefix6 = edge->attributes->standard.local6;
+ p.family = AF_INET6;
+ p.prefixlen = prefix->prefixlen;
+ apply_mask_ipv6((struct prefix_ipv6 *)&p);
+ if (IPV6_ADDR_SAME(&p.u.prefix6, &prefix->u.prefix6)) {
+ std = &edge->attributes->standard;
+ break;
+ }
+ }
+ if (std)
+ p.u.prefix6 = std->local6;
+ }
+ if (!std)
+ p = *prefix;
+ else
+ te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
+ prefix, &p);
+
+ /* Search existing Subnet in TED ... */
+ subnet = ls_find_subnet(args->ted, p);
+ /* ... and create a new Subnet if not found */
+ if (!subnet) {
+ ls_pref = ls_prefix_new(vertex->node->adv, p);
+ subnet = ls_subnet_add(args->ted, ls_pref);
+ if (!subnet)
+ return LSP_ITER_CONTINUE;
+ }
+ ls_pref = subnet->ls_pref;
+
+ te_debug(" |- %s Subnet from prefix %pFX",
+ subnet->status == NEW ? "Create" : "Found", &p);
+
+ /* Update Metric */
+ if (!CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)
+ || (ls_pref->metric != metric)) {
+ ls_pref->metric = metric;
+ SET_FLAG(ls_pref->flags, LS_PREF_METRIC);
+ if (subnet->status != NEW)
+ subnet->status = UPDATE;
+ } else {
+ if (subnet->status == ORPHAN)
+ subnet->status = SYNC;
+ }
+
+ /* Update Prefix SID if any */
+ if (subtlvs && subtlvs->prefix_sids.count != 0) {
+ struct isis_prefix_sid *psid;
+ struct ls_sid sr = {};
+
+ psid = (struct isis_prefix_sid *)subtlvs->prefix_sids.head;
+ sr.algo = psid->algorithm;
+ sr.sid_flag = psid->flags;
+ sr.sid = psid->value;
+
+ if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SR)
+ || !memcmp(&ls_pref->sr, &sr, sizeof(struct ls_sid))) {
+ memcpy(&ls_pref->sr, &sr, sizeof(struct ls_sid));
+ SET_FLAG(ls_pref->flags, LS_PREF_SR);
+ if (subnet->status != NEW)
+ subnet->status = UPDATE;
+ } else {
+ if (subnet->status == ORPHAN)
+ subnet->status = SYNC;
+ }
+ } else {
+ if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
+ UNSET_FLAG(ls_pref->flags, LS_PREF_SR);
+ if (subnet->status != NEW)
+ subnet->status = UPDATE;
+ } else {
+ if (subnet->status == ORPHAN)
+ subnet->status = SYNC;
+ }
+ }
+
+ /* Update status and Export Link State Edge if needed */
+ if (subnet->status != SYNC) {
+ if (args->export)
+ isis_te_export(LS_MSG_TYPE_PREFIX, subnet);
+ subnet->status = SYNC;
+ }
+
+ return LSP_ITER_CONTINUE;
+}
+
+/**
+ * Parse ISIS LSP to fulfill the Link State Database
+ *
+ * @param ted Link State Database
+ * @param lsp ISIS Link State PDU
+ */
+static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp)
+{
+ struct ls_ted *ted;
+ struct ls_vertex *vertex;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+ struct listnode *node;
+ struct isis_te_args args;
+
+ /* Sanity Check */
+ if (!IS_MPLS_TE(mta) || !mta->ted || !lsp)
+ return;
+
+ ted = mta->ted;
+
+ te_debug("ISIS-TE(%s): Parse LSP %s", lsp->area->area_tag,
+ sysid_print(lsp->hdr.lsp_id));
+
+ /* First parse LSP to obtain the corresponding Vertex */
+ vertex = lsp_to_vertex(ted, lsp);
+ if (!vertex) {
+ zlog_warn("Unable to build Vertex from LSP %s. Abort!",
+ sysid_print(lsp->hdr.lsp_id));
+ return;
+ }
+
+ /* Check if Vertex has been modified */
+ if (vertex->status != SYNC) {
+ /* Vertex is out of sync: export it if requested */
+ if (IS_EXPORT_TE(mta))
+ isis_te_export(LS_MSG_TYPE_NODE, vertex);
+ vertex->status = SYNC;
+ }
+
+ /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
+ for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge))
+ edge->status = ORPHAN;
+
+ for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet))
+ subnet->status = ORPHAN;
+
+ /* Process all Extended Reachability in LSP (all fragments) */
+ args.ted = ted;
+ args.vertex = vertex;
+ args.export = mta->export;
+ isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV4_UNICAST, lsp_to_edge_cb,
+ &args);
+
+ isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV6_UNICAST, lsp_to_edge_cb,
+ &args);
+
+ /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
+ isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST,
+ lsp_to_subnet_cb, &args);
+ isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST,
+ lsp_to_subnet_cb, &args);
+ isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST,
+ lsp_to_subnet_cb, &args);
+
+ /* Clean remaining Orphan Edges or Subnets */
+ if (IS_EXPORT_TE(mta))
+ ls_vertex_clean(ted, vertex, zclient);
+ else
+ ls_vertex_clean(ted, vertex, NULL);
+}
+
+/**
+ * Delete Link State Database Vertex, Edge & Prefix that correspond to this
+ * ISIS Link State PDU
+ *
+ * @param ted Link State Database
+ * @param lsp ISIS Link State PDU
+ */
+static void isis_te_delete_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp)
+{
+ struct ls_ted *ted;
+ struct ls_vertex *vertex = NULL;
+ struct ls_node lnode = {};
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+ struct listnode *nnode, *node;
+
+ /* Sanity Check */
+ if (!IS_MPLS_TE(mta) || !mta->ted || !lsp)
+ return;
+
+ te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %s",
+ lsp->area->area_tag, sysid_print(lsp->hdr.lsp_id));
+
+ /* Compute Link State Node ID from IS-IS sysID ... */
+ if (lsp->level == ISIS_LEVEL1)
+ lnode.adv.origin = ISIS_L1;
+ else
+ lnode.adv.origin = ISIS_L2;
+ memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN);
+ lnode.adv.id.iso.level = lsp->level;
+ ted = mta->ted;
+ /* ... and search the corresponding vertex */
+ vertex = ls_find_vertex_by_id(ted, lnode.adv);
+ if (!vertex)
+ return;
+
+ te_debug(" |- Delete Vertex %s", vertex->node->name);
+
+ /*
+ * We can't use the ls_vertex_del_all() function if export TE is set,
+ * as we must first advertise the client daemons of each removal.
+ */
+ /* Remove outgoing Edges */
+ for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) {
+ if (IS_EXPORT_TE(mta)) {
+ edge->status = DELETE;
+ isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
+ }
+ ls_edge_del_all(ted, edge);
+ }
+
+ /* Disconnect incoming Edges */
+ for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) {
+ ls_disconnect(vertex, edge, false);
+ if (edge->source == NULL) {
+ if (IS_EXPORT_TE(mta)) {
+ edge->status = DELETE;
+ isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
+ }
+ ls_edge_del_all(ted, edge);
+ }
+ }
+
+ /* Remove subnets */
+ for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) {
+ if (IS_EXPORT_TE(mta)) {
+ subnet->status = DELETE;
+ isis_te_export(LS_MSG_TYPE_PREFIX, subnet);
+ }
+ ls_subnet_del_all(ted, subnet);
+ }
+
+ /* Then remove Link State Node */
+ if (IS_EXPORT_TE(mta)) {
+ vertex->status = DELETE;
+ isis_te_export(LS_MSG_TYPE_NODE, vertex);
+ }
+ ls_node_del(vertex->node);
+
+ /* Finally, remove Vertex */
+ ls_vertex_del(ted, vertex);
+}
+
+/**
+ * Process ISIS LSP according to the event to add, update or remove
+ * corresponding vertex, edge and prefix in the Link State database.
+ * Since LSP could be fragmented, the function starts by searching the root LSP
+ * to retrieve the complete LSP, including eventual fragment before processing
+ * all of them.
+ *
+ * @param lsp ISIS Link State PDU
+ * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
+ *
+ */
+void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event)
+{
+ struct isis_area *area;
+ struct isis_lsp *lsp0;
+
+ /* Sanity check */
+ if (!lsp || !lsp->area)
+ return;
+
+ area = lsp->area;
+ if (!IS_MPLS_TE(area->mta))
+ return;
+
+ /* Adjust LSP0 in case of fragment */
+ if (LSP_FRAGMENT(lsp->hdr.lsp_id))
+ lsp0 = lsp->lspu.zero_lsp;
+ else
+ lsp0 = lsp;
+
+ /* Then process event */
+ switch (event) {
+ case LSP_ADD:
+ case LSP_UPD:
+ case LSP_INC:
+ isis_te_parse_lsp(area->mta, lsp0);
+ break;
+ case LSP_DEL:
+ isis_te_delete_lsp(area->mta, lsp0);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Send the whole Link State Traffic Engineering Database to the consumer that
+ * request it through a ZAPI Link State Synchronous Opaque Message.
+ *
+ * @param info ZAPI Opaque message
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int isis_te_sync_ted(struct zapi_opaque_reg_info dst)
+{
+ struct listnode *node, *inode;
+ struct isis *isis;
+ struct isis_area *area;
+ struct mpls_te_area *mta;
+ int rc = -1;
+
+ te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__,
+ dst.proto);
+ /* For each area, send TED if TE distribution is enabled */
+ for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ mta = area->mta;
+ if (IS_MPLS_TE(mta) && IS_EXPORT_TE(mta)) {
+ te_debug(" |- Export TED from area %s",
+ area->area_tag);
+ rc = ls_sync_ted(mta->ted, zclient, &dst);
+ if (rc != 0)
+ return rc;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * Initialize the Link State database from the LSP already stored for this area
+ *
+ * @param area ISIS area
+ */
+void isis_te_init_ted(struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+
+ /* Iterate over all lsp. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ frr_each (lspdb, &area->lspdb[level - 1], lsp)
+ isis_te_parse_lsp(area->mta, lsp);
+}
+
/* Followings are vty command functions */
#ifndef FABRICD
+static void show_router_id(struct vty *vty, struct isis_area *area)
+{
+ bool no_match = true;
+
+ vty_out(vty, "Area %s:\n", area->area_tag);
+ if (area->mta->router_id.s_addr != 0) {
+ vty_out(vty, " MPLS-TE IPv4 Router-Address: %pI4\n",
+ &area->mta->router_id);
+ no_match = false;
+ }
+ if (!IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
+ vty_out(vty, " MPLS-TE IPv6 Router-Address: %pI6\n",
+ &area->mta->router_id_ipv6);
+ no_match = false;
+ }
+ if (no_match)
+ vty_out(vty, " N/A\n");
+}
+
DEFUN(show_isis_mpls_te_router,
show_isis_mpls_te_router_cmd,
"show " PROTO_NAME " [vrf <NAME|all>] mpls-te router",
@@ -331,15 +1281,7 @@ DEFUN(show_isis_mpls_te_router,
if (!IS_MPLS_TE(area->mta))
continue;
- vty_out(vty, "Area %s:\n",
- area->area_tag);
- if (ntohs(area->mta->router_id.s_addr)
- != 0)
- vty_out(vty,
- " MPLS-TE Router-Address: %pI4\n",
- &area->mta->router_id);
- else
- vty_out(vty, " N/A\n");
+ show_router_id(vty, area);
}
}
return 0;
@@ -352,13 +1294,7 @@ DEFUN(show_isis_mpls_te_router,
if (!IS_MPLS_TE(area->mta))
continue;
- vty_out(vty, "Area %s:\n", area->area_tag);
- if (ntohs(area->mta->router_id.s_addr) != 0)
- vty_out(vty,
- " MPLS-TE Router-Address: %pI4\n",
- &area->mta->router_id);
- else
- vty_out(vty, " N/A\n");
+ show_router_id(vty, area);
}
}
}
@@ -528,7 +1464,308 @@ DEFUN (show_isis_mpls_te_interface,
return CMD_SUCCESS;
}
-#endif
+
+/**
+ * Search Vertex in TED that corresponds to the given string that represent
+ * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
+ *
+ * @param ted Link State Database
+ * @param id ISO System ID
+ * @param isis Main reference to the isis daemon
+ *
+ * @return Vertex if found, NULL otherwise
+ */
+static struct ls_vertex *vertex_for_arg(struct ls_ted *ted, const char *id,
+ struct isis *isis)
+{
+ char sysid[255] = {0};
+ uint8_t number[3];
+ const char *pos;
+ uint8_t lspid[ISIS_SYS_ID_LEN + 2] = {0};
+ struct isis_dynhn *dynhn;
+ uint64_t key = 0;
+
+ if (!id)
+ return NULL;
+
+ /*
+ * extract fragment and pseudo id from the string argv
+ * in the forms:
+ * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
+ * (b) <systemid/hostname>.<pseudo-id> or
+ * (c) <systemid/hostname> or
+ * Where systemid is in the form:
+ * xxxx.xxxx.xxxx
+ */
+ strlcpy(sysid, id, sizeof(sysid));
+ if (strlen(id) > 3) {
+ pos = id + strlen(id) - 3;
+ if (strncmp(pos, "-", 1) == 0) {
+ memcpy(number, ++pos, 2);
+ lspid[ISIS_SYS_ID_LEN + 1] =
+ (uint8_t)strtol((char *)number, NULL, 16);
+ pos -= 4;
+ if (strncmp(pos, ".", 1) != 0)
+ return NULL;
+ }
+ if (strncmp(pos, ".", 1) == 0) {
+ memcpy(number, ++pos, 2);
+ lspid[ISIS_SYS_ID_LEN] =
+ (uint8_t)strtol((char *)number, NULL, 16);
+ sysid[pos - id - 1] = '\0';
+ }
+ }
+
+ /*
+ * Try to find the lsp-id if the argv
+ * string is in
+ * the form
+ * hostname.<pseudo-id>-<fragment>
+ */
+ if (sysid2buff(lspid, sysid)) {
+ key = sysid_to_key(lspid);
+ } else if ((dynhn = dynhn_find_by_name(isis, sysid))) {
+ memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN);
+ key = sysid_to_key(lspid);
+ } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) {
+ memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
+ key = sysid_to_key(lspid);
+ }
+
+ if (key == 0)
+ return NULL;
+
+ return ls_find_vertex_by_key(ted, key);
+}
+
+/**
+ * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
+ *
+ * @param vty VTY output console
+ * @param argv Command line argument
+ * @param argc Number of command line argument
+ * @param ted Traffic Engineering Database
+ * @param isis isis Main reference to the isis daemon
+ *
+ * @return Command Success if OK, Command Warning otherwise
+ */
+static int show_ted(struct vty *vty, struct cmd_token *argv[], int argc,
+ struct isis_area *area, struct isis *isis)
+{
+ int idx;
+ char *id;
+ struct in_addr ip_addr;
+ struct in6_addr ip6_addr;
+ struct prefix pref;
+ struct ls_ted *ted;
+ struct ls_vertex *vertex;
+ struct ls_edge *edge;
+ struct ls_subnet *subnet;
+ uint64_t key;
+ bool detail = false;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+
+ if (!IS_MPLS_TE(area->mta) || !area->mta->ted) {
+ vty_out(vty, "MPLS-TE is disabled for Area %s\n",
+ area->area_tag ? area->area_tag : "null");
+ return CMD_SUCCESS;
+ }
+
+ ted = area->mta->ted;
+
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
+
+ if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "detail"))
+ detail = true;
+
+ idx = 4;
+ if (argv_find(argv, argc, "vertex", &idx)) {
+ /* Show Vertex */
+ id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg
+ : NULL;
+ if (!id)
+ vertex = NULL;
+ else if (!strncmp(id, "self", 4))
+ vertex = ted->self;
+ else {
+ vertex = vertex_for_arg(ted, id, isis);
+ if (!vertex) {
+ vty_out(vty, "No vertex found for ID %s\n", id);
+ return CMD_WARNING;
+ }
+ }
+
+ if (vertex)
+ ls_show_vertex(vertex, vty, json, detail);
+ else
+ ls_show_vertices(ted, vty, json, detail);
+
+ } else if (argv_find(argv, argc, "edge", &idx)) {
+ /* Show Edge */
+ if (argv_find(argv, argc, "A.B.C.D", &idx)) {
+ if (!inet_pton(AF_INET, argv[idx]->arg, &ip_addr)) {
+ vty_out(vty,
+ "Specified Edge ID %s is invalid\n",
+ argv[idx]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ /* Get the Edge from the Link State Database */
+ key = ((uint64_t)ntohl(ip_addr.s_addr)) & 0xffffffff;
+ edge = ls_find_edge_by_key(ted, key);
+ if (!edge) {
+ vty_out(vty, "No edge found for ID %pI4\n",
+ &ip_addr);
+ return CMD_WARNING;
+ }
+ } else if (argv_find(argv, argc, "X:X::X:X", &idx)) {
+ if (!inet_pton(AF_INET6, argv[idx]->arg, &ip6_addr)) {
+ vty_out(vty,
+ "Specified Edge ID %s is invalid\n",
+ argv[idx]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ /* Get the Edge from the Link State Database */
+ key = (uint64_t)ntohl(ip6_addr.s6_addr32[3])
+ | ((uint64_t)ntohl(ip6_addr.s6_addr32[2]) << 32);
+ edge = ls_find_edge_by_key(ted, key);
+ if (!edge) {
+ vty_out(vty, "No edge found for ID %pI6\n",
+ &ip6_addr);
+ return CMD_WARNING;
+ }
+ } else
+ edge = NULL;
+
+ if (edge)
+ ls_show_edge(edge, vty, json, detail);
+ else
+ ls_show_edges(ted, vty, json, detail);
+
+ } else if (argv_find(argv, argc, "subnet", &idx)) {
+ /* Show Subnet */
+ if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
+ if (!str2prefix(argv[idx]->arg, &pref)) {
+ vty_out(vty, "Invalid prefix format %s\n",
+ argv[idx]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ /* Get the Subnet from the Link State Database */
+ subnet = ls_find_subnet(ted, pref);
+ if (!subnet) {
+ vty_out(vty, "No subnet found for ID %pFX\n",
+ &pref);
+ return CMD_WARNING;
+ }
+ } else if (argv_find(argv, argc, "X:X::X:X/M", &idx)) {
+ if (!str2prefix(argv[idx]->arg, &pref)) {
+ vty_out(vty, "Invalid prefix format %s\n",
+ argv[idx]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ /* Get the Subnet from the Link State Database */
+ subnet = ls_find_subnet(ted, pref);
+ if (!subnet) {
+ vty_out(vty, "No subnet found for ID %pFX\n",
+ &pref);
+ return CMD_WARNING;
+ }
+ } else
+ subnet = NULL;
+
+ if (subnet)
+ ls_show_subnet(subnet, vty, json, detail);
+ else
+ ls_show_subnets(ted, vty, json, detail);
+
+ } else {
+ /* Show the complete TED */
+ ls_show_ted(ted, vty, json, detail);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/**
+ * Show ISIS Traffic Engineering Database
+ *
+ * @param vty VTY output console
+ * @param argv Command line argument
+ * @param argc Number of command line argument
+ * @param isis isis Main reference to the isis daemon
+
+ * @return Command Success if OK, Command Warning otherwise
+ */
+static int show_isis_ted(struct vty *vty, struct cmd_token *argv[], int argc,
+ struct isis *isis)
+{
+ struct listnode *node;
+ struct isis_area *area;
+ int rc;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ rc = show_ted(vty, argv, argc, area, isis);
+ if (rc != CMD_SUCCESS)
+ return rc;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_isis_mpls_te_db,
+ show_isis_mpls_te_db_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] mpls-te database [<vertex [WORD]|edge [A.B.C.D|X:X::X:X]|subnet [A.B.C.D/M|X:X::X:X/M]>] [detail|json]",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ MPLS_TE_STR
+ "MPLS-TE database\n"
+ "MPLS-TE Vertex\n"
+ "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
+ "MPLS-TE Edge\n"
+ "MPLS-TE Edge ID (as an IPv4 address)\n"
+ "MPLS-TE Edge ID (as an IPv6 address)\n"
+ "MPLS-TE Subnet\n"
+ "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
+ "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
+ "Detailed information\n"
+ JSON_STR)
+{
+ int idx_vrf = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ struct listnode *node;
+ struct isis *isis;
+ int rc = CMD_WARNING;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+ rc = show_isis_ted(vty, argv, argc, isis);
+ if (rc != CMD_SUCCESS)
+ return rc;
+ }
+ return CMD_SUCCESS;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis)
+ rc = show_isis_ted(vty, argv, argc, isis);
+ }
+
+ return rc;
+}
+
+#endif /* #ifndef FRABRICD */
/* Initialize MPLS_TE */
void isis_mpls_te_init(void)
@@ -536,13 +1773,14 @@ void isis_mpls_te_init(void)
/* Register Circuit and Adjacency hook */
hook_register(isis_if_new_hook, isis_mpls_te_update);
- hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook);
-
+ hook_register(isis_adj_ip_enabled_hook, isis_mpls_te_adj_ip_enabled);
+ hook_register(isis_adj_ip_disabled_hook, isis_mpls_te_adj_ip_disabled);
#ifndef FABRICD
/* Register new VTY commands */
install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
install_element(VIEW_NODE, &show_isis_mpls_te_interface_cmd);
+ install_element(VIEW_NODE, &show_isis_mpls_te_db_cmd);
#endif
return;
diff --git a/isisd/isis_te.h b/isisd/isis_te.h
index 2a6911d50..56954073d 100644
--- a/isisd/isis_te.h
+++ b/isisd/isis_te.h
@@ -88,8 +88,10 @@ typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t;
&& e->status != EXT_ADJ_SID \
&& e->status != EXT_LAN_ADJ_SID)
#define IS_MPLS_TE(a) (a && a->status == enable)
+#define IS_EXPORT_TE(a) (a->export)
/* Per area MPLS-TE parameters */
+struct ls_ted;
struct mpls_te_area {
/* Status of MPLS-TE: enable or disable */
status_t status;
@@ -101,13 +103,30 @@ struct mpls_te_area {
interas_mode_t inter_as;
struct in_addr interas_areaid;
- /* MPLS_TE router ID */
+ /* MPLS_TE IPv4 & IPv6 Router IDs */
struct in_addr router_id;
+ struct in6_addr router_id_ipv6;
+
+ /* Link State Database */
+ struct ls_ted *ted;
+ bool export;
+};
+
+/* Structure to provide parameters to lsp iterate callback function */
+struct isis_te_args {
+ struct ls_ted *ted;
+ struct ls_vertex *vertex;
+ bool export;
};
+enum lsp_event { LSP_UNKNOWN, LSP_ADD, LSP_UPD, LSP_DEL, LSP_INC, LSP_TICK };
+
/* Prototypes. */
void isis_mpls_te_init(void);
void isis_link_params_update(struct isis_circuit *, struct interface *);
int isis_mpls_te_update(struct interface *);
+void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event);
+int isis_te_sync_ted(struct zapi_opaque_reg_info dst);
+void isis_te_init_ted(struct isis_area *area);
#endif /* _ZEBRA_ISIS_MPLS_TE_H */
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index a66d3b00f..9a442e037 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -99,6 +99,7 @@ static const struct pack_order_entry pack_order[] = {
PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
+ PACK_ENTRY(GLOBAL_IPV6_ADDRESS, ISIS_ITEMS, global_ipv6_address),
PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
@@ -128,27 +129,41 @@ struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
}
/*
- * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
- * A negative value could be used to skip copy of Adjacency SID.
+ * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6
+ * Multi-Topology. Special 4096 value i.e. first R flag set is used to indicate
+ * that MT is disabled i.e. IS-IS is working with a Single Topology.
*/
static struct isis_ext_subtlvs *
-copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
+copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid)
{
struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
struct isis_adj_sid *adj;
struct isis_lan_adj_sid *lan;
+ /* Copy the Extended IS main part */
memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
+
+ /* Disable IPv4 / IPv6 advertisement in function of MTID */
+ if (mtid == ISIS_MT_IPV4_UNICAST) {
+ UNSET_SUBTLV(rv, EXT_LOCAL_ADDR6);
+ UNSET_SUBTLV(rv, EXT_NEIGH_ADDR6);
+ }
+ if (mtid == ISIS_MT_IPV6_UNICAST) {
+ UNSET_SUBTLV(rv, EXT_LOCAL_ADDR);
+ UNSET_SUBTLV(rv, EXT_NEIGH_ADDR);
+ }
+
+ /* Prepare (LAN)-Adjacency Segment Routing ID*/
init_item_list(&rv->adj_sid);
init_item_list(&rv->lan_sid);
UNSET_SUBTLV(rv, EXT_ADJ_SID);
UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
- /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
+ /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */
for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
adj = adj->next) {
- if ((mtid != -1)
+ if ((mtid != ISIS_MT_DISABLE)
&& (((mtid == ISIS_MT_IPV4_UNICAST)
&& (adj->family != AF_INET))
|| ((mtid == ISIS_MT_IPV6_UNICAST)
@@ -166,9 +181,10 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
SET_SUBTLV(rv, EXT_ADJ_SID);
}
+ /* Same for LAN Adj SID */
for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
lan = lan->next) {
- if ((mtid != -1)
+ if ((mtid != ISIS_MT_DISABLE)
&& (((mtid == ISIS_MT_IPV4_UNICAST)
&& (lan->family != AF_INET))
|| ((mtid == ISIS_MT_IPV6_UNICAST)
@@ -196,8 +212,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
uint16_t mtid)
{
- char ibuf[PREFIX2STR_BUFFER];
-
/* Standard metrics */
if (IS_SUBTLV(exts, EXT_ADM_GRP))
sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
@@ -212,16 +226,17 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n",
&exts->local_addr);
if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
- sbuf_push(buf, indent, "Remote Interface IP Address(es): %pI4\n",
+ sbuf_push(buf, indent,
+ "Remote Interface IP Address(es): %pI4\n",
&exts->neigh_addr);
if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
- sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n",
- inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
- PREFIX2STR_BUFFER));
+ sbuf_push(buf, indent,
+ "Local Interface IPv6 Address(es): %pI6\n",
+ &exts->local_addr6);
if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
- sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n",
- inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
- PREFIX2STR_BUFFER));
+ sbuf_push(buf, indent,
+ "Remote Interface IPv6 Address(es): %pI6\n",
+ &exts->neigh_addr6);
if (IS_SUBTLV(exts, EXT_MAX_BW))
sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
exts->max_bw);
@@ -289,11 +304,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
adj = adj->next) {
- if (((mtid == ISIS_MT_IPV4_UNICAST)
- && (adj->family != AF_INET))
- || ((mtid == ISIS_MT_IPV6_UNICAST)
- && (adj->family != AF_INET6)))
- continue;
sbuf_push(
buf, indent,
"Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
@@ -319,10 +329,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
lan; lan = lan->next) {
- if (((mtid == ISIS_MT_IPV4_UNICAST)
- && (lan->family != AF_INET))
- || ((mtid == ISIS_MT_IPV6_UNICAST)
- && (lan->family != AF_INET6)))
continue;
sbuf_push(buf, indent,
"Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
@@ -1839,12 +1845,12 @@ static int pack_item_ipv6_address(struct isis_item *i, struct stream *s,
{
struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
- if (STREAM_WRITEABLE(s) < 16) {
- *min_len = 16;
+ if (STREAM_WRITEABLE(s) < IPV6_MAX_BYTELEN) {
+ *min_len = IPV6_MAX_BYTELEN;
return 1;
}
- stream_put(s, &a->addr, 16);
+ stream_put(s, &a->addr, IPV6_MAX_BYTELEN);
return 0;
}
@@ -1865,7 +1871,7 @@ static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
}
struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
- stream_get(&rv->addr, s, 16);
+ stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
@@ -1873,6 +1879,70 @@ static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
}
+/* Functions related to TLV 233 Global IPv6 Interface addresses */
+static struct isis_item *copy_item_global_ipv6_address(struct isis_item *i)
+{
+ struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+ struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+ rv->addr = a->addr;
+ return (struct isis_item *)rv;
+}
+
+static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i,
+ struct sbuf *buf, int indent)
+{
+ struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+ char addrbuf[INET6_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
+ sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf);
+}
+
+static void free_item_global_ipv6_address(struct isis_item *i)
+{
+ XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_global_ipv6_address(struct isis_item *i, struct stream *s,
+ size_t *min_len)
+{
+ struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+
+ if (STREAM_WRITEABLE(s) < IPV6_MAX_BYTELEN) {
+ *min_len = IPV6_MAX_BYTELEN;
+ return 1;
+ }
+
+ stream_put(s, &a->addr, IPV6_MAX_BYTELEN);
+
+ return 0;
+}
+
+static int unpack_item_global_ipv6_address(uint16_t mtid, uint8_t len,
+ struct stream *s, struct sbuf *log,
+ void *dest, int indent)
+{
+ struct isis_tlvs *tlvs = dest;
+
+ sbuf_push(log, indent, "Unpack Global IPv6 Interface address...\n");
+ if (len < IPV6_MAX_BYTELEN) {
+ sbuf_push(
+ log, indent,
+ "Not enough data left.(Expected 16 bytes of IPv6 address, got %hhu)\n",
+ len);
+ return 1;
+ }
+
+ struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+ stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
+
+ format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log,
+ indent + 2);
+ append_item(&tlvs->global_ipv6_address, (struct isis_item *)rv);
+ return 0;
+}
+
/* Functions related to TLV 229 MT Router information */
static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
{
@@ -2273,6 +2343,77 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
return 0;
}
+/* Functions related to TLV 140 IPv6 TE Router ID */
+
+static struct in6_addr *copy_tlv_te_router_id_ipv6(const struct in6_addr *id)
+{
+ if (!id)
+ return NULL;
+
+ struct in6_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+ memcpy(rv, id, sizeof(*rv));
+ return rv;
+}
+
+static void format_tlv_te_router_id_ipv6(const struct in6_addr *id,
+ struct sbuf *buf, int indent)
+{
+ if (!id)
+ return;
+
+ char addrbuf[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf));
+ sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf);
+}
+
+static void free_tlv_te_router_id_ipv6(struct in6_addr *id)
+{
+ XFREE(MTYPE_ISIS_TLV, id);
+}
+
+static int pack_tlv_te_router_id_ipv6(const struct in6_addr *id,
+ struct stream *s)
+{
+ if (!id)
+ return 0;
+
+ if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
+ return 1;
+
+ stream_putc(s, ISIS_TLV_TE_ROUTER_ID_IPV6);
+ stream_putc(s, IPV6_MAX_BYTELEN);
+ stream_put(s, id, IPV6_MAX_BYTELEN);
+ return 0;
+}
+
+static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context,
+ uint8_t tlv_type, uint8_t tlv_len,
+ struct stream *s, struct sbuf *log,
+ void *dest, int indent)
+{
+ struct isis_tlvs *tlvs = dest;
+
+ sbuf_push(log, indent, "Unpacking IPv6 TE Router ID TLV...\n");
+ if (tlv_len != IPV6_MAX_BYTELEN) {
+ sbuf_push(log, indent, "WARNING: Length invalid\n");
+ return 1;
+ }
+
+ if (tlvs->te_router_id_ipv6) {
+ sbuf_push(
+ log, indent,
+ "WARNING: IPv6 TE Router ID present multiple times.\n");
+ stream_forward_getp(s, tlv_len);
+ return 0;
+ }
+
+ tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, IPV6_MAX_BYTELEN);
+ stream_get(tlvs->te_router_id_ipv6, s, IPV6_MAX_BYTELEN);
+ format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, indent + 2);
+ return 0;
+}
+
+
/* Functions related to TLV 150 Spine-Leaf-Extension */
static struct isis_spine_leaf *copy_tlv_spine_leaf(
@@ -3640,6 +3781,7 @@ struct isis_tlvs *isis_alloc_tlvs(void)
init_item_list(&result->oldstyle_ip_reach_ext);
init_item_list(&result->ipv4_address);
init_item_list(&result->ipv6_address);
+ init_item_list(&result->global_ipv6_address);
init_item_list(&result->extended_ip_reach);
RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
init_item_list(&result->ipv6_reach);
@@ -3696,8 +3838,14 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
&rv->ipv6_address);
+ copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
+ &tlvs->global_ipv6_address, &rv->global_ipv6_address);
+
rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
+ rv->te_router_id_ipv6 =
+ copy_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
+
copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
&tlvs->extended_ip_reach, &rv->extended_ip_reach);
@@ -3751,6 +3899,7 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
+ format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, indent);
format_tlv_router_cap(tlvs->router_cap, buf, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
@@ -3771,6 +3920,9 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
&tlvs->ipv6_address, buf, indent);
+ format_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
+ &tlvs->global_ipv6_address, buf, indent);
+
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
&tlvs->extended_ip_reach, buf, indent);
@@ -3828,7 +3980,10 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
&tlvs->ipv4_address);
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
&tlvs->ipv6_address);
+ free_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
+ &tlvs->global_ipv6_address);
free_tlv_te_router_id(tlvs->te_router_id);
+ free_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
&tlvs->extended_ip_reach);
free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
@@ -4035,6 +4190,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
copy_tlv_te_router_id(tlvs->te_router_id);
}
+ rv = pack_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, stream);
+ if (rv)
+ return rv;
+ if (fragment_tlvs) {
+ fragment_tlvs->te_router_id_ipv6 =
+ copy_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6);
+ }
+
rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
if (rv)
return rv;
@@ -4255,10 +4418,12 @@ ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
TLV_OPS(te_router_id, "TLV 134 TE Router ID");
ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
+TLV_OPS(te_router_id_ipv6, "TLV 140 IPv6 TE Router ID");
TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
+ITEM_TLV_OPS(global_ipv6_address, "TLV 233 Global IPv6 Interface Address");
ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
TLV_OPS(router_cap, "TLV 242 Router Capability");
@@ -4279,12 +4444,14 @@ static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
[ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
[ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
[ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
+ [ISIS_TLV_TE_ROUTER_ID_IPV6] = &tlv_te_router_id_ipv6_ops,
[ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
[ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
[ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
[ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
[ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
+ [ISIS_TLV_GLOBAL_IPV6_ADDRESS] = &tlv_global_ipv6_address_ops,
[ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
[ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
@@ -4427,6 +4594,26 @@ void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
}
}
+void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs *tlvs,
+ struct list *addresses)
+{
+ struct listnode *node;
+ struct prefix_ipv6 *ip_addr;
+ unsigned int addr_count = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
+ if (addr_count >= 15)
+ break;
+
+ struct isis_ipv6_address *a =
+ XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
+
+ a->addr = ip_addr->prefix;
+ append_item(&tlvs->global_ipv6_address, (struct isis_item *)a);
+ addr_count++;
+ }
+}
+
typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
struct stream *stream,
struct isis_auth *auth, bool is_lsp);
@@ -4606,10 +4793,12 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
}
-DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
- (adj, family));
+DEFINE_HOOK(isis_adj_ip_enabled_hook,
+ (struct isis_adjacency * adj, int family, bool global),
+ (adj, family, global));
DEFINE_HOOK(isis_adj_ip_disabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family));
+ (struct isis_adjacency * adj, int family, bool global),
+ (adj, family, global));
static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
struct isis_adjacency *adj,
@@ -4620,7 +4809,7 @@ static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
if (adj->ipv4_address_count == 0 && tlvs->ipv4_address.count > 0)
ipv4_enabled = true;
else if (adj->ipv4_address_count > 0 && tlvs->ipv4_address.count == 0)
- hook_call(isis_adj_ip_disabled_hook, adj, AF_INET);
+ hook_call(isis_adj_ip_disabled_hook, adj, AF_INET, false);
if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
uint32_t oc = adj->ipv4_address_count;
@@ -4654,7 +4843,7 @@ static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
}
if (ipv4_enabled)
- hook_call(isis_adj_ip_enabled_hook, adj, AF_INET);
+ hook_call(isis_adj_ip_enabled_hook, adj, AF_INET, false);
}
static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
@@ -4663,23 +4852,23 @@ static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
{
bool ipv6_enabled = false;
- if (adj->ipv6_address_count == 0 && tlvs->ipv6_address.count > 0)
+ if (adj->ll_ipv6_count == 0 && tlvs->ipv6_address.count > 0)
ipv6_enabled = true;
- else if (adj->ipv6_address_count > 0 && tlvs->ipv6_address.count == 0)
- hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6);
+ else if (adj->ll_ipv6_count > 0 && tlvs->ipv6_address.count == 0)
+ hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6, false);
- if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
- uint32_t oc = adj->ipv6_address_count;
+ if (adj->ll_ipv6_count != tlvs->ipv6_address.count) {
+ uint32_t oc = adj->ll_ipv6_count;
*changed = true;
- adj->ipv6_address_count = tlvs->ipv6_address.count;
- adj->ipv6_addresses = XREALLOC(
- MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
- adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
-
- for (; oc < adj->ipv6_address_count; oc++) {
- memset(&adj->ipv6_addresses[oc], 0,
- sizeof(adj->ipv6_addresses[oc]));
+ adj->ll_ipv6_count = tlvs->ipv6_address.count;
+ adj->ll_ipv6_addrs = XREALLOC(
+ MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs,
+ adj->ll_ipv6_count * sizeof(*adj->ll_ipv6_addrs));
+
+ for (; oc < adj->ll_ipv6_count; oc++) {
+ memset(&adj->ll_ipv6_addrs[oc], 0,
+ sizeof(adj->ll_ipv6_addrs[oc]));
}
}
@@ -4691,16 +4880,65 @@ static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
else
addr = addr->next;
- if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
+ if (!memcmp(&adj->ll_ipv6_addrs[i], &addr->addr,
sizeof(addr->addr)))
continue;
*changed = true;
- adj->ipv6_addresses[i] = addr->addr;
+ adj->ll_ipv6_addrs[i] = addr->addr;
}
if (ipv6_enabled)
- hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6);
+ hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6, false);
+}
+
+
+static void tlvs_global_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
+ struct isis_adjacency *adj,
+ bool *changed)
+{
+ bool global_ipv6_enabled = false;
+
+ if (adj->global_ipv6_count == 0 && tlvs->global_ipv6_address.count > 0)
+ global_ipv6_enabled = true;
+ else if (adj->global_ipv6_count > 0
+ && tlvs->global_ipv6_address.count == 0)
+ hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6, true);
+
+ if (adj->global_ipv6_count != tlvs->global_ipv6_address.count) {
+ uint32_t oc = adj->global_ipv6_count;
+
+ *changed = true;
+ adj->global_ipv6_count = tlvs->global_ipv6_address.count;
+ adj->global_ipv6_addrs = XREALLOC(
+ MTYPE_ISIS_ADJACENCY_INFO, adj->global_ipv6_addrs,
+ adj->global_ipv6_count
+ * sizeof(*adj->global_ipv6_addrs));
+
+ for (; oc < adj->global_ipv6_count; oc++) {
+ memset(&adj->global_ipv6_addrs[oc], 0,
+ sizeof(adj->global_ipv6_addrs[oc]));
+ }
+ }
+
+ struct isis_ipv6_address *addr = NULL;
+ for (unsigned int i = 0; i < tlvs->global_ipv6_address.count; i++) {
+ if (!addr)
+ addr = (struct isis_ipv6_address *)
+ tlvs->global_ipv6_address.head;
+ else
+ addr = addr->next;
+
+ if (!memcmp(&adj->global_ipv6_addrs[i], &addr->addr,
+ sizeof(addr->addr)))
+ continue;
+
+ *changed = true;
+ adj->global_ipv6_addrs[i] = addr->addr;
+ }
+
+ if (global_ipv6_enabled)
+ hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6, true);
}
void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
@@ -4712,6 +4950,7 @@ void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
tlvs_protocols_supported_to_adj(tlvs, adj, changed);
tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
+ tlvs_global_ipv6_addresses_to_adj(tlvs, adj, changed);
}
bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
@@ -4793,6 +5032,16 @@ void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
memcpy(tlvs->te_router_id, id, sizeof(*id));
}
+void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs *tlvs,
+ const struct in6_addr *id)
+{
+ XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id_ipv6);
+ if (!id)
+ return;
+ tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
+ memcpy(tlvs->te_router_id_ipv6, id, sizeof(*id));
+}
+
void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint8_t metric)
{
@@ -4922,7 +5171,7 @@ void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
struct isis_item_list *l;
- if (mtid == ISIS_MT_IPV4_UNICAST)
+ if ((mtid == ISIS_MT_IPV4_UNICAST) || (mtid == ISIS_MT_DISABLE))
l = &tlvs->extended_reach;
else
l = isis_get_mt_items(&tlvs->mt_reach, mtid);
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 0438d13ae..38470ef85 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -324,9 +324,11 @@ struct isis_tlvs {
struct isis_item_list oldstyle_ip_reach_ext;
struct isis_item_list ipv4_address;
struct isis_item_list ipv6_address;
+ struct isis_item_list global_ipv6_address;
struct isis_item_list mt_router_info;
bool mt_router_info_empty;
struct in_addr *te_router_id;
+ struct in6_addr *te_router_id_ipv6;
struct isis_item_list extended_ip_reach;
struct isis_mt_item_list mt_ip_reach;
char *hostname;
@@ -372,10 +374,12 @@ enum isis_tlv_type {
ISIS_TLV_TE_ROUTER_ID = 134,
ISIS_TLV_EXTENDED_IP_REACH = 135,
ISIS_TLV_DYNAMIC_HOSTNAME = 137,
+ ISIS_TLV_TE_ROUTER_ID_IPV6 = 140,
ISIS_TLV_SPINE_LEAF_EXT = 150,
ISIS_TLV_MT_REACH = 222,
ISIS_TLV_MT_ROUTER_INFO = 229,
ISIS_TLV_IPV6_ADDRESS = 232,
+ ISIS_TLV_GLOBAL_IPV6_ADDRESS = 233,
ISIS_TLV_MT_IP_REACH = 235,
ISIS_TLV_IPV6_REACH = 236,
ISIS_TLV_MT_IPV6_REACH = 237,
@@ -575,6 +579,8 @@ void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
struct list *addresses);
void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
struct list *addresses);
+void isis_tlvs_add_global_ipv6_addresses(struct isis_tlvs *tlvs,
+ struct list *addresses);
int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
struct stream *stream, bool is_lsp);
bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
@@ -594,6 +600,8 @@ void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
const struct isis_router_cap *cap);
void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
const struct in_addr *id);
+void isis_tlvs_set_te_router_id_ipv6(struct isis_tlvs *tlvs,
+ const struct in6_addr *id);
void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint8_t metric);
void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 27e80e250..52a5cdd64 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -38,6 +38,7 @@
#include "vrf.h"
#include "libfrr.h"
#include "bfd.h"
+#include "link_state.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
@@ -747,6 +748,25 @@ static void isis_zebra_connected(struct zclient *zclient)
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
}
+/**
+ * Register / unregister Link State ZAPI Opaque Message
+ *
+ * @param up True to register, false to unregister
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int isis_zebra_ls_register(bool up)
+{
+ int rc;
+
+ if (up)
+ rc = ls_register(zclient, true);
+ else
+ rc = ls_unregister(zclient, true);
+
+ return rc;
+}
+
/*
* opaque messages between processes
*/
@@ -754,6 +774,7 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
{
struct stream *s;
struct zapi_opaque_msg info;
+ struct zapi_opaque_reg_info dst;
struct ldp_igp_sync_if_state state;
struct ldp_igp_sync_announce announce;
struct zapi_rlfa_response rlfa;
@@ -764,6 +785,13 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
return -1;
switch (info.type) {
+ case LINK_STATE_SYNC:
+ STREAM_GETC(s, dst.proto);
+ STREAM_GETW(s, dst.instance);
+ STREAM_GETL(s, dst.session_id);
+ dst.type = LINK_STATE_SYNC;
+ ret = isis_te_sync_ted(dst);
+ break;
case LDP_IGP_SYNC_IF_STATE_UPDATE:
STREAM_GET(&state, s, sizeof(state));
ret = isis_ldp_sync_state_update(state);
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 348d7b3ea..84dc58ec6 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -67,5 +67,6 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
int isis_zebra_release_label_range(uint32_t start, uint32_t end);
void isis_zebra_vrf_register(struct isis *isis);
void isis_zebra_vrf_deregister(struct isis *isis);
+int isis_zebra_ls_register(bool up);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 21c97aced..3fa2b7cc2 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -81,6 +81,7 @@ unsigned long debug_tx_queue;
unsigned long debug_sr;
unsigned long debug_ldp_sync;
unsigned long debug_lfa;
+unsigned long debug_te;
DEFINE_MGROUP(ISISD, "isisd");
@@ -1374,6 +1375,10 @@ void print_debug(struct vty *vty, int flags, int onoff)
if (flags & DEBUG_SR)
vty_out(vty, "IS-IS Segment Routing events debugging is %s\n",
onoffs);
+ if (flags & DEBUG_TE)
+ vty_out(vty,
+ "IS-IS Traffic Engineering events debugging is %s\n",
+ onoffs);
if (flags & DEBUG_LFA)
vty_out(vty, "IS-IS LFA events debugging is %s\n", onoffs);
if (flags & DEBUG_UPDATE_PACKETS)
@@ -1416,6 +1421,8 @@ DEFUN_NOSH (show_debugging,
print_debug(vty, DEBUG_SPF_EVENTS, 1);
if (IS_DEBUG_SR)
print_debug(vty, DEBUG_SR, 1);
+ if (IS_DEBUG_TE)
+ print_debug(vty, DEBUG_TE, 1);
if (IS_DEBUG_UPDATE_PACKETS)
print_debug(vty, DEBUG_UPDATE_PACKETS, 1);
if (IS_DEBUG_RTE_EVENTS)
@@ -1473,6 +1480,10 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug " PROTO_NAME " sr-events\n");
write++;
}
+ if (IS_DEBUG_TE) {
+ vty_out(vty, "debug " PROTO_NAME " te-events\n");
+ write++;
+ }
if (IS_DEBUG_LFA) {
vty_out(vty, "debug " PROTO_NAME " lfa\n");
write++;
@@ -1707,6 +1718,33 @@ DEFUN (no_debug_isis_srevents,
return CMD_SUCCESS;
}
+DEFUN (debug_isis_teevents,
+ debug_isis_teevents_cmd,
+ "debug " PROTO_NAME " te-events",
+ DEBUG_STR
+ PROTO_HELP
+ "IS-IS Traffic Engineering Events\n")
+{
+ debug_te |= DEBUG_TE;
+ print_debug(vty, DEBUG_TE, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_teevents,
+ no_debug_isis_teevents_cmd,
+ "no debug " PROTO_NAME " te-events",
+ NO_STR
+ UNDEBUG_STR
+ PROTO_HELP
+ "IS-IS Traffic Engineering Events\n")
+{
+ debug_te &= ~DEBUG_TE;
+ print_debug(vty, DEBUG_TE, 0);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (debug_isis_lfa,
debug_isis_lfa_cmd,
"debug " PROTO_NAME " lfa",
@@ -3095,6 +3133,8 @@ void isis_init(void)
install_element(ENABLE_NODE, &no_debug_isis_spfevents_cmd);
install_element(ENABLE_NODE, &debug_isis_srevents_cmd);
install_element(ENABLE_NODE, &no_debug_isis_srevents_cmd);
+ install_element(ENABLE_NODE, &debug_isis_teevents_cmd);
+ install_element(ENABLE_NODE, &no_debug_isis_teevents_cmd);
install_element(ENABLE_NODE, &debug_isis_lfa_cmd);
install_element(ENABLE_NODE, &no_debug_isis_lfa_cmd);
install_element(ENABLE_NODE, &debug_isis_rtevents_cmd);
@@ -3126,6 +3166,8 @@ void isis_init(void)
install_element(CONFIG_NODE, &no_debug_isis_spfevents_cmd);
install_element(CONFIG_NODE, &debug_isis_srevents_cmd);
install_element(CONFIG_NODE, &no_debug_isis_srevents_cmd);
+ install_element(CONFIG_NODE, &debug_isis_teevents_cmd);
+ install_element(CONFIG_NODE, &no_debug_isis_teevents_cmd);
install_element(CONFIG_NODE, &debug_isis_lfa_cmd);
install_element(CONFIG_NODE, &no_debug_isis_lfa_cmd);
install_element(CONFIG_NODE, &debug_isis_rtevents_cmd);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 3febda1d8..7f8474a5f 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -331,6 +331,7 @@ extern unsigned long debug_tx_queue;
extern unsigned long debug_sr;
extern unsigned long debug_ldp_sync;
extern unsigned long debug_lfa;
+extern unsigned long debug_te;
#define DEBUG_ADJ_PACKETS (1<<0)
#define DEBUG_SNP_PACKETS (1<<1)
@@ -347,6 +348,7 @@ extern unsigned long debug_lfa;
#define DEBUG_SR (1<<12)
#define DEBUG_LDP_SYNC (1<<13)
#define DEBUG_LFA (1<<14)
+#define DEBUG_TE (1<<15)
/* Debug related macro. */
#define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@@ -364,6 +366,7 @@ extern unsigned long debug_lfa;
#define IS_DEBUG_SR (debug_sr & DEBUG_SR)
#define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
#define IS_DEBUG_LFA (debug_lfa & DEBUG_LFA)
+#define IS_DEBUG_TE (debug_te & DEBUG_TE)
#define lsp_debug(...) \
do { \
@@ -383,6 +386,10 @@ extern unsigned long debug_lfa;
zlog_debug(__VA_ARGS__); \
} while (0)
-#define DEBUG_TE DEBUG_LSP_GEN
+#define te_debug(...) \
+ do { \
+ if (IS_DEBUG_TE) \
+ zlog_debug(__VA_ARGS__); \
+ } while (0)
#endif /* ISISD_H */