Merge pull request #6934 from Niral-Networks/niral_dev_vrf_isis_core_pr4

isisd, yang, doc : Support for different VRF in ISIS.
This commit is contained in:
Renato Westphal 2020-09-04 18:44:56 -03:00 committed by GitHub
commit b686742e2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 2692 additions and 97 deletions

View File

@ -47,7 +47,7 @@ digraph climodes {
CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ]; CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ];
CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ]; CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ];
CONFIG_NODE -> LDP_NODE [ label="mpls ldp" ]; CONFIG_NODE -> LDP_NODE [ label="mpls ldp" ];
CONFIG_NODE -> ISIS_NODE [ label="router isis WORD" ]; CONFIG_NODE -> ISIS_NODE [ label="router isis WORD [vrf NAME]" ];
CONFIG_NODE -> RMAP_NODE [ label="route-map WORD <deny|permit> (1-65535)" ]; CONFIG_NODE -> RMAP_NODE [ label="route-map WORD <deny|permit> (1-65535)" ];
CONFIG_NODE -> PW_NODE [ label="pseudowire IFNAME" ]; CONFIG_NODE -> PW_NODE [ label="pseudowire IFNAME" ];
CONFIG_NODE -> VTY_NODE [ label="line vty" ]; CONFIG_NODE -> VTY_NODE [ label="line vty" ];

View File

@ -33,8 +33,8 @@ ISIS router
To start the ISIS process you have to specify the ISIS router. As of this To start the ISIS process you have to specify the ISIS router. As of this
writing, *isisd* does not support multiple ISIS processes. writing, *isisd* does not support multiple ISIS processes.
.. index:: [no] router isis WORD .. index:: [no] router isis WORD [vrf NAME]
.. clicmd:: [no] router isis WORD .. clicmd:: [no] router isis WORD [vrf NAME]
Enable or disable the ISIS process by specifying the ISIS domain with Enable or disable the ISIS process by specifying the ISIS domain with
'WORD'. *isisd* does not yet support multiple ISIS processes but you must 'WORD'. *isisd* does not yet support multiple ISIS processes but you must
@ -202,8 +202,8 @@ ISIS interface
.. _ip-router-isis-word: .. _ip-router-isis-word:
.. index:: [no] <ip|ipv6> router isis WORD .. index:: [no] <ip|ipv6> router isis WORD [vrf NAME]
.. clicmd:: [no] <ip|ipv6> router isis WORD .. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]
Activate ISIS adjacency on this interface. Note that the name of ISIS Activate ISIS adjacency on this interface. Note that the name of ISIS
instance must be the same as the one used to configure the ISIS process (see instance must be the same as the one used to configure the ISIS process (see
@ -751,3 +751,22 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration.
segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null
! !
ISIS Vrf Configuration Examples
===============================
A simple vrf example:
.. code-block:: frr
!
interface eth0 vrf RED
ip router isis FOO vrf RED
isis network point-to-point
isis circuit-type level-2-only
!
router isis FOO vrf RED
net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
metric-style wide
is-type level-2-only

View File

@ -1244,12 +1244,14 @@ static int isis_interface_config_write(struct vty *vty)
#else #else
static int isis_interface_config_write(struct vty *vty) static int isis_interface_config_write(struct vty *vty)
{ {
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct vrf *vrf = NULL;
int write = 0; int write = 0;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
struct interface *ifp; struct interface *ifp;
struct lyd_node *dnode;
FOR_ALL_INTERFACES (vrf, ifp) { FOR_ALL_INTERFACES (vrf, ifp) {
struct lyd_node *dnode;
dnode = yang_dnode_get( dnode = yang_dnode_get(
running_config->dnode, running_config->dnode,
"/frr-interface:lib/interface[name='%s'][vrf='%s']", "/frr-interface:lib/interface[name='%s'][vrf='%s']",
@ -1260,6 +1262,7 @@ static int isis_interface_config_write(struct vty *vty)
write++; write++;
nb_cli_show_dnode_cmds(vty, dnode, false); nb_cli_show_dnode_cmds(vty, dnode, false);
} }
}
return write; return write;
} }
#endif /* ifdef FABRICD */ #endif /* ifdef FABRICD */
@ -1268,6 +1271,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
struct interface *ifp) struct interface *ifp)
{ {
struct isis_circuit *circuit = circuit_scan_by_ifp(ifp); struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
if (circuit && circuit->area) if (circuit && circuit->area)
return NULL; return NULL;
circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area); circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area);
@ -1446,7 +1450,7 @@ int isis_if_delete_hook(struct interface *ifp)
/* Clean up the circuit data */ /* Clean up the circuit data */
if (ifp && ifp->info) { if (ifp && ifp->info) {
circuit = ifp->info; circuit = ifp->info;
isis_csm_state_change(IF_DOWN_FROM_Z, circuit, circuit->area); isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
} }
return 0; return 0;
@ -1454,10 +1458,15 @@ int isis_if_delete_hook(struct interface *ifp)
static int isis_ifp_create(struct interface *ifp) static int isis_ifp_create(struct interface *ifp)
{ {
if (if_is_operative(ifp)) struct vrf *vrf = NULL;
if (if_is_operative(ifp)) {
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf)
isis_global_instance_create(vrf->name);
isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
ifp); ifp);
}
hook_call(isis_if_new_hook, ifp); hook_call(isis_if_new_hook, ifp);
return 0; return 0;

View File

