doc, yang, isisd : Support for different VRF in isisd

1. Added isis with different vrf and it's dependecies.
2. Added new vrf leaf in yang.
3. A minor change for IF_DOWN_FROM_Z passing argrument is
   replaced with ifp pointer in api "isis_if_delete_hook()".
4. Minor fix in the isisd spf unit test.

Co-authored-by: Kaushik <kaushik@niralnetworks.com>"
Signed-off-by: harios_niral <hari@niralnetworks.com>
This commit is contained in:
harios_niral 2020-08-18 00:26:51 -07:00
parent 3fb5678572
commit 65251ce80f
15 changed files with 395 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,21 +1244,24 @@ 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;
struct interface *ifp;
struct lyd_node *dnode;
FOR_ALL_INTERFACES (vrf, ifp) { RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
dnode = yang_dnode_get( struct interface *ifp;
running_config->dnode,
"/frr-interface:lib/interface[name='%s'][vrf='%s']",
ifp->name, vrf->name);
if (dnode == NULL)
continue;
write++; FOR_ALL_INTERFACES (vrf, ifp) {
nb_cli_show_dnode_cmds(vty, dnode, false); 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; return write;
} }
@ -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_STR "router isis WORD$tag [vrf NAME$vrf_name]",
"ISO IS-IS\n" ROUTER_STR
"ISO Routing area tag\n") "ISO IS-IS\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_STR ROUTER_STR "no router isis WORD$tag [vrf NAME$vrf_name]",
"ISO IS-IS\n" NO_STR ROUTER_STR
"ISO Routing area tag\n") "ISO IS-IS\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,
"Interface Internet Protocol config commands\n" "ip router isis WORD$tag [vrf NAME$vrf_name]",
"IP router interface commands\n" "Interface Internet Protocol config commands\n"
"IS-IS routing protocol\n" "IP router interface commands\n"
"Routing process tag\n") "IS-IS routing protocol\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,
"Interface Internet Protocol config commands\n" "ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
"IP router interface commands\n" "Interface Internet Protocol config commands\n"
"IS-IS routing protocol\n" "IP router interface commands\n"
"Routing process tag\n") "IS-IS routing protocol\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,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, 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"
"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")
{ {
const struct lyd_node *dnode; 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, 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

@ -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";