diff options
author | Olivier Dugeon <olivier.dugeon@orange.com> | 2021-06-30 17:23:56 +0200 |
---|---|---|
committer | Olivier Dugeon <olivier.dugeon@orange.com> | 2021-11-30 15:22:28 +0100 |
commit | 173f8887cc3716985bfe4b84bdf2228194716f7d (patch) | |
tree | 6bf71295b47e814980e8620feba04e6950d7ed18 | |
parent | Merge pull request #10146 from ton31337/fix/acl_bmp (diff) | |
download | frr-173f8887cc3716985bfe4b84bdf2228194716f7d.tar.xz frr-173f8887cc3716985bfe4b84bdf2228194716f7d.zip |
isisd: Add support for RFC6119 (IPv6 TE in IS-IS)
- Add advertisement of Global IPv6 address in IIH pdu
- Add new CLI to set IPv6 Router ID
- Add advertisement of IPv6 Router ID
- Correctly advertise IPv6 local and neighbor addresses in Extended IS and MT
Reachability TLVs
- Correct output of Neighbor IPv6 address in 'show isis database detail'
- Manage IPv6 addresses advertisement and corresponiding Adjacency SID when
IS-IS is not using Multi-Topology by introducing a new ISIS_MT_DISABLE
value for mtid (== 4096 i.e. first reserved flag set to 1)
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
-rw-r--r-- | doc/user/isisd.rst | 4 | ||||
-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 | 39 | ||||
-rw-r--r-- | isisd/isis_lfa.c | 5 | ||||
-rw-r--r-- | isisd/isis_lsp.c | 16 | ||||
-rw-r--r-- | isisd/isis_mt.c | 11 | ||||
-rw-r--r-- | isisd/isis_mt.h | 2 | ||||
-rw-r--r-- | isisd/isis_nb.c | 8 | ||||
-rw-r--r-- | isisd/isis_nb.h | 7 | ||||
-rw-r--r-- | isisd/isis_nb_config.c | 51 | ||||
-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 | 139 | ||||
-rw-r--r-- | isisd/isis_te.h | 3 | ||||
-rw-r--r-- | isisd/isis_tlvs.c | 349 | ||||
-rw-r--r-- | isisd/isis_tlvs.h | 8 | ||||
-rw-r--r-- | tests/isisd/test_fuzz_isis_tlv_tests.h.gz | bin | 176859 -> 245481 bytes | |||
-rw-r--r-- | yang/frr-isisd.yang | 5 |
23 files changed, 619 insertions, 118 deletions
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 4a711a8fe..2bba3b975 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -330,6 +330,10 @@ Traffic Engineering Configure stable IP address for MPLS-TE. +.. clicmd:: mpls-te router-address ipv6 <X:X::X:X> + + Configure stable IPv6 address for MPLS-TE. + .. clicmd:: show isis mpls-te interface .. clicmd:: show isis mpls-te interface INTERFACE diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index f5e8a790b..ea05824f0 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); @@ -414,11 +414,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); } @@ -577,12 +577,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 bf03d0a05..b6f798bb2 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 @@ -3125,6 +3162,8 @@ 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_default_originate_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..94353a5bc 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1067,6 +1067,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 +1609,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 +1639,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), 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..57d013b3d 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -567,6 +567,14 @@ 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/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..11167096c 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -211,6 +211,10 @@ 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 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 +467,9 @@ 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_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..bf043c4f4 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1930,6 +1930,57 @@ 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/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..348894fed 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -248,29 +248,99 @@ 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; + + /* Sanity Check */ + if (!adj || !adj->circuit) + return 0; + + circuit = adj->circuit; - struct isis_circuit *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 Remote IP address parameter if possible */ - if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext)) + /* Update MPLS TE IP address parameters if possible */ + if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(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); + /* 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; } @@ -302,6 +372,25 @@ int isis_mpls_te_update(struct interface *ifp) /* 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 +420,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 +433,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); } } } @@ -536,8 +611,8 @@ 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 */ diff --git a/isisd/isis_te.h b/isisd/isis_te.h index 2a6911d50..e69ae4072 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -101,8 +101,9 @@ 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; }; /* Prototypes. */ 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/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex b50c5683b..accc906bf 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 5997e8866..7a67a739e 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1481,6 +1481,11 @@ module frr-isisd { description "Stable IP address of the advertising router."; } + leaf router-address-v6 { + type inet:ipv6-address; + description + "Stable IPv6 address of the advertising router."; + } } container segment-routing { |