@ -46,16 +46,21 @@
/* /*
* XPath: /frr-isisd:isis/instance * XPath: /frr-isisd:isis/instance
*/ */
DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag", DEFPY_YANG_NOSH(router_isis, router_isis_cmd,
"router isis WORD$tag [vrf NAME$vrf_name]",
ROUTER_STR ROUTER_STR
"ISO IS-IS\n" "ISO IS-IS\n"
"ISO Routing area tag\n") "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{ {
int ret; int ret;
char base_xpath[XPATH_MAXLEN]; char base_xpath[XPATH_MAXLEN];
if (!vrf_name)
vrf_name = VRF_DEFAULT_NAME;
snprintf(base_xpath, XPATH_MAXLEN, snprintf(base_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']", tag); "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
vrf_name);
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
/* default value in yang for is-type is level-1, but in FRR /* default value in yang for is-type is level-1, but in FRR
* the first instance is assigned is-type level-1-2. We * the first instance is assigned is-type level-1-2. We
@ -77,25 +82,30 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
return ret; return ret;
} }
DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", DEFPY_YANG(no_router_isis, no_router_isis_cmd,
"no router isis WORD$tag [vrf NAME$vrf_name]",
NO_STR ROUTER_STR NO_STR ROUTER_STR
"ISO IS-IS\n" "ISO IS-IS\n"
"ISO Routing area tag\n") "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{ {
char temp_xpath[XPATH_MAXLEN]; char temp_xpath[XPATH_MAXLEN];
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct isis_circuit *circuit = NULL; struct isis_circuit *circuit = NULL;
struct isis_area *area = NULL; struct isis_area *area = NULL;
if (!yang_dnode_exists(vty->candidate_config->dnode, if (!vrf_name)
"/frr-isisd:isis/instance[area-tag='%s']", vrf_name = VRF_DEFAULT_NAME;
tag)) {
if (!yang_dnode_exists(
vty->candidate_config->dnode,
"/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
vrf_name)) {
vty_out(vty, "ISIS area %s not found.\n", tag); vty_out(vty, "ISIS area %s not found.\n", tag);
return CMD_ERR_NOTHING_TODO; return CMD_ERR_NOTHING_TODO;
} }
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
area = isis_area_lookup(tag, VRF_DEFAULT); area = isis_area_lookup_by_vrf(tag, vrf_name);
if (area && area->circuit_list && listcount(area->circuit_list)) { if (area && area->circuit_list && listcount(area->circuit_list)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode, for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) { circuit)) {
@ -114,15 +124,23 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
} }
return nb_cli_apply_changes( return nb_cli_apply_changes(
vty, "/frr-isisd:isis/instance[area-tag='%s']", tag); vty, "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
vrf_name);
} }
void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
bool show_defaults) bool show_defaults)
{ {
const char *vrf = NULL;
vrf = yang_dnode_get_string(dnode, "./vrf");
vty_out(vty, "!\n"); vty_out(vty, "!\n");
vty_out(vty, "router isis %s\n", vty_out(vty, "router isis %s ",
yang_dnode_get_string(dnode, "./area-tag")); yang_dnode_get_string(dnode, "./area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf"));
vty_out(vty, "\n");
} }
/* /*
@ -131,16 +149,18 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
* XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing
* XPath: /frr-isisd:isis/instance * XPath: /frr-isisd:isis/instance
*/ */
DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag", DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
"ip router isis WORD$tag [vrf NAME$vrf_name]",
"Interface Internet Protocol config commands\n" "Interface Internet Protocol config commands\n"
"IP router interface commands\n" "IP router interface commands\n"
"IS-IS routing protocol\n" "IS-IS routing protocol\n"
"Routing process tag\n") "Routing process tag\n" VRF_CMD_HELP_STR)
{ {
char temp_xpath[XPATH_MAXLEN]; char temp_xpath[XPATH_MAXLEN];
const char *circ_type; const char *circ_type;
struct isis_area *area = NULL; struct isis_area *area = NULL;
struct interface *ifp; struct interface *ifp;
struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model /* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb. * is synced with FRR and call the appropriate NB cb.
@ -150,16 +170,26 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return CMD_SUCCESS; return CMD_SUCCESS;
} }
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp)
area = isis_area_lookup(tag, ifp->vrf_id);
if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
vrf_name = VRF_DEFAULT_NAME;
if (ifp->vrf_id != VRF_DEFAULT) {
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf && !vrf_name)
vrf_name = vrf->name;
}
area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) { if (!area) {
isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN, snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']", tag); "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag); nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
snprintf(temp_xpath, XPATH_MAXLEN, snprintf(
"/frr-isisd:isis/instance[area-tag='%s']/is-type", temp_xpath, XPATH_MAXLEN,
tag); "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY, nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2" listcount(im->isis) == 0 ? "level-1-2"
: NULL); : NULL);
@ -167,6 +197,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL); NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag); NB_OP_MODIFY, tag);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true"); NB_OP_MODIFY, "true");
nb_cli_enqueue_change( nb_cli_enqueue_change(
@ -192,6 +225,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL); NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag); NB_OP_MODIFY, tag);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true"); NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@ -206,16 +242,18 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return nb_cli_apply_changes(vty, NULL); return nb_cli_apply_changes(vty, NULL);
} }
DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag", DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
"ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
"Interface Internet Protocol config commands\n" "Interface Internet Protocol config commands\n"
"IP router interface commands\n" "IP router interface commands\n"
"IS-IS routing protocol\n" "IS-IS routing protocol\n"
"Routing process tag\n") "Routing process tag\n" VRF_CMD_HELP_STR)
{ {
char temp_xpath[XPATH_MAXLEN]; char temp_xpath[XPATH_MAXLEN];
const char *circ_type; const char *circ_type;
struct isis_area *area = NULL;
struct interface *ifp; struct interface *ifp;
struct isis_area *area;
struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model /* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb. * is synced with FRR and call the appropriate NB cb.
@ -225,16 +263,25 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
return CMD_SUCCESS; return CMD_SUCCESS;
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp) if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
area = isis_area_lookup(tag, ifp->vrf_id); vrf_name = VRF_DEFAULT_NAME;
if (ifp->vrf_id != VRF_DEFAULT) {
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf && !vrf_name)
vrf_name = vrf->name;
}
area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) { if (!area) {
isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN, snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']", tag); "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag); nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
snprintf(temp_xpath, XPATH_MAXLEN, snprintf(
"/frr-isisd:isis/instance[area-tag='%s']/is-type", temp_xpath, XPATH_MAXLEN,
tag); "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY, nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2" listcount(im->isis) == 0 ? "level-1-2"
: NULL); : NULL);
@ -242,6 +289,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL); NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag); NB_OP_MODIFY, tag);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true"); NB_OP_MODIFY, "true");
nb_cli_enqueue_change( nb_cli_enqueue_change(
@ -267,6 +317,8 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL); NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag); NB_OP_MODIFY, tag);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true"); NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@ -282,7 +334,7 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
} }
DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd, DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
"no <ip|ipv6>$ip router isis [WORD]$tag", "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]",
NO_STR NO_STR
"Interface Internet Protocol config commands\n" "Interface Internet Protocol config commands\n"
"IP router interface commands\n" "IP router interface commands\n"
@ -324,19 +376,33 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults) bool show_defaults)
{ {
const char *vrf;
vrf = yang_dnode_get_string(dnode, "../vrf");
if (!yang_dnode_get_bool(dnode, NULL)) if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no"); vty_out(vty, " no");
vty_out(vty, " ip router isis %s\n", vty_out(vty, " ip router isis %s ",
yang_dnode_get_string(dnode, "../area-tag")); yang_dnode_get_string(dnode, "../area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
vty_out(vty, "vrf %s", vrf);
vty_out(vty, "\n");
} }
void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
bool show_defaults) bool show_defaults)
{ {
const char *vrf;
vrf = yang_dnode_get_string(dnode, "../vrf");
if (!yang_dnode_get_bool(dnode, NULL)) if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no"); vty_out(vty, " no");
vty_out(vty, " ipv6 router isis %s\n", vty_out(vty, " ipv6 router isis %s ",
yang_dnode_get_string(dnode, "../area-tag")); yang_dnode_get_string(dnode, "../area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
vty_out(vty, "vrf %s", vrf);
vty_out(vty, "\n");
} }
/* /*

View File

@ -236,13 +236,12 @@ int main(int argc, char **argv, char **envp)
/* thread master */ /* thread master */
isis_master_init(frr_init()); isis_master_init(frr_init());
master = im->master; master = im->master;
/* /*
* initializations * initializations
*/ */
isis_error_init(); isis_error_init();
access_list_init(); access_list_init();
vrf_init(NULL, NULL, NULL, NULL, NULL); isis_vrf_init();
prefix_list_init(); prefix_list_init();
isis_init(); isis_init();
isis_circuit_init(); isis_circuit_init();
@ -261,7 +260,7 @@ int main(int argc, char **argv, char **envp)
mt_init(); mt_init();
/* create the global 'isis' instance */ /* create the global 'isis' instance */
isis_global_instance_create(); isis_global_instance_create(VRF_DEFAULT_NAME);
isis_zebra_init(master, instance); isis_zebra_init(master, instance);
isis_bfd_init(); isis_bfd_init();

View File

@ -550,6 +550,13 @@ const struct frr_yang_module_info frr_isisd_info = {
.modify = lib_interface_isis_area_tag_modify, .modify = lib_interface_isis_area_tag_modify,
}, },
}, },
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/vrf",
.cbs = {
.modify = lib_interface_isis_vrf_modify,
},
},
{ {
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type", .xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
.cbs = { .cbs = {

View File

@ -168,6 +168,7 @@ int isis_instance_mpls_te_router_address_destroy(
int lib_interface_isis_create(struct nb_cb_create_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_destroy(struct nb_cb_destroy_args *args);
int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args); int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args); int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args); int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args); int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args);

View File

@ -53,16 +53,19 @@ int isis_instance_create(struct nb_cb_create_args *args)
{ {
struct isis_area *area; struct isis_area *area;
const char *area_tag; const char *area_tag;
const char *vrf_name;
if (args->event != NB_EV_APPLY) if (args->event != NB_EV_APPLY)
return NB_OK; return NB_OK;
vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
area = isis_area_lookup(area_tag, VRF_DEFAULT); isis_global_instance_create(vrf_name);
area = isis_area_lookup_by_vrf(area_tag, vrf_name);
if (area) if (area)
return NB_ERR_INCONSISTENCY; return NB_ERR_INCONSISTENCY;
area = isis_area_create(area_tag, VRF_DEFAULT_NAME); area = isis_area_create(area_tag, vrf_name);
/* save area in dnode to avoid looking it up all the time */ /* save area in dnode to avoid looking it up all the time */
nb_running_set_entry(args->dnode, area); nb_running_set_entry(args->dnode, area);
@ -75,7 +78,6 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
if (args->event != NB_EV_APPLY) if (args->event != NB_EV_APPLY)
return NB_OK; return NB_OK;
area = nb_running_unset_entry(args->dnode); area = nb_running_unset_entry(args->dnode);
isis_area_destroy(area); isis_area_destroy(area);
@ -116,7 +118,6 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
area = nb_running_get_entry(args->dnode, NULL, true); area = nb_running_get_entry(args->dnode, NULL, true);
if (area == NULL) if (area == NULL)
return NB_ERR_VALIDATION; return NB_ERR_VALIDATION;
addr.addr_len = dotformat2buff(buff, net_title); addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len); memcpy(addr.area_addr, buff, addr.addr_len);
if (addr.area_addr[addr.addr_len - 1] != 0) { if (addr.area_addr[addr.addr_len - 1] != 0) {
@ -148,6 +149,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
case NB_EV_APPLY: case NB_EV_APPLY:
area = nb_running_get_entry(args->dnode, NULL, true); area = nb_running_get_entry(args->dnode, NULL, true);
addrr = args->resource->ptr; addrr = args->resource->ptr;
assert(area);
if (area->isis->sysid_set == 0) { if (area->isis->sysid_set == 0) {
/* /*
@ -1830,8 +1832,10 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
{ {
struct isis_area *area = NULL; struct isis_area *area = NULL;
struct interface *ifp; struct interface *ifp;
struct isis_circuit *circuit; struct isis_circuit *circuit = NULL;
struct vrf *vrf;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
const char *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
uint32_t min_mtu, actual_mtu; uint32_t min_mtu, actual_mtu;
switch (args->event) { switch (args->event) {
@ -1846,8 +1850,17 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
/* zebra might not know yet about the MTU - nothing we can do */ /* zebra might not know yet about the MTU - nothing we can do */
if (!ifp || ifp->mtu == 0) if (!ifp || ifp->mtu == 0)
break; break;
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (ifp->vrf_id != VRF_DEFAULT && vrf
&& strcmp(vrf->name, vrf_name) != 0) {
snprintf(args->errmsg, args->errmsg_len,
"interface %s not in vrf %s\n", ifp->name,
vrf_name);
return NB_ERR_VALIDATION;
}
actual_mtu = actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu; if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
area = isis_area_lookup(area_tag, ifp->vrf_id); area = isis_area_lookup(area_tag, ifp->vrf_id);
if (area) if (area)
min_mtu = area->lsp_mtu; min_mtu = area->lsp_mtu;
@ -1866,9 +1879,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
} }
break; break;
case NB_EV_APPLY: case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true); area = isis_area_lookup_by_vrf(area_tag, vrf_name);
if (ifp)
area = isis_area_lookup(area_tag, ifp->vrf_id);
/* The area should have already be created. We are /* The area should have already be created. We are
* setting the priority of the global isis area creation * setting the priority of the global isis area creation
* slightly lower, so it should be executed first, but I * slightly lower, so it should be executed first, but I
@ -1881,7 +1892,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
__func__, area_tag); __func__, area_tag);
abort(); abort();
} }
ifp = nb_running_get_entry(args->dnode, NULL, true);
circuit = isis_circuit_create(area, ifp); circuit = isis_circuit_create(area, ifp);
assert(circuit assert(circuit
&& (circuit->state == C_STATE_CONF && (circuit->state == C_STATE_CONF
@ -1956,6 +1967,44 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
return NB_OK; return NB_OK;
} }
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/vrf
*/
int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct vrf *vrf;
const char *ifname, *vrfname, *vrf_name;
struct isis_circuit *circuit;
if (args->event == NB_EV_VALIDATE) {
/* libyang doesn't like relative paths across module boundaries
*/
ifname = yang_dnode_get_string(args->dnode->parent->parent,
"./name");
vrfname = yang_dnode_get_string(args->dnode->parent->parent,
"./vrf");
vrf = vrf_lookup_by_name(vrfname);
assert(vrf);
ifp = if_lookup_by_name(ifname, vrf->vrf_id);
if (!ifp)
return NB_OK;
vrf_name = yang_dnode_get_string(args->dnode, NULL);
circuit = circuit_scan_by_ifp(ifp);
if (circuit && circuit->area && circuit->area->isis
&& strcmp(circuit->area->isis->name, vrf_name)) {
snprintf(args->errmsg, args->errmsg_len,
"ISIS circuit is already defined on vrf %s",
circuit->area->isis->name);
return NB_ERR_VALIDATION;
}
}
return NB_OK;
}
/* /*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type * XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
*/ */

View File

@ -577,6 +577,20 @@ int isis_zebra_label_manager_connect(void)
return 0; return 0;
} }
void isis_zebra_vrf_register(struct isis *isis)
{
if (!zclient || zclient->sock < 0 || !isis)
return;
if (isis->vrf_id != VRF_UNKNOWN) {
if (IS_DEBUG_EVENTS)
zlog_debug("%s: Register VRF %s id %u", __func__,
isis->name, isis->vrf_id);
zclient_send_reg_requests(zclient, isis->vrf_id);
}
}
static void isis_zebra_connected(struct zclient *zclient) static void isis_zebra_connected(struct zclient *zclient)
{ {
zclient_send_reg_requests(zclient, VRF_DEFAULT); zclient_send_reg_requests(zclient, VRF_DEFAULT);

View File

@ -57,5 +57,6 @@ bool isis_zebra_label_manager_ready(void);
int isis_zebra_label_manager_connect(void); int isis_zebra_label_manager_connect(void);
int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size); int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
int isis_zebra_release_label_range(uint32_t start, uint32_t end); int isis_zebra_release_label_range(uint32_t start, uint32_t end);
void isis_zebra_vrf_register(struct isis *isis);
#endif /* _ZEBRA_ISIS_ZEBRA_H */ #endif /* _ZEBRA_ISIS_ZEBRA_H */

View File

@ -35,6 +35,7 @@
#include "prefix.h" #include "prefix.h"
#include "table.h" #include "table.h"
#include "qobj.h" #include "qobj.h"
#include "zclient.h"
#include "vrf.h" #include "vrf.h"
#include "spf_backoff.h" #include "spf_backoff.h"
#include "lib/northbound_cli.h" #include "lib/northbound_cli.h"
@ -167,29 +168,32 @@ void isis_master_init(struct thread_master *master)
im->master = master; im->master = master;
} }
void isis_global_instance_create() void isis_global_instance_create(const char *vrf_name)
{ {
struct isis *isis; struct isis *isis;
isis = isis_lookup_by_vrfid(VRF_DEFAULT); isis = isis_lookup_by_vrfname(vrf_name);
if (isis == NULL) { if (isis == NULL) {
isis = isis_new(VRF_DEFAULT); isis = isis_new(vrf_name);
isis_add(isis); isis_add(isis);
} }
} }
struct isis *isis_new(vrf_id_t vrf_id) struct isis *isis_new(const char *vrf_name)
{ {
struct vrf *vrf; struct vrf *vrf;
struct isis *isis; struct isis *isis;
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
isis->vrf_id = vrf_id; vrf = vrf_lookup_by_name(vrf_name);
vrf = vrf_lookup_by_id(vrf_id);
if (vrf) { if (vrf) {
isis->vrf_id = vrf->vrf_id;
isis_vrf_link(isis, vrf); isis_vrf_link(isis, vrf);
isis->name = XSTRDUP(MTYPE_ISIS, vrf->name); isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
} else {
isis->vrf_id = VRF_UNKNOWN;
isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
} }
if (IS_DEBUG_EVENTS) if (IS_DEBUG_EVENTS)
@ -223,15 +227,20 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
if (vrf) { if (vrf) {
isis = isis_lookup_by_vrfid(vrf->vrf_id); isis = isis_lookup_by_vrfid(vrf->vrf_id);
if (isis == NULL) { if (isis == NULL) {
isis = isis_new(vrf->vrf_id); isis = isis_new(vrf_name);
isis_add(isis); isis_add(isis);
} }
} else } else {
return NULL; isis = isis_lookup_by_vrfid(VRF_UNKNOWN);
if (isis == NULL) {
isis = isis_new(vrf_name);
isis_add(isis);
}
}
} else { } else {
isis = isis_lookup_by_vrfid(VRF_DEFAULT); isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL) { if (isis == NULL) {
isis = isis_new(VRF_DEFAULT); isis = isis_new(VRF_DEFAULT_NAME);
isis_add(isis); isis_add(isis);
} }
} }
@ -336,6 +345,24 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
return area; return area;
} }
struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
const char *vrf_name)
{
struct isis_area *area;
struct listnode *node;
struct isis *isis = NULL;
isis = isis_lookup_by_vrfname(vrf_name);
if (isis == NULL)
return NULL;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
if (strcmp(area->area_tag, area_tag) == 0)
return area;
return NULL;
}
struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id)
{ {
struct isis_area *area; struct isis_area *area;
@ -449,6 +476,95 @@ void isis_area_destroy(struct isis_area *area)
} }
/* This is hook function for vrf create called as part of vrf_init */
static int isis_vrf_new(struct vrf *vrf)
{
if (IS_DEBUG_EVENTS)
zlog_debug("%s: VRF Created: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
return 0;
}
/* This is hook function for vrf delete call as part of vrf_init */
static int isis_vrf_delete(struct vrf *vrf)
{
if (IS_DEBUG_EVENTS)
zlog_debug("%s: VRF Deletion: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
return 0;
}
static int isis_vrf_enable(struct vrf *vrf)
{
struct isis *isis;
vrf_id_t old_vrf_id;
if (IS_DEBUG_EVENTS)
zlog_debug("%s: VRF %s id %u enabled", __func__, vrf->name,
vrf->vrf_id);
isis = isis_lookup_by_vrfname(vrf->name);
if (isis) {
if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
XFREE(MTYPE_ISIS, isis->name);
isis->name = NULL;
}
old_vrf_id = isis->vrf_id;
/* We have instance configured, link to VRF and make it "up". */
isis_vrf_link(isis, vrf);
if (IS_DEBUG_EVENTS)
zlog_debug(
"%s: isis linked to vrf %s vrf_id %u (old id %u)",
__func__, vrf->name, isis->vrf_id, old_vrf_id);
if (old_vrf_id != isis->vrf_id) {
frr_with_privs (&isisd_privs) {
/* stop zebra redist to us for old vrf */
zclient_send_dereg_requests(zclient,
old_vrf_id);
/* start zebra redist to us for new vrf */
isis_zebra_vrf_register(isis);
}
}
}
return 0;
}
static int isis_vrf_disable(struct vrf *vrf)
{
struct isis *isis;
vrf_id_t old_vrf_id = VRF_UNKNOWN;
if (vrf->vrf_id == VRF_DEFAULT)
return 0;
if (IS_DEBUG_EVENTS)
zlog_debug("%s: VRF %s id %d disabled.", __func__, vrf->name,
vrf->vrf_id);
isis = isis_lookup_by_vrfname(vrf->name);
if (isis) {
old_vrf_id = isis->vrf_id;
/* We have instance configured, unlink
* from VRF and make it "down".
*/
isis_vrf_unlink(isis, vrf);
if (IS_DEBUG_EVENTS)
zlog_debug("%s: isis old_vrf_id %d unlinked", __func__,
old_vrf_id);
}
return 0;
}
void isis_vrf_init(void)
{
vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable,
isis_vrf_delete, isis_vrf_enable);
}
void isis_finish(struct isis *isis) void isis_finish(struct isis *isis)
{ {
struct vrf *vrf = NULL; struct vrf *vrf = NULL;

View File

@ -73,7 +73,6 @@ struct isis_master {
struct list *isis; struct list *isis;
/* ISIS thread master. */ /* ISIS thread master. */
struct thread_master *master; struct thread_master *master;
/* Various OSPF global configuration. */
uint8_t options; uint8_t options;
}; };
#define F_ISIS_UNIT_TEST 0x01 #define F_ISIS_UNIT_TEST 0x01
@ -213,15 +212,19 @@ void isis_finish(struct isis *isis);
void isis_master_init(struct thread_master *master); void isis_master_init(struct thread_master *master);
void isis_vrf_link(struct isis *isis, struct vrf *vrf); void isis_vrf_link(struct isis *isis, struct vrf *vrf);
void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
void isis_global_instance_create(void); void isis_global_instance_create(const char *vrf_name);
struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);
struct isis *isis_lookup_by_vrfname(const char *vrfname); struct isis *isis_lookup_by_vrfname(const char *vrfname);
struct isis *isis_lookup_by_sysid(const uint8_t *sysid); struct isis *isis_lookup_by_sysid(const uint8_t *sysid);
void isis_init(void); void isis_init(void);
struct isis *isis_new(vrf_id_t vrf_id); void isis_vrf_init(void);
struct isis *isis_new(const char *vrf_name);
struct isis_area *isis_area_create(const char *, const char *); struct isis_area *isis_area_create(const char *, const char *);
struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id);
struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
const char *vrf_name);
int isis_area_get(struct vty *vty, const char *area_tag); int isis_area_get(struct vty *vty, const char *area_tag);
void isis_area_destroy(struct isis_area *area); void isis_area_destroy(struct isis_area *area);
void print_debug(struct vty *, int, int); void print_debug(struct vty *, int, int);

