summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/figures/nodes.dot2
-rw-r--r--doc/user/isisd.rst27
-rw-r--r--isisd/isis_circuit.c39
-rw-r--r--isisd/isis_cli.c160
-rw-r--r--isisd/isis_main.c5
-rw-r--r--isisd/isis_nb.c7
-rw-r--r--isisd/isis_nb.h1
-rw-r--r--isisd/isis_nb_config.c69
-rw-r--r--isisd/isis_zebra.c14
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c136
-rw-r--r--isisd/isisd.h9
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--vtysh/vtysh.c5
-rw-r--r--yang/frr-isisd.yang15
15 files changed, 395 insertions, 97 deletions
diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot
index b548b5529a..4ce147b2c4 100644
--- a/doc/figures/nodes.dot
+++ b/doc/figures/nodes.dot
@@ -47,7 +47,7 @@ digraph climodes {
CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ];
CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ];
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 -> PW_NODE [ label="pseudowire IFNAME" ];
CONFIG_NODE -> VTY_NODE [ label="line vty" ];
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 1155b49eb1..8cbbe0809f 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -33,8 +33,8 @@ ISIS router
To start the ISIS process you have to specify the ISIS router. As of this
writing, *isisd* does not support multiple ISIS processes.
-.. index:: [no] router isis WORD
-.. clicmd:: [no] router isis WORD
+.. index:: [no] router isis WORD [vrf NAME]
+.. clicmd:: [no] router isis WORD [vrf NAME]
Enable or disable the ISIS process by specifying the ISIS domain with
'WORD'. *isisd* does not yet support multiple ISIS processes but you must
@@ -202,8 +202,8 @@ ISIS interface
.. _ip-router-isis-word:
-.. index:: [no] <ip|ipv6> router isis WORD
-.. clicmd:: [no] <ip|ipv6> router isis WORD
+.. index:: [no] <ip|ipv6> router isis WORD [vrf NAME]
+.. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]
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
@@ -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
!
+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
+
+
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 985e07820f..1214c01a12 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1244,21 +1244,24 @@ static int isis_interface_config_write(struct vty *vty)
#else
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;
- struct interface *ifp;
- struct lyd_node *dnode;
- FOR_ALL_INTERFACES (vrf, ifp) {
- dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifp->name, vrf->name);
- if (dnode == NULL)
- continue;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct interface *ifp;
- write++;
- nb_cli_show_dnode_cmds(vty, dnode, false);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ struct lyd_node *dnode;
+ dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+ if (dnode == NULL)
+ continue;
+
+ write++;
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ }
}
return write;
}
@@ -1268,6 +1271,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
struct interface *ifp)
{
struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
+
if (circuit && circuit->area)
return NULL;
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 */
if (ifp && 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;
@@ -1454,10 +1458,15 @@ int isis_if_delete_hook(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),
ifp);
-
+ }
hook_call(isis_if_new_hook, ifp);
return 0;
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 4d02758003..31fe41db82 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -46,16 +46,21 @@
/*
* XPath: /frr-isisd:isis/instance
*/
-DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
- ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG_NOSH(router_isis, router_isis_cmd,
+ "router isis WORD$tag [vrf NAME$vrf_name]",
+ ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
int ret;
char base_xpath[XPATH_MAXLEN];
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
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);
/* default value in yang for is-type is level-1, but in FRR
* 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;
}
-DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
- NO_STR ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG(no_router_isis, no_router_isis_cmd,
+ "no router isis WORD$tag [vrf NAME$vrf_name]",
+ NO_STR ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
struct listnode *node, *nnode;
struct isis_circuit *circuit = NULL;
struct isis_area *area = NULL;
- if (!yang_dnode_exists(vty->candidate_config->dnode,
- "/frr-isisd:isis/instance[area-tag='%s']",
- tag)) {
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ 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);
return CMD_ERR_NOTHING_TODO;
}
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)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) {
@@ -114,15 +124,23 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
}
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,
bool show_defaults)
{
+ const char *vrf = NULL;
+
+ vrf = yang_dnode_get_string(dnode, "./vrf");
+
vty_out(vty, "!\n");
- vty_out(vty, "router isis %s\n",
+ vty_out(vty, "router isis %s ",
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-isisd:isis/instance
*/
-DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
+ "ip router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
struct isis_area *area = NULL;
struct interface *ifp;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* 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;
}
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) {
+ isis_global_instance_create(vrf_name);
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);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -167,6 +197,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-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_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -192,6 +225,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-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_OP_MODIFY, "true");
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);
}
-DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
+ "ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
- struct isis_area *area = NULL;
struct interface *ifp;
+ struct isis_area *area;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* 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;
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) {
+ isis_global_instance_create(vrf_name);
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);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -242,6 +289,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-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_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -267,6 +317,8 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-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_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@@ -282,13 +334,13 @@ 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,
- "no <ip|ipv6>$ip router isis [WORD]$tag",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+ "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n")
{
const struct lyd_node *dnode;
@@ -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,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
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"));
+ 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,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
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"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, "\n");
}
/*
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 6352303c23..26f5227aae 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -236,13 +236,12 @@ int main(int argc, char **argv, char **envp)
/* thread master */
isis_master_init(frr_init());
master = im->master;
-
/*
* initializations
*/
isis_error_init();
access_list_init();
- vrf_init(NULL, NULL, NULL, NULL, NULL);
+ isis_vrf_init();
prefix_list_init();
isis_init();
isis_circuit_init();
@@ -261,7 +260,7 @@ int main(int argc, char **argv, char **envp)
mt_init();
/* create the global 'isis' instance */
- isis_global_instance_create();
+ isis_global_instance_create(VRF_DEFAULT_NAME);
isis_zebra_init(master, instance);
isis_bfd_init();
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 2b8b02e3f1..33b0b4d02c 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -551,6 +551,13 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .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",
.cbs = {
.cli_show = cli_show_ip_isis_circ_type,
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index a9401bc86a..a79cb8ff57 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -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_destroy(struct nb_cb_destroy_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_ipv6_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args);
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index d722868414..170fe92c28 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -53,16 +53,19 @@ int isis_instance_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
const char *area_tag;
+ const char *vrf_name;
if (args->event != NB_EV_APPLY)
return NB_OK;
-
+ vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
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)
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 */
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)
return NB_OK;
-
area = nb_running_unset_entry(args->dnode);
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);
if (area == NULL)
return NB_ERR_VALIDATION;
-
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len);
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:
area = nb_running_get_entry(args->dnode, NULL, true);
addrr = args->resource->ptr;
+ assert(area);
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 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 *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
uint32_t min_mtu, actual_mtu;
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 */
if (!ifp || ifp->mtu == 0)
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 =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
+
area = isis_area_lookup(area_tag, ifp->vrf_id);
if (area)
min_mtu = area->lsp_mtu;
@@ -1866,9 +1879,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
}
break;
case NB_EV_APPLY:
- ifp = nb_running_get_entry(args->dnode, NULL, true);
- if (ifp)
- area = isis_area_lookup(area_tag, ifp->vrf_id);
+ area = isis_area_lookup_by_vrf(area_tag, vrf_name);
/* The area should have already be created. We are
* setting the priority of the global isis area creation
* 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);
abort();
}
-
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
circuit = isis_circuit_create(area, ifp);
assert(circuit
&& (circuit->state == C_STATE_CONF
@@ -1957,6 +1968,44 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
}
/*
+ * 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
*/
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 3aa21a9aed..a50eb607d9 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -577,6 +577,20 @@ int isis_zebra_label_manager_connect(void)
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)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 4449b63c2e..768919ff46 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -57,5 +57,6 @@ bool isis_zebra_label_manager_ready(void);
int isis_zebra_label_manager_connect(void);
int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
int isis_zebra_release_label_range(uint32_t start, uint32_t end);
+void isis_zebra_vrf_register(struct isis *isis);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index aca98bf651..2a2c71b1fd 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -35,6 +35,7 @@
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "zclient.h"
#include "vrf.h"
#include "spf_backoff.h"
#include "lib/northbound_cli.h"
@@ -167,29 +168,32 @@ void isis_master_init(struct thread_master *master)
im->master = master;
}
-void isis_global_instance_create()
+void isis_global_instance_create(const char *vrf_name)
{
struct isis *isis;
- isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ isis = isis_lookup_by_vrfname(vrf_name);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(vrf_name);
isis_add(isis);
}
}
-struct isis *isis_new(vrf_id_t vrf_id)
+struct isis *isis_new(const char *vrf_name)
{
struct vrf *vrf;
struct isis *isis;
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
- isis->vrf_id = vrf_id;
- vrf = vrf_lookup_by_id(vrf_id);
+ vrf = vrf_lookup_by_name(vrf_name);
if (vrf) {
+ isis->vrf_id = vrf->vrf_id;
isis_vrf_link(isis, vrf);
isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+ } else {
+ isis->vrf_id = VRF_UNKNOWN;
+ isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
}
if (IS_DEBUG_EVENTS)
@@ -223,15 +227,20 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
if (vrf) {
isis = isis_lookup_by_vrfid(vrf->vrf_id);
if (isis == NULL) {
- isis = isis_new(vrf->vrf_id);
+ isis = isis_new(vrf_name);
+ isis_add(isis);
+ }
+ } else {
+ isis = isis_lookup_by_vrfid(VRF_UNKNOWN);
+ if (isis == NULL) {
+ isis = isis_new(vrf_name);
isis_add(isis);
}
- } else
- return NULL;
+ }
} else {
isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
isis_add(isis);
}
}
@@ -336,6 +345,24 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
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 *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)
{
struct vrf *vrf = NULL;
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 0c0a1eed10..c26a62dfac 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -73,7 +73,6 @@ struct isis_master {
struct list *isis;
/* ISIS thread master. */
struct thread_master *master;
- /* Various OSPF global configuration. */
uint8_t options;
};
#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_vrf_link(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_vrfname(const char *vrfname);
struct isis *isis_lookup_by_sysid(const uint8_t *sysid);
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_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);
void isis_area_destroy(struct isis_area *area);
void print_debug(struct vty *, int, int);
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index dae906b956..73bb531dc0 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -291,7 +291,7 @@ int main(int argc, char **argv)
/* IS-IS inits. */
yang_module_load("frr-isisd");
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
listnode_add(im->isis, isis);
SET_FLAG(im->options, F_ISIS_UNIT_TEST);
debug_spf_events |= DEBUG_SPF_EVENTS;
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index d3fc8bc338..4edbb7a889 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1892,10 +1892,11 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
}
#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
"ISO IS-IS\n"
- "ISO Routing area tag\n")
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
vty->node = ISIS_NODE;
return CMD_SUCCESS;
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 1bb693a1ef..00296516ef 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -340,6 +340,13 @@ module frr-isisd {
"Area-tag associated to this circuit.";
}
+ leaf vrf {
+ type string;
+ default "default";
+ description
+ "VRF NAME.";
+ }
+
leaf ipv4-routing {
type boolean;
default "false";
@@ -793,7 +800,7 @@ module frr-isisd {
description
"Configuration of the IS-IS routing daemon.";
list instance {
- key "area-tag";
+ key "area-tag vrf";
description
"IS-IS routing instance.";
leaf area-tag {
@@ -802,6 +809,12 @@ module frr-isisd {
"Area-tag associated to this routing instance.";
}
+ leaf vrf {
+ type string;
+ description
+ "VRF NAME.";
+ }
+
leaf is-type {
type level;
default "level-1-2";