mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 21:10:28 +00:00
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>
This commit is contained in:
parent
0536fea8d2
commit
173f8887cc
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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" \
|
||||
|
@ -566,6 +566,14 @@ const struct frr_yang_module_info frr_isisd_info = {
|
||||
.modify = isis_instance_mpls_te_router_address_modify,
|
||||
},
|
||||
},
|
||||
{
|
||||
.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 = {
|
||||
|
@ -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);
|
||||
|
@ -1929,6 +1929,57 @@ int isis_instance_mpls_te_router_address_destroy(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
141
isisd/isis_te.c
141
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;
|
||||
|
||||
struct isis_circuit *circuit = adj->circuit;
|
||||
|
||||
/* Update MPLS TE Remote IP address parameter if possible */
|
||||
if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
|
||||
/* Sanity Check */
|
||||
if (!adj || !adj->circuit)
|
||||
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);
|
||||
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:
|
||||
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 */
|
||||
|
@ -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. */
|
||||
|
@ -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));
|
||||
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->ipv6_address_count; oc++) {
|
||||
memset(&adj->ipv6_addresses[oc], 0,
|
||||
sizeof(adj->ipv6_addresses[oc]));
|
||||
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);
|
||||
|
@ -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,
|
||||
|
Binary file not shown.
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user