View File

@ -291,7 +291,7 @@ int main(int argc, char **argv)
/* IS-IS inits. */ /* IS-IS inits. */
yang_module_load("frr-isisd"); yang_module_load("frr-isisd");
isis = isis_new(VRF_DEFAULT); isis = isis_new(VRF_DEFAULT_NAME);
listnode_add(im->isis, isis); listnode_add(im->isis, isis);
SET_FLAG(im->options, F_ISIS_UNIT_TEST); SET_FLAG(im->options, F_ISIS_UNIT_TEST);
debug_spf_events |= DEBUG_SPF_EVENTS; debug_spf_events |= DEBUG_SPF_EVENTS;

View File

@ -0,0 +1,15 @@
hostname r1
debug isis adj-packets
debug isis events
debug isis update-packets
interface r1-eth0
ip router isis 1 vrf r1-cust1
ipv6 router isis 1 vrf r1-cust1
isis circuit-type level-2-only
!
router isis 1 vrf r1-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00
metric-style wide
redistribute ipv4 connected level-2
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,57 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0",
"ip": "10.0.20.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
],
"10.0.20.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r1-eth0",
"ip": "10.0.20.1"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"vrfId": 3,
"vrfName": "r1-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "10.0.20.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
]
}

View File

@ -0,0 +1,40 @@
{
"2001:db8:1:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
],
"2001:db8:2:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
]
}

