diff options
author | Russ White <russ@riw.us> | 2022-01-18 16:12:08 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-18 16:12:08 +0100 |
commit | 18ed776ca29533f6c49479b1a0dd95d36bb6b5ec (patch) | |
tree | 2b03c65d7b92d5988f660f4f477191e14e6a3cc8 /isisd | |
parent | Merge pull request #9644 from opensourcerouting/ospf-opaque-attrs (diff) | |
parent | topotests: Add new IS-IS Traffic Engineering tests (diff) | |
download | frr-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.c | 23 | ||||
-rw-r--r-- | isisd/isis_adjacency.h | 12 | ||||
-rw-r--r-- | isisd/isis_bfd.c | 11 | ||||
-rw-r--r-- | isisd/isis_circuit.c | 10 | ||||
-rw-r--r-- | isisd/isis_cli.c | 71 | ||||
-rw-r--r-- | isisd/isis_lfa.c | 5 | ||||
-rw-r--r-- | isisd/isis_lsp.c | 67 | ||||
-rw-r--r-- | isisd/isis_mt.c | 11 | ||||
-rw-r--r-- | isisd/isis_mt.h | 2 | ||||
-rw-r--r-- | isisd/isis_nb.c | 15 | ||||
-rw-r--r-- | isisd/isis_nb.h | 10 | ||||
-rw-r--r-- | isisd/isis_nb_config.c | 94 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 5 | ||||
-rw-r--r-- | isisd/isis_route.c | 4 | ||||
-rw-r--r-- | isisd/isis_snmp.c | 7 | ||||
-rw-r--r-- | isisd/isis_sr.c | 18 | ||||
-rw-r--r-- | isisd/isis_te.c | 1370 | ||||
-rw-r--r-- | isisd/isis_te.h | 21 | ||||
-rw-r--r-- | isisd/isis_tlvs.c | 349 | ||||
-rw-r--r-- | isisd/isis_tlvs.h | 8 | ||||
-rw-r--r-- | isisd/isis_zebra.c | 28 | ||||
-rw-r--r-- | isisd/isis_zebra.h | 1 | ||||
-rw-r--r-- | isisd/isisd.c | 42 | ||||
-rw-r--r-- | isisd/isisd.h | 9 |
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 */ |