From aaf2fd21fc3a463496ef3377a63e892d733a403a Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Tue, 13 Nov 2018 17:19:10 +0100 Subject: [PATCH] isisd: retrofit 'router isis' and 'ip router isis' cmds These are complex commands to retrofit, partly due to the number of different callbacks they touch. Additionally, in FRR adding an interface to an IS-IS area that does not exist also creates that area. To make sure that this behavior is kept, while at the same time keeping the northbound api consistent, we need to take extra care to call the appropriate callbacks to update the YANG tree. Note that many callbacks rely on the existence of the corresponding IS-IS area; when these callbacks are joined together in a single transaction, we need to ensure that the area creation is performed first, or the config will fail. For this reason, the isis instance create callback has been given a slightly lower priority than the others. Signed-off-by: Emanuele Di Pascale --- isisd/isis_cli.c | 265 +++++++++++++++++++++++++++++++++++++++ isisd/isis_cli.h | 6 + isisd/isis_northbound.c | 205 ++++++++++++++++++++++++++++-- isisd/isis_vty_common.c | 107 ---------------- isisd/isis_vty_fabricd.c | 108 ++++++++++++++++ isisd/isisd.c | 35 +++--- isisd/isisd.h | 2 + 7 files changed, 594 insertions(+), 134 deletions(-) diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 9f82d8581..2650c5bcb 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -43,8 +43,273 @@ #ifndef FABRICD +/* + * XPath: /frr-isisd:isis/instance + */ +DEFPY_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag", + ROUTER_STR + "ISO IS-IS\n" + "ISO Routing area tag\n") +{ + int ret; + char base_xpath[XPATH_MAXLEN]; + + snprintf(base_xpath, XPATH_MAXLEN, + "/frr-isisd:isis/instance[area-tag='%s']", tag); + 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 + * need to make sure to set it in the yang model so that it + * is consistent with what FRR sees. + */ + if (listcount(isis->area_list) == 0) + nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, + "level-1-2"); + ret = nb_cli_apply_changes(vty, base_xpath); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(ISIS_NODE, base_xpath); + + return ret; +} + +DEFPY(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") +{ + char temp_xpath[XPATH_MAXLEN]; + struct listnode *node, *nnode; + struct isis_circuit *circuit = NULL; + struct isis_area *area = NULL; + + area = isis_area_lookup(tag); + if (!area) { + vty_out(vty, "ISIS area %s not found.\n", tag); + return CMD_ERR_NOTHING_TODO; + } + + nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + if (area->circuit_list && listcount(area->circuit_list)) { + for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode, + circuit)) { + /* add callbacks to delete each of the circuits listed + */ + const char *vrf_name = + vrf_lookup_by_id(circuit->interface->vrf_id) + ->name; + snprintf( + temp_xpath, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", + circuit->interface->name, vrf_name); + nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DELETE, + NULL); + } + } + + return nb_cli_apply_changes( + vty, "/frr-isisd:isis/instance[area-tag='%s']", tag); +} + +void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, "!\n"); + vty_out(vty, "router isis %s\n", + yang_dnode_get_string(dnode, "./area-tag")); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/ + * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv4-routing + * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing + * XPath: /frr-isisd:isis/instance + */ +DEFPY(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") +{ + char temp_xpath[XPATH_MAXLEN]; + const char *circ_type; + struct isis_area *area; + + /* area will be created if it is not present. make sure the yang model + * is synced with FRR and call the appropriate NB cb. + */ + area = isis_area_lookup(tag); + if (!area) { + snprintf(temp_xpath, XPATH_MAXLEN, + "/frr-isisd:isis/instance[area-tag='%s']", tag); + 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); + nb_cli_enqueue_change( + vty, temp_xpath, NB_OP_MODIFY, + listcount(isis->area_list) == 0 ? "level-1-2" : NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, + NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", + NB_OP_MODIFY, tag); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change( + vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY, + listcount(isis->area_list) == 0 ? "level-1-2" + : "level-1"); + } else { + /* area exists, circuit type defaults to its area's is_type */ + switch (area->is_type) { + case IS_LEVEL_1: + circ_type = "level-1"; + break; + case IS_LEVEL_2: + circ_type = "level-2"; + break; + case IS_LEVEL_1_AND_2: + circ_type = "level-1-2"; + break; + } + nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, + NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", + NB_OP_MODIFY, tag); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", + NB_OP_MODIFY, circ_type); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(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") +{ + char temp_xpath[XPATH_MAXLEN]; + const char *circ_type; + struct isis_area *area; + + /* area will be created if it is not present. make sure the yang model + * is synced with FRR and call the appropriate NB cb. + */ + area = isis_area_lookup(tag); + if (!area) { + snprintf(temp_xpath, XPATH_MAXLEN, + "/frr-isisd:isis/instance[area-tag='%s']", tag); + 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); + nb_cli_enqueue_change( + vty, temp_xpath, NB_OP_MODIFY, + listcount(isis->area_list) == 0 ? "level-1-2" : NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, + NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", + NB_OP_MODIFY, tag); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change( + vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY, + listcount(isis->area_list) == 0 ? "level-1-2" + : "level-1"); + } else { + /* area exists, circuit type defaults to its area's is_type */ + switch (area->is_type) { + case IS_LEVEL_1: + circ_type = "level-1"; + break; + case IS_LEVEL_2: + circ_type = "level-2"; + break; + case IS_LEVEL_1_AND_2: + circ_type = "level-1-2"; + break; + } + nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, + NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", + NB_OP_MODIFY, tag); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", + NB_OP_MODIFY, circ_type); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, + "no $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") +{ + const struct lyd_node *dnode = + yang_dnode_get(running_config->dnode, VTY_CURR_XPATH); + struct interface *ifp; + struct isis_circuit *circuit = NULL; + + /* check for the existance of a circuit */ + if (dnode) { + ifp = yang_dnode_get_entry(dnode, false); + if (ifp) + circuit = circuit_scan_by_ifp(ifp); + } + + /* if both ipv4 and ipv6 are off delete the interface isis container too + */ + if (!strncmp(ip, "ipv6", strlen("ipv6"))) { + if (circuit && !circuit->ip_router) + nb_cli_enqueue_change(vty, "./frr-isisd:isis", + NB_OP_DELETE, NULL); + else + nb_cli_enqueue_change(vty, + "./frr-isisd:isis/ipv6-routing", + NB_OP_DELETE, NULL); + } else { /* no ipv4 */ + if (circuit && !circuit->ipv6_router) + nb_cli_enqueue_change(vty, "./frr-isisd:isis", + NB_OP_DELETE, NULL); + else + nb_cli_enqueue_change(vty, + "./frr-isisd:isis/ipv4-routing", + NB_OP_DELETE, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " ip router isis %s\n", + yang_dnode_get_string(dnode, "../area-tag")); +} + +void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " ipv6 router isis %s\n", + yang_dnode_get_string(dnode, "../area-tag")); +} + void isis_cli_init(void) { + install_element(CONFIG_NODE, &router_isis_cmd); + install_element(CONFIG_NODE, &no_router_isis_cmd); + + install_element(INTERFACE_NODE, &ip_router_isis_cmd); + install_element(INTERFACE_NODE, &ip6_router_isis_cmd); + install_element(INTERFACE_NODE, &no_ip_router_isis_cmd); } #endif /* ifndef FABRICD */ diff --git a/isisd/isis_cli.h b/isisd/isis_cli.h index 952bd9d74..e98608759 100644 --- a/isisd/isis_cli.h +++ b/isisd/isis_cli.h @@ -21,5 +21,11 @@ #define ISISD_ISIS_CLI_H_ /* add cli_show declarations here as externs */ +void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); #endif /* ISISD_ISIS_CLI_H_ */ diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 23c4fec4f..711451234 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -54,14 +54,35 @@ static int isis_instance_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + struct isis_area *area; + const char *area_tag; + + if (event != NB_EV_APPLY) + return NB_OK; + + area_tag = yang_dnode_get_string(dnode, "./area-tag"); + area = isis_area_lookup(area_tag); + if (area) + return NB_ERR_INCONSISTENCY; + + area = isis_area_create(area_tag); + /* save area in dnode to avoid looking it up all the time */ + yang_dnode_set_entry(dnode, area); + return NB_OK; } static int isis_instance_delete(enum nb_event event, const struct lyd_node *dnode) { - /* TODO: implement me. */ + const char *area_tag; + + if (event != NB_EV_APPLY) + return NB_OK; + + area_tag = yang_dnode_get_string(dnode, "./area-tag"); + isis_area_destroy(area_tag); + return NB_OK; } @@ -72,7 +93,16 @@ static int isis_instance_is_type_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + struct isis_area *area; + int type; + + if (event != NB_EV_APPLY) + return NB_OK; + + area = yang_dnode_get_entry(dnode, true); + type = yang_dnode_get_enum(dnode, NULL); + isis_area_is_type_set(area, type); + return NB_OK; } @@ -1003,14 +1033,63 @@ static int lib_interface_isis_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + struct isis_area *area; + struct interface *ifp; + struct isis_circuit *circuit; + const char *area_tag = yang_dnode_get_string(dnode, "./area-tag"); + + if (event != NB_EV_APPLY) + return NB_OK; + + area = isis_area_lookup(area_tag); + /* 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 + * cannot rely on that so here I have to check. + */ + if (!area) { + flog_err( + EC_LIB_NB_CB_CONFIG_APPLY, + "%s: attempt to create circuit for area %s before the area has been created", + __func__, area_tag); + abort(); + } + + ifp = yang_dnode_get_entry(dnode, true); + circuit = isis_circuit_create(area, ifp); + assert(circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP); + yang_dnode_set_entry(dnode, circuit); + return NB_OK; } static int lib_interface_isis_delete(enum nb_event event, const struct lyd_node *dnode) { - /* TODO: implement me. */ + struct isis_circuit *circuit; + + if (event != NB_EV_APPLY) + return NB_OK; + + circuit = yang_dnode_get_entry(dnode, true); + if (!circuit) + return NB_ERR_INCONSISTENCY; + /* delete circuit through csm changes */ + switch (circuit->state) { + case C_STATE_UP: + isis_csm_state_change(IF_DOWN_FROM_Z, circuit, + circuit->interface); + isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area); + break; + case C_STATE_CONF: + isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area); + break; + case C_STATE_INIT: + isis_csm_state_change(IF_DOWN_FROM_Z, circuit, + circuit->interface); + break; + } + return NB_OK; } @@ -1021,7 +1100,32 @@ static int lib_interface_isis_area_tag_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + struct isis_circuit *circuit; + struct interface *ifp; + struct vrf *vrf; + const char *area_tag, *ifname, *vrfname; + + if (event == NB_EV_VALIDATE) { + /* libyang doesn't like relative paths across module boundaries + */ + ifname = yang_dnode_get_string(dnode->parent->parent, "./name"); + vrfname = yang_dnode_get_string(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; + circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list); + area_tag = yang_dnode_get_string(dnode, NULL); + if (circuit && circuit->area && circuit->area->area_tag + && strcmp(circuit->area->area_tag, area_tag)) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "ISIS circuit is already defined on %s", + circuit->area->area_tag); + return NB_ERR_VALIDATION; + } + } + return NB_OK; } @@ -1032,7 +1136,42 @@ static int lib_interface_isis_circuit_type_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + int circ_type = yang_dnode_get_enum(dnode, NULL); + struct isis_circuit *circuit; + struct interface *ifp; + struct vrf *vrf; + const char *ifname, *vrfname; + + switch (event) { + case NB_EV_VALIDATE: + /* libyang doesn't like relative paths across module boundaries + */ + ifname = yang_dnode_get_string(dnode->parent->parent, "./name"); + vrfname = yang_dnode_get_string(dnode->parent->parent, "./vrf"); + vrf = vrf_lookup_by_name(vrfname); + assert(vrf); + ifp = if_lookup_by_name(ifname, vrf->vrf_id); + if (!ifp) + break; + circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list); + if (circuit && circuit->state == C_STATE_UP + && circuit->area->is_type != IS_LEVEL_1_AND_2 + && circuit->area->is_type != circ_type) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "Invalid circuit level for area %s", + circuit->area->area_tag); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + circuit = yang_dnode_get_entry(dnode, true); + isis_circuit_is_type_set(circuit, circ_type); + break; + } + return NB_OK; } @@ -1043,14 +1182,34 @@ static int lib_interface_isis_ipv4_routing_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + bool ipv6; + struct isis_circuit *circuit; + + if (event != NB_EV_APPLY) + return NB_OK; + + circuit = yang_dnode_get_entry(dnode, true); + ipv6 = yang_dnode_exists(dnode, "../ipv6-routing"); + isis_circuit_af_set(circuit, true, ipv6); + return NB_OK; } static int lib_interface_isis_ipv4_routing_delete(enum nb_event event, const struct lyd_node *dnode) { - /* TODO: implement me. */ + bool ipv6; + struct isis_circuit *circuit; + + if (event != NB_EV_APPLY) + return NB_OK; + + circuit = yang_dnode_get_entry(dnode, true); + if (circuit && circuit->area) { + ipv6 = yang_dnode_exists(dnode, "../ipv6-routing"); + isis_circuit_af_set(circuit, false, ipv6); + } + return NB_OK; } @@ -1061,14 +1220,34 @@ static int lib_interface_isis_ipv6_routing_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { - /* TODO: implement me. */ + bool ipv4; + struct isis_circuit *circuit; + + if (event != NB_EV_APPLY) + return NB_OK; + + circuit = yang_dnode_get_entry(dnode, true); + ipv4 = yang_dnode_exists(dnode, "../ipv6-routing"); + isis_circuit_af_set(circuit, ipv4, true); + return NB_OK; } static int lib_interface_isis_ipv6_routing_delete(enum nb_event event, const struct lyd_node *dnode) { - /* TODO: implement me. */ + bool ipv4; + struct isis_circuit *circuit; + + if (event != NB_EV_APPLY) + return NB_OK; + + circuit = yang_dnode_get_entry(dnode, true); + if (circuit->area) { + ipv4 = yang_dnode_exists(dnode, "../ipv4-routing"); + isis_circuit_af_set(circuit, ipv4, false); + } + return NB_OK; } @@ -1415,6 +1594,8 @@ const struct frr_yang_module_info frr_isisd_info = { .xpath = "/frr-isisd:isis/instance", .cbs.create = isis_instance_create, .cbs.delete = isis_instance_delete, + .cbs.cli_show = cli_show_router_isis, + .priority = NB_DFLT_PRIORITY - 1, }, { .xpath = "/frr-isisd:isis/instance/is-type", @@ -1705,11 +1886,13 @@ const struct frr_yang_module_info frr_isisd_info = { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv4-routing", .cbs.create = lib_interface_isis_ipv4_routing_create, .cbs.delete = lib_interface_isis_ipv4_routing_delete, + .cbs.cli_show = cli_show_ip_isis_ipv4, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv6-routing", .cbs.create = lib_interface_isis_ipv6_routing_create, .cbs.delete = lib_interface_isis_ipv6_routing_delete, + .cbs.cli_show = cli_show_ip_isis_ipv6, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1", diff --git a/isisd/isis_vty_common.c b/isisd/isis_vty_common.c index c21176304..f5ca9c1dd 100644 --- a/isisd/isis_vty_common.c +++ b/isisd/isis_vty_common.c @@ -57,109 +57,6 @@ struct isis_circuit *isis_circuit_lookup(struct vty *vty) return circuit; } -DEFUN (ip_router_isis, - ip_router_isis_cmd, - "ip router " PROTO_NAME " WORD", - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - PROTO_HELP - "Routing process tag\n") -{ - int idx_afi = 0; - int idx_word = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct isis_circuit *circuit; - struct isis_area *area; - const char *af = argv[idx_afi]->arg; - const char *area_tag = argv[idx_word]->arg; - - /* Prevent more than one area per circuit */ - circuit = circuit_scan_by_ifp(ifp); - if (circuit && circuit->area) { - if (strcmp(circuit->area->area_tag, area_tag)) { - vty_out(vty, "ISIS circuit is already defined on %s\n", - circuit->area->area_tag); - return CMD_ERR_NOTHING_TODO; - } - } - - area = isis_area_lookup(area_tag); - if (!area) - area = isis_area_create(area_tag); - - if (!circuit || !circuit->area) { - circuit = isis_circuit_create(area, ifp); - - if (circuit->state != C_STATE_CONF - && circuit->state != C_STATE_UP) { - vty_out(vty, - "Couldn't bring up interface, please check log.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; - if (af[2] != '\0') - ipv6 = true; - else - ip = true; - - isis_circuit_af_set(circuit, ip, ipv6); - return CMD_SUCCESS; -} - -DEFUN (ip6_router_isis, - ip6_router_isis_cmd, - "ipv6 router " PROTO_NAME " WORD", - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - PROTO_HELP - "Routing process tag\n") -{ - return ip_router_isis(self, vty, argc, argv); -} - -DEFUN (no_ip_router_isis, - no_ip_router_isis_cmd, - "no router " PROTO_NAME " WORD", - NO_STR - "Interface Internet Protocol config commands\n" - "IP router interface commands\n" - "IP router interface commands\n" - PROTO_HELP - "Routing process tag\n") -{ - int idx_afi = 1; - int idx_word = 4; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct isis_area *area; - struct isis_circuit *circuit; - const char *af = argv[idx_afi]->arg; - const char *area_tag = argv[idx_word]->arg; - - area = isis_area_lookup(area_tag); - if (!area) { - vty_out(vty, "Can't find ISIS instance %s\n", - area_tag); - return CMD_ERR_NO_MATCH; - } - - circuit = circuit_lookup_by_ifp(ifp, area->circuit_list); - if (!circuit) { - vty_out(vty, "ISIS is not enabled on circuit %s\n", ifp->name); - return CMD_ERR_NO_MATCH; - } - - bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; - if (af[2] != '\0') - ipv6 = false; - else - ip = false; - - isis_circuit_af_set(circuit, ip, ipv6); - return CMD_SUCCESS; -} - DEFUN (isis_passive, isis_passive_cmd, PROTO_NAME " passive", @@ -947,10 +844,6 @@ DEFUN (no_domain_passwd, void isis_vty_init(void) { - install_element(INTERFACE_NODE, &ip_router_isis_cmd); - install_element(INTERFACE_NODE, &ip6_router_isis_cmd); - install_element(INTERFACE_NODE, &no_ip_router_isis_cmd); - install_element(INTERFACE_NODE, &isis_passive_cmd); install_element(INTERFACE_NODE, &no_isis_passive_cmd); diff --git a/isisd/isis_vty_fabricd.c b/isisd/isis_vty_fabricd.c index aa48fe1d3..819b61dc7 100644 --- a/isisd/isis_vty_fabricd.c +++ b/isisd/isis_vty_fabricd.c @@ -29,6 +29,7 @@ #include "isisd/isis_tlvs.h" #include "isisd/isis_misc.h" #include "isisd/isis_lsp.h" +#include "isisd/isis_csm.h" DEFUN (fabric_tier, fabric_tier_cmd, @@ -181,6 +182,109 @@ DEFUN (show_lsp_flooding, return CMD_SUCCESS; } +DEFUN (ip_router_isis, + ip_router_isis_cmd, + "ip router " PROTO_NAME " WORD", + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + PROTO_HELP + "Routing process tag\n") +{ + int idx_afi = 0; + int idx_word = 3; + VTY_DECLVAR_CONTEXT(interface, ifp); + struct isis_circuit *circuit; + struct isis_area *area; + const char *af = argv[idx_afi]->arg; + const char *area_tag = argv[idx_word]->arg; + + /* Prevent more than one area per circuit */ + circuit = circuit_scan_by_ifp(ifp); + if (circuit && circuit->area) { + if (strcmp(circuit->area->area_tag, area_tag)) { + vty_out(vty, "ISIS circuit is already defined on %s\n", + circuit->area->area_tag); + return CMD_ERR_NOTHING_TODO; + } + } + + area = isis_area_lookup(area_tag); + if (!area) + area = isis_area_create(area_tag); + + if (!circuit || !circuit->area) { + circuit = isis_circuit_create(area, ifp); + + if (circuit->state != C_STATE_CONF + && circuit->state != C_STATE_UP) { + vty_out(vty, + "Couldn't bring up interface, please check log.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = true; + else + ip = true; + + isis_circuit_af_set(circuit, ip, ipv6); + return CMD_SUCCESS; +} + +DEFUN (ip6_router_isis, + ip6_router_isis_cmd, + "ipv6 router " PROTO_NAME " WORD", + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + PROTO_HELP + "Routing process tag\n") +{ + return ip_router_isis(self, vty, argc, argv); +} + +DEFUN (no_ip_router_isis, + no_ip_router_isis_cmd, + "no router " PROTO_NAME " WORD", + NO_STR + "Interface Internet Protocol config commands\n" + "IP router interface commands\n" + "IP router interface commands\n" + PROTO_HELP + "Routing process tag\n") +{ + int idx_afi = 1; + int idx_word = 4; + VTY_DECLVAR_CONTEXT(interface, ifp); + struct isis_area *area; + struct isis_circuit *circuit; + const char *af = argv[idx_afi]->arg; + const char *area_tag = argv[idx_word]->arg; + + area = isis_area_lookup(area_tag); + if (!area) { + vty_out(vty, "Can't find ISIS instance %s\n", + area_tag); + return CMD_ERR_NO_MATCH; + } + + circuit = circuit_lookup_by_ifp(ifp, area->circuit_list); + if (!circuit) { + vty_out(vty, "ISIS is not enabled on circuit %s\n", ifp->name); + return CMD_ERR_NO_MATCH; + } + + bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; + if (af[2] != '\0') + ipv6 = false; + else + ip = false; + + isis_circuit_af_set(circuit, ip, ipv6); + return CMD_SUCCESS; +} + void isis_vty_daemon_init(void) { install_element(ROUTER_NODE, &fabric_tier_cmd); @@ -189,4 +293,8 @@ void isis_vty_daemon_init(void) install_element(ROUTER_NODE, &no_triggered_csnp_cmd); install_element(ENABLE_NODE, &show_lsp_flooding_cmd); + + install_element(INTERFACE_NODE, &ip_router_isis_cmd); + install_element(INTERFACE_NODE, &ip6_router_isis_cmd); + install_element(INTERFACE_NODE, &no_ip_router_isis_cmd); } diff --git a/isisd/isisd.c b/isisd/isisd.c index 0e496193a..3721dff3b 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -36,6 +36,7 @@ #include "table.h" #include "qobj.h" #include "spf_backoff.h" +#include "lib/northbound_cli.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -67,7 +68,6 @@ DEFINE_QOBJ_TYPE(isis_area) * Prototypes. */ int isis_area_get(struct vty *, const char *); -int isis_area_destroy(struct vty *, const char *); int area_net_title(struct vty *, const char *); int area_clear_net_title(struct vty *, const char *); int show_isis_interface_common(struct vty *, const char *ifname, char); @@ -207,7 +207,7 @@ int isis_area_get(struct vty *vty, const char *area_tag) return CMD_SUCCESS; } -int isis_area_destroy(struct vty *vty, const char *area_tag) +int isis_area_destroy(const char *area_tag) { struct isis_area *area; struct listnode *node, *nnode; @@ -217,7 +217,8 @@ int isis_area_destroy(struct vty *vty, const char *area_tag) area = isis_area_lookup(area_tag); if (area == NULL) { - vty_out(vty, "Can't find ISIS instance \n"); + zlog_warn("%s: could not find area with area-tag %s", + __func__, area_tag); return CMD_ERR_NO_MATCH; } @@ -1452,12 +1453,13 @@ DEFUN (show_database, return show_isis_database(vty, id, uilevel); } +#ifdef FABRICD /* - * 'router isis' command + * 'router openfabric' command */ -DEFUN_NOSH (router_isis, - router_isis_cmd, - "router " PROTO_NAME " WORD", +DEFUN_NOSH (router_openfabric, + router_openfabric_cmd, + "router openfabric WORD", ROUTER_STR PROTO_HELP "ISO Routing area tag\n") @@ -1467,20 +1469,20 @@ DEFUN_NOSH (router_isis, } /* - *'no router isis' command + *'no router openfabric' command */ -DEFUN (no_router_isis, - no_router_isis_cmd, - "no router " PROTO_NAME " WORD", +DEFUN (no_router_openfabric, + no_router_openfabric_cmd, + "no router openfabric WORD", NO_STR ROUTER_STR PROTO_HELP "ISO Routing area tag\n") { int idx_word = 3; - return isis_area_destroy(vty, argv[idx_word]->arg); + return isis_area_destroy(argv[idx_word]->arg); } - +#endif /* ifdef FABRICD */ /* * 'net' command */ @@ -2179,11 +2181,12 @@ void isis_init() install_element(CONFIG_NODE, &debug_isis_bfd_cmd); install_element(CONFIG_NODE, &no_debug_isis_bfd_cmd); - install_element(CONFIG_NODE, &router_isis_cmd); - install_element(CONFIG_NODE, &no_router_isis_cmd); - install_default(ROUTER_NODE); +#ifdef FABRICD + install_element(CONFIG_NODE, &router_openfabric_cmd); + install_element(CONFIG_NODE, &no_router_openfabric_cmd); +#endif /* ifdef FABRICD */ install_element(ROUTER_NODE, &net_cmd); install_element(ROUTER_NODE, &no_net_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 14677ac7a..8447a309b 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -29,6 +29,7 @@ #include "isisd/isis_common.h" #include "isisd/isis_redist.h" #include "isisd/isis_pdu_counter.h" +#include "isisd/isis_circuit.h" #include "isis_flags.h" #include "dict.h" #include "isis_memory.h" @@ -185,6 +186,7 @@ void isis_new(unsigned long); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup(const char *); int isis_area_get(struct vty *vty, const char *area_tag); +int isis_area_destroy(const char *area_tag); void print_debug(struct vty *, int, int); struct isis_lsp *lsp_for_arg(const char *argv, dict_t *lspdb); -- 2.39.5