View File

@ -0,0 +1,14 @@
{
"2001:db8:1:1::/64": {
"dev": "r1-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:1::/64": {
"dev": "r1-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,13 @@
{
"10.0.10.0/24": {
"dev": "r1-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.20.1"
},
"10.0.20.0/24": {
"dev": "r1-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,80 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r1"
}
],
"ipv6": [
{
"vertex": "r1"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r1"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r1-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r1(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP",
"vertex": "10.0.10.0/24"
}
],
"ipv6": [
{
"vertex": "r1"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r1-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r1(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "internal",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
}
]
}
}
}

View File

@ -0,0 +1,9 @@
hostname r1
interface r1-eth0 vrf r1-cust1
ip address 10.0.20.2/24
ipv6 address 2001:db8:1:1::2/64
!
interface lo
ip address 10.254.0.1/32
ipv6 address 2001:db8:F::1/128
!

View File

@ -0,0 +1,15 @@
hostname r2
debug isis adj-packets
debug isis events
debug isis update-packets
interface r2-eth0
ip router isis 1 vrf r2-cust1
ipv6 router isis 1 vrf r2-cust1
isis circuit-type level-2-only
!
router isis 1 vrf r2-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
metric-style wide
redistribute ipv4 connected level-2
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,57 @@
{
"10.0.11.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0",
"ip": "10.0.21.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
],
"10.0.21.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r2-eth0",
"ip": "10.0.21.1"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"vrfId": 3,
"vrfName": "r2-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "10.0.21.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
]
}

View File

@ -0,0 +1,40 @@
{
"2001:db8:1:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
],
"2001:db8:2:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
]
}

View File

@ -0,0 +1,14 @@
{
"2001:db8:1:2::/64": {
"dev": "r2-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r2-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,13 @@
{
"10.0.11.0/24": {
"dev": "r2-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.21.1"
},
"10.0.21.0/24": {
"dev": "r2-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,80 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r2"
}
],
"ipv6": [
{
"vertex": "r2"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r2"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r2-eth0",
"metric": "10",
"next-hop": "r4",
"parent": "r2(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP",
"vertex": "10.0.11.0/24"
}
],
"ipv6": [
{
"vertex": "r2"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
},
{
"interface": "r2-eth0",
"metric": "10",
"next-hop": "r4",
"parent": "r2(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r4",
"metric": "internal",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
}
]
}
}
}

View File

@ -0,0 +1,9 @@
hostname r2
interface r2-eth0 vrf r2-cust1
ip address 10.0.21.2/24
ipv6 address 2001:db8:1:2::2/64
!
interface lo
ip address 10.254.0.2/32
ipv6 address 2001:db8:F::2/128
!

View File

@ -0,0 +1,22 @@
hostname r3
debug isis adj-packets
debug isis events
debug isis update-packets
interface r3-eth0
ip router isis 1 vrf r3-cust1
ipv6 router isis 1 vrf r3-cust1
isis circuit-type level-2-only
!
interface r3-eth1
ip router isis 1 vrf r3-cust1
ipv6 router isis 1 vrf r3-cust1
isis circuit-type level-1
!
router isis 1 vrf r3-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv4 connected level-2
redistribute ipv6 connected level-1
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,112 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r3-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.11.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.20.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r3-eth0",
"ip": "10.0.20.2"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r3-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r3-eth0"
}
],
"prefix": "10.0.20.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.21.0/24": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r3-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:1:2::/64": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:2:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:2:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r3-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:1:2::/64": {
"dev": "r3-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:1::/64": {
"dev": "r3-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r3-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r3-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.11.0/24": {
"dev": "r3-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.10.1"
},
"10.0.20.0/24": {
"dev": "r3-eth0",
"proto": "kernel",
"scope": "link"
},
"10.0.21.0/24": {
"dev": "r3-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.10.1"
}
}

View File

@ -0,0 +1,132 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r3-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "30",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.21.0/24"
}
],
"ipv6": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"interface": "r3-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "30",
"parent": "r3-eth1",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
}
],
"ipv6": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r3-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r3"
}
]
}
}
}

View File

@ -0,0 +1,13 @@
hostname r3
interface r3-eth0 vrf r3-cust1
ip address 10.0.20.1/24
ipv6 address 2001:db8:1:1::1/64
!
interface r3-eth1 vrf r3-cust1
ip address 10.0.10.2/24
ipv6 address 2001:db8:2:1::2/64
!
interface lo
ip address 10.254.0.3/32
ipv6 address 2001:db8:F::3/128
!

View File

@ -0,0 +1,25 @@
hostname r4
debug isis adj-packets
debug isis events
debug isis update-packets
debug isis lsp-gen
debug isis lsp-sched
interface r4-eth0
ip router isis 1 vrf r4-cust1
ipv6 router isis 1 vrf r4-cust1
isis circuit-type level-2-only
!
interface r4-eth1
ip router isis 1 vrf r4-cust1
ipv6 router isis 1 vrf r4-cust1
isis circuit-type level-1
!
router isis 1 vrf r4-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv4 connected level-2
redistribute ipv6 connected level-1
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,105 @@
{
"10.0.10.0/24": [
{
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.11.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r4-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.20.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.21.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r4-eth0",
"ip": "10.0.21.2"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r4-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r4-eth0"
}
],
"prefix": "10.0.21.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:1:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r4-eth0"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:2:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:2:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r4-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:1:2::/64": {
"dev": "r4-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:1::/64": {
"dev": "r4-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:2::/64": {
"dev": "r4-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r4-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.1"
},
"10.0.11.0/24": {
"dev": "r4-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.20.0/24": {
"dev": "r4-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.1"
},
"10.0.21.0/24": {
"dev": "r4-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,132 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r4-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "30",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.20.0/24"
}
],
"ipv6": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r4-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "30",
"parent": "r4-eth1",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4-eth0",
"metric": "10",
"next-hop": "r2",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r2"
},
{
"interface": "r2",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth0",
"type": "IP",
"vertex": "10.0.21.0/24"
}
],
"ipv6": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
},
{
"interface": "r4-eth0",
"metric": "10",
"next-hop": "r2",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r2"
}
]
}
}
}

View File

@ -0,0 +1,13 @@
hostname r4
interface r4-eth0 vrf r4-cust1
ip address 10.0.21.1/24
ipv6 address 2001:db8:1:2::1/64
!
interface r4-eth1 vrf r4-cust1
ip address 10.0.11.2/24
ipv6 address 2001:db8:2:2::2/64
!
interface lo
ip address 10.254.0.4/32
ipv6 address 2001:db8:F::4/128
!

View File

@ -0,0 +1,21 @@
hostname r5
debug isis adj-packets
debug isis events
debug isis update-packets
interface r5-eth0
ip router isis 1 vrf r5-cust1
ipv6 router isis 1 vrf r5-cust1
isis circuit-type level-1
!
interface r5-eth1
ip router isis 1 vrf r5-cust1
ipv6 router isis 1 vrf r5-cust1
isis circuit-type level-1
!
router isis 1 vrf r5-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00
metric-style wide
is-type level-1
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
!

View File

@ -0,0 +1,106 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r5-eth0",
"ip": "10.0.10.2"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r5-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "10.0.10.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.11.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r5-eth1",
"ip": "10.0.11.2"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r5-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.20.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0",
"ip": "10.0.10.2"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.21.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1",
"ip": "10.0.11.2"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:1:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:2:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:2:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r5-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:1:2::/64": {
"dev": "r5-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:1::/64": {
"dev": "r5-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r5-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r5-eth0",
"proto": "kernel",
"scope": "link"
},
"10.0.11.0/24": {
"dev": "r5-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.20.0/24": {
"dev": "r5-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.10.2"
},
"10.0.21.0/24": {
"dev": "r5-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.2"
}
}

View File

@ -0,0 +1,124 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r5"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r5-eth1",
"metric": "10",
"next-hop": "r4",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
}
],
"ipv6": [
{
"vertex": "r5"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r5-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r5-eth1",
"metric": "10",
"next-hop": "r4",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r3",
"metric": "internal",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r4",
"metric": "internal",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
}
]
},
"level-2": {
"ipv4": [],
"ipv6": []
}
}
}

View File

@ -0,0 +1,13 @@
hostname r5
interface r5-eth0 vrf r5-cust1
ip address 10.0.10.1/24
ipv6 address 2001:db8:2:1::1/64
!
interface r5-eth1 vrf r5-cust1
ip address 10.0.11.1/24
ipv6 address 2001:db8:2:2::1/64
!
interface lo
ip address 10.254.0.5/32
ipv6 address 2001:db8:F::5/128
!

View File

@ -0,0 +1,100 @@
## Color coding:
#########################
## Main FRR: #f08080 red
## Switches: #d0e0d0 gray
## RIP: #19e3d9 Cyan
## RIPng: #fcb314 dark yellow
## OSPFv2: #32b835 Green
## OSPFv3: #19e3d9 Cyan
## ISIS IPv4 #fcb314 dark yellow
## ISIS IPv6 #9a81ec purple
## BGP IPv4 #eee3d3 beige
## BGP IPv6 #fdff00 yellow
##### Colors (see http://www.color-hex.com/)
graph template {
label="isis topo1";
# Routers
r1 [
shape=doubleoctagon,
label="r1\n10.254.0.1\n2001:DB8:F::1",
fillcolor="#f08080",
style=filled,
];
r2 [
shape=doubleoctagon
label="r2\n10.254.0.2\n2001:DB8:F::2",
fillcolor="#f08080",
style=filled,
];
r3 [
shape=doubleoctagon
label="r3\n10.254.0.3\n2001:DB8:F::3",
fillcolor="#f08080",
style=filled,
];
r4 [
shape=doubleoctagon
label="r4\n10.254.0.4\n2001:DB8:F::4",
fillcolor="#f08080",
style=filled,
];
r5 [
shape=doubleoctagon
label="r5\n10.254.0.5\n2001:DB8:F::5",
fillcolor="#f08080",
style=filled,
];
# Switches
sw1 [
shape=oval,
label="sw1\n10.0.20.0/24\n2001:DB8:1:1::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw2 [
shape=oval,
label="sw2\n10.0.21.0/24\n2001:DB8:1:2::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw3 [
shape=oval,
label="sw3\n10.0.10.0/24\n2001:DB8:2:1::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw4 [
shape=oval,
label="sw4\n10.0.11.0/24\n2001:DB8:2:2::/64",
fillcolor="#d0e0d0",
style=filled,
];
# Connections
subgraph cluster0 {
label="level 2";
r1 -- sw1 [label="eth0\n.2"];
r2 -- sw2 [label="eth0\n.2"];
}
subgraph cluster1 {
label="level 1/2";
r3 -- sw1 [label="eth0\n.1"];
r3 -- sw3 [label="eth1\n.2"];
r4 -- sw4 [label="eth1\n.2"];
r4 -- sw2 [label="eth0\n.1"];
}
subgraph cluster2 {
label="level 1";
r5 -- sw3 [label="eth0\n.1"];
r5 -- sw4 [label="eth1\n.1"];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,455 @@
#!/usr/bin/env python
#
# Copyright (c) 2020 by Niral Networks, Inc. ("Niral Networks")
# Used Copyright (c) 2018 by Network Device Education Foundation,
# Inc. ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_isis_topo1_vrf.py: Test ISIS vrf topology.
"""
import collections
import functools
import json
import os
import re
import sys
import pytest
import platform
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from mininet.topo import Topo
class ISISTopo1(Topo):
"Simple two layer ISIS vrf topology"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
# Add ISIS routers:
# r1 r2
# | sw1 | sw2
# r3 r4
# | |
# sw3 sw4
# \ /
# r5
for routern in range(1, 6):
tgen.add_router("r{}".format(routern))
# r1 <- sw1 -> r3
sw = tgen.add_switch("sw1")
sw.add_link(tgen.gears["r1"])
sw.add_link(tgen.gears["r3"])
# r2 <- sw2 -> r4
sw = tgen.add_switch("sw2")
sw.add_link(tgen.gears["r2"])
sw.add_link(tgen.gears["r4"])
# r3 <- sw3 -> r5
sw = tgen.add_switch("sw3")
sw.add_link(tgen.gears["r3"])
sw.add_link(tgen.gears["r5"])
# r4 <- sw4 -> r5
sw = tgen.add_switch("sw4")
sw.add_link(tgen.gears["r4"])
sw.add_link(tgen.gears["r5"])
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(ISISTopo1, mod.__name__)
tgen.start_topology()
logger.info("Testing with VRF Lite support")
krel = platform.release()
# May need to adjust handling of vrf traffic depending on kernel version
l3mdev_accept = 0
if (
topotest.version_cmp(krel, "4.15") >= 0
and topotest.version_cmp(krel, "4.18") <= 0
):
l3mdev_accept = 1
if topotest.version_cmp(krel, "5.0") >= 0:
l3mdev_accept = 1
logger.info(
"krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept)
)
cmds = [
"ip link add {0}-cust1 type vrf table 1001",
"ip link add loop1 type dummy",
"ip link set {0}-eth0 master {0}-cust1",
"ip link set {0}-eth1 master {0}-cust1",
]
# For all registered routers, load the zebra configuration file
for rname, router in tgen.routers().iteritems():
# create VRF rx-cust1 and link rx-eth0 to rx-cust1
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept")
logger.info(
"router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output)
)
if l3mdev_accept:
output = tgen.net[rname].cmd(
"sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
)
for rname, router in tgen.routers().iteritems():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_ISIS,
os.path.join(CWD, "{}/isisd.conf".format(rname))
)
# After loading the configurations, this function loads configured daemons.
tgen.start_router()
has_version_20 = False
for router in tgen.routers().values():
if router.has_version("<", "4"):
has_version_20 = True
if has_version_20:
logger.info("Skipping ISIS vrf tests for FRR 2.0")
tgen.set_error("ISIS has convergence problems with IPv6")
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
# move back rx-eth0 to default VRF
# delete rx-vrf
tgen.stop_topology()
def test_isis_convergence():
"Wait for the protocol to converge before starting to test"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("waiting for ISIS protocol to converge")
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
expected = json.loads(open(filename).read())
def compare_isis_topology(router, expected):
"Helper function to test ISIS vrf topology convergence."
actual = show_isis_topology(router)
return topotest.json_cmp(actual, expected)
test_func = functools.partial(compare_isis_topology, router, expected)
(result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120)
assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
def test_isis_route_installation():
"Check whether all expected routes are present"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf routes")
# Check for routes in 'show ip route vrf {}-cust1 json'
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
for network, routes in expected.iteritems():
for route in routes:
if route["protocol"] != "isis":
continue
for nexthop in route["nexthops"]:
nexthop.pop("interfaceIndex", None)
nexthop.pop("interfaceName", None)
assertmsg = "Router '{}' routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_linux_route_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf routes in OS")
# Check for routes in `ip route show vrf {}-cust1`
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip4_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
for network, netoptions in expected.iteritems():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
assertmsg = "Router '{}' OS routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_route6_installation():
"Check whether all expected routes are present"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf IPv6 routes")
# Check for routes in 'show ipv6 route vrf {}-cust1 json'
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
for network, routes in expected.iteritems():
for route in routes:
if route["protocol"] != "isis":
continue
for nexthop in route["nexthops"]:
nexthop.pop("interfaceIndex", None)
nexthop.pop("interfaceName", None)
assertmsg = "Router '{}' routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_linux_route6_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
# Check for routes in `ip -6 route show vrf {}-cust1`
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip6_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
for network, netoptions in expected.iteritems():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
assertmsg = "Router '{}' OS routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip("Memory leak test/report is disabled")
tgen.report_memory_leaks()
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
#
# Auxiliary functions
#
def dict_merge(dct, merge_dct):
"""
Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
updating only top-level keys, dict_merge recurses down into dicts nested
to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
``dct``.
:param dct: dict onto which the merge is executed
:param merge_dct: dct merged into dct
:return: None
Source:
https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
"""
for k, v in merge_dct.iteritems():
if (
k in dct
and isinstance(dct[k], dict)
and isinstance(merge_dct[k], collections.Mapping)
):
dict_merge(dct[k], merge_dct[k])
else:
dct[k] = merge_dct[k]
def parse_topology(lines, level):
"""
Parse the output of 'show isis topology level-X' into a Python dict.
"""
areas = {}
area = None
ipv = None
for line in lines:
area_match = re.match(r"Area (.+):", line)
if area_match:
area = area_match.group(1)
if area not in areas:
areas[area] = {level: {"ipv4": [], "ipv6": []}}
ipv = None
continue
elif area is None:
continue
if re.match(r"IS\-IS paths to level-. routers that speak IPv6", line):
ipv = "ipv6"
continue
if re.match(r"IS\-IS paths to level-. routers that speak IP", line):
ipv = "ipv4"
continue
item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
if item_match is not None:
# Skip header
if (
item_match.group(1) == "Vertex"
and item_match.group(2) == "Type"
and item_match.group(3) == "Metric"
and item_match.group(4) == "Next-Hop"
and item_match.group(5) == "Interface"
and item_match.group(6) == "Parent"
):
continue
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
"next-hop": item_match.group(4),
"interface": item_match.group(5),
"parent": item_match.group(6),
}
)
continue
item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
if item_match is not None:
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
"parent": item_match.group(4),
}
)
continue
item_match = re.match(r"([^ ]+)", line)
if item_match is not None:
areas[area][level][ipv].append({"vertex": item_match.group(1)})
continue
return areas
def show_isis_topology(router):
"""
Get the ISIS vrf topology in a dictionary format.
Sample:
{
'area-name': {
'level-1': [
{
'vertex': 'r1'
}
],
'level-2': [
{
'vertex': '10.0.0.1/24',
'type': 'IP',
'parent': '0',
'metric': 'internal'
}
]
},
'area-name-2': {
'level-2': [
{
"interface": "rX-ethY",
"metric": "Z",
"next-hop": "rA",
"parent": "rC(B)",
"type": "TE-IS",
"vertex": "rD"
}
]
}
}
"""
l1out = topotest.normalize_text(
router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name))
).splitlines()
l2out = topotest.normalize_text(
router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name))
).splitlines()
l1 = parse_topology(l1out, "level-1")
l2 = parse_topology(l2out, "level-2")
dict_merge(l1, l2)
return l1

View File

@ -720,6 +720,49 @@ def ip4_route(node):
return result return result
def ip4_vrf_route(node):
"""
Gets a structured return of the command 'ip route show vrf {0}-cust1'.
It can be used in conjuction with json_cmp() to provide accurate assert explanations.
Return example:
{
'10.0.1.0/24': {
'dev': 'eth0',
'via': '172.16.0.1',
'proto': '188',
},
'10.0.2.0/24': {
'dev': 'eth1',
'proto': 'kernel',
}
}
"""
output = normalize_text(
node.run("ip route show vrf {0}-cust1".format(node.name))).splitlines()
result = {}
for line in output:
columns = line.split(" ")
route = result[columns[0]] = {}
prev = None
for column in columns:
if prev == "dev":
route["dev"] = column
if prev == "via":
route["via"] = column
if prev == "proto":
# translate protocol names back to numbers
route["proto"] = proto_name_to_number(column)
if prev == "metric":
route["metric"] = column
if prev == "scope":
route["scope"] = column
prev = column
return result
def ip6_route(node): def ip6_route(node):
""" """
Gets a structured return of the command 'ip -6 route'. It can be used in Gets a structured return of the command 'ip -6 route'. It can be used in
@ -760,6 +803,47 @@ def ip6_route(node):
return result return result
def ip6_vrf_route(node):
"""
Gets a structured return of the command 'ip -6 route show vrf {0}-cust1'.
It can be used in conjuction with json_cmp() to provide accurate assert explanations.
Return example:
{
'2001:db8:1::/64': {
'dev': 'eth0',
'proto': '188',
},
'2001:db8:2::/64': {
'dev': 'eth1',
'proto': 'kernel',
}
}
"""
output = normalize_text(
node.run("ip -6 route show vrf {0}-cust1".format(node.name))).splitlines()
result = {}
for line in output:
columns = line.split(" ")
route = result[columns[0]] = {}
prev = None
for column in columns:
if prev == "dev":
route["dev"] = column
if prev == "via":
route["via"] = column
if prev == "proto":
# translate protocol names back to numbers
route["proto"] = proto_name_to_number(column)
if prev == "metric":
route["metric"] = column
if prev == "pref":
route["pref"] = column
prev = column
return result
def ip_rules(node): def ip_rules(node):
""" """
Gets a structured return of the command 'ip rule'. It can be used in Gets a structured return of the command 'ip rule'. It can be used in

View File

@ -1892,10 +1892,11 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
} }
#endif #endif
DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, "router isis WORD", DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
"router isis WORD [vrf NAME]",
ROUTER_STR ROUTER_STR
"ISO IS-IS\n" "ISO IS-IS\n"
"ISO Routing area tag\n") "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{ {
vty->node = ISIS_NODE; vty->node = ISIS_NODE;
return CMD_SUCCESS; return CMD_SUCCESS;

View File

@ -340,6 +340,13 @@ module frr-isisd {
"Area-tag associated to this circuit."; "Area-tag associated to this circuit.";
} }
leaf vrf {
type string;
default "default";
description
"VRF NAME.";
}
leaf ipv4-routing { leaf ipv4-routing {
type boolean; type boolean;
default "false"; default "false";
@ -793,7 +800,7 @@ module frr-isisd {
description description
"Configuration of the IS-IS routing daemon."; "Configuration of the IS-IS routing daemon.";
list instance { list instance {
key "area-tag"; key "area-tag vrf";
description description
"IS-IS routing instance."; "IS-IS routing instance.";
leaf area-tag { leaf area-tag {
@ -802,6 +809,12 @@ module frr-isisd {
"Area-tag associated to this routing instance."; "Area-tag associated to this routing instance.";
} }
leaf vrf {
type string;
description
"VRF NAME.";
}
leaf is-type { leaf is-type {
type level; type level;
default "level-1-2"; default "level-1-2";