diff options
Diffstat (limited to '')
-rw-r--r-- | pathd/path_cli.c | 1344 |
1 files changed, 1344 insertions, 0 deletions
diff --git a/pathd/path_cli.c b/pathd/path_cli.c new file mode 100644 index 0000000..4775aa3 --- /dev/null +++ b/pathd/path_cli.c @@ -0,0 +1,1344 @@ +/* + * Copyright (C) 2020 NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include <float.h> +#include <math.h> +#include <zebra.h> + +#include "memory.h" +#include "log.h" +#include "command.h" +#include "mpls.h" +#include "northbound_cli.h" +#include "termtable.h" + +#include "pathd/pathd.h" +#include "pathd/path_nb.h" +#ifndef VTYSH_EXTRACT_PL +#include "pathd/path_cli_clippy.c" +#endif +#include "pathd/path_ted.h" + +#define XPATH_MAXATTRSIZE 64 +#define XPATH_MAXKEYSIZE 42 +#define XPATH_POLICY_BASELEN 100 +#define XPATH_POLICY_MAXLEN (XPATH_POLICY_BASELEN + XPATH_MAXATTRSIZE) +#define XPATH_CANDIDATE_BASELEN (XPATH_POLICY_BASELEN + XPATH_MAXKEYSIZE) +#define XPATH_CANDIDATE_MAXLEN (XPATH_CANDIDATE_BASELEN + XPATH_MAXATTRSIZE) + + +static int config_write_segment_routing(struct vty *vty); +static int segment_list_has_src_dst( + struct vty *vty, char *xpath, long index, const char *index_str, + struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, + struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, + const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, + const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str); +static int segment_list_has_prefix( + struct vty *vty, char *xpath, long index, const char *index_str, + const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, + const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, + const char *has_algo, long algo, const char *algo_str, + const char *has_iface_id, long iface_id, const char *iface_id_str); + +DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client"); + +DEFINE_HOOK(pathd_srte_config_write, (struct vty *vty), (vty)); + +/* Vty node structures. */ +static struct cmd_node segment_routing_node = { + .name = "segment-routing", + .node = SEGMENT_ROUTING_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-sr)# ", + .config_write = config_write_segment_routing, +}; + +static struct cmd_node sr_traffic_eng_node = { + .name = "sr traffic-eng", + .node = SR_TRAFFIC_ENG_NODE, + .parent_node = SEGMENT_ROUTING_NODE, + .prompt = "%s(config-sr-te)# ", +}; + +static struct cmd_node srte_segment_list_node = { + .name = "srte segment-list", + .node = SR_SEGMENT_LIST_NODE, + .parent_node = SR_TRAFFIC_ENG_NODE, + .prompt = "%s(config-sr-te-segment-list)# ", +}; + +static struct cmd_node srte_policy_node = { + .name = "srte policy", + .node = SR_POLICY_NODE, + .parent_node = SR_TRAFFIC_ENG_NODE, + .prompt = "%s(config-sr-te-policy)# ", +}; + +static struct cmd_node srte_candidate_dyn_node = { + .name = "srte candidate-dyn", + .node = SR_CANDIDATE_DYN_NODE, + .parent_node = SR_POLICY_NODE, + .prompt = "%s(config-sr-te-candidate)# ", +}; + + +/* + * Show SR-TE info + */ +DEFPY(show_srte_policy, + show_srte_policy_cmd, + "show sr-te policy", + SHOW_STR + "SR-TE info\n" + "SR-TE Policy\n") +{ + struct ttable *tt; + struct srte_policy *policy; + char *table; + + if (RB_EMPTY(srte_policy_head, &srte_policies)) { + vty_out(vty, "No SR Policies to display.\n\n"); + return CMD_SUCCESS; + } + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); + + RB_FOREACH (policy, srte_policy_head, &srte_policies) { + char endpoint[46]; + char binding_sid[16] = "-"; + + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); + if (policy->binding_sid != MPLS_LABEL_NONE) + snprintf(binding_sid, sizeof(binding_sid), "%u", + policy->binding_sid); + + ttable_add_row(tt, "%s|%u|%s|%s|%s", endpoint, policy->color, + policy->name, binding_sid, + policy->status == SRTE_POLICY_STATUS_UP + ? "Active" + : "Inactive"); + } + + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + + ttable_del(tt); + + return CMD_SUCCESS; +} + + +/* + * Show detailed SR-TE info + */ +DEFPY(show_srte_policy_detail, + show_srte_policy_detail_cmd, + "show sr-te policy detail", + SHOW_STR + "SR-TE info\n" + "SR-TE Policy\n" + "Show a detailed summary\n") +{ + struct srte_policy *policy; + + if (RB_EMPTY(srte_policy_head, &srte_policies)) { + vty_out(vty, "No SR Policies to display.\n\n"); + return CMD_SUCCESS; + } + + vty_out(vty, "\n"); + RB_FOREACH (policy, srte_policy_head, &srte_policies) { + struct srte_candidate *candidate; + char endpoint[46]; + char binding_sid[16] = "-"; + char *segment_list_info; + static char undefined_info[] = "(undefined)"; + static char created_by_pce_info[] = "(created by PCE)"; + + + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); + if (policy->binding_sid != MPLS_LABEL_NONE) + snprintf(binding_sid, sizeof(binding_sid), "%u", + policy->binding_sid); + vty_out(vty, + "Endpoint: %s Color: %u Name: %s BSID: %s Status: %s\n", + endpoint, policy->color, policy->name, binding_sid, + policy->status == SRTE_POLICY_STATUS_UP ? "Active" + : "Inactive"); + + RB_FOREACH (candidate, srte_candidate_head, + &policy->candidate_paths) { + struct srte_segment_list *segment_list; + + segment_list = candidate->lsp->segment_list; + if (segment_list == NULL) + segment_list_info = undefined_info; + else if (segment_list->protocol_origin + == SRTE_ORIGIN_PCEP) + segment_list_info = created_by_pce_info; + else + segment_list_info = + candidate->lsp->segment_list->name; + + vty_out(vty, + " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n", + CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST) + ? "*" + : " ", + candidate->preference, candidate->name, + candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT + ? "explicit" + : "dynamic", + segment_list_info, + srte_origin2str( + candidate->lsp->protocol_origin)); + } + + vty_out(vty, "\n"); + } + + return CMD_SUCCESS; +} + +DEFPY_NOSH( + segment_routing_list, + segment_routing_cmd, + "segment-routing", + "Configure segment routing\n") +{ + VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE); + return CMD_SUCCESS; +} + +DEFPY_NOSH( + sr_traffic_eng_list, + sr_traffic_eng_cmd, + "traffic-eng", + "Configure SR traffic engineering\n") +{ + VTY_PUSH_CONTEXT_NULL(SR_TRAFFIC_ENG_NODE); + return CMD_SUCCESS; +} + +/* + * XPath: /frr-pathd:pathd/srte/segment-list + */ +DEFPY_NOSH( + srte_segment_list, + srte_segment_list_cmd, + "segment-list WORD$name", + "Segment List\n" + "Segment List Name\n") +{ + char xpath[XPATH_MAXLEN]; + int ret; + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/segment-list[name='%s']", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/segment-list[name='%s']/protocol-origin", + name); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "local"); + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/segment-list[name='%s']/originator", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "config"); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) { + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/segment-list[name='%s']", name); + VTY_PUSH_XPATH(SR_SEGMENT_LIST_NODE, xpath); + } + + return ret; +} + +DEFPY(srte_no_segment_list, + srte_no_segment_list_cmd, + "no segment-list WORD$name", + NO_STR + "Segment List\n" + "Segment List Name\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/segment-list[name='%s']", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " segment-list %s\n", + yang_dnode_get_string(dnode, "./name")); +} + +void cli_show_srte_segment_list_end(struct vty *vty, + const struct lyd_node *dnode) +{ + vty_out(vty, " exit\n"); +} + +static int segment_list_has_src_dst( + struct vty *vty, char *xpath, long index, const char *index_str, + struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, + struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, + const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, + const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str) +{ + const char *node_src_id; + uint32_t ted_sid = MPLS_LABEL_NONE; + + struct ipaddr ip_src = {}; + struct ipaddr ip_dst = {}; + if (adj_src_ipv4_str != NULL) { + ip_src.ipa_type = IPADDR_V4; + ip_src.ip._v4_addr = adj_src_ipv4; + ip_dst.ipa_type = IPADDR_V4; + ip_dst.ip._v4_addr = adj_dst_ipv4; + } else if (adj_src_ipv6_str != NULL) { + ip_src.ipa_type = IPADDR_V6; + ip_src.ip._v6_addr = adj_src_ipv6; + ip_dst.ipa_type = IPADDR_V6; + ip_dst.ip._v6_addr = adj_dst_ipv6; + } else { + return CMD_ERR_NO_MATCH; + } + ted_sid = path_ted_query_type_f(&ip_src, &ip_dst); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_warn( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_f SRC (%pIA) DST (%pIA)!", + __func__, &ip_src, &ip_dst); + } + /* type */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", + index_str); + if (adj_src_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_adjacency"); + node_src_id = adj_src_ipv4_str; + } else if (adj_src_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_adjacency"); + node_src_id = adj_src_ipv6_str; + } else { + /* + * This is just to make the compiler happy about + * node_src_id not being initialized. This + * should never happen unless we change the cli + * function. + */ + assert(!"We must have a adj_src_ipv4_str or a adj_src_ipv6_str"); + } + + /* addresses */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_src_id); + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/remote-address", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + adj_dst_ipv4_str ? adj_dst_ipv4_str + : adj_dst_ipv6_str); + return CMD_SUCCESS; +} +int segment_list_has_prefix( + struct vty *vty, char *xpath, long index, const char *index_str, + const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, + const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, + const char *has_algo, long algo, const char *algo_str, + const char *has_iface_id, long iface_id, const char *iface_id_str) +{ + char buf_prefix[INET6_ADDRSTRLEN]; + + uint32_t ted_sid = MPLS_LABEL_NONE; + struct prefix prefix_cli = {}; + struct ipaddr pre_ipaddr = {}; + /* prefix with algorithm or local interface id */ + /* Type */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", + index_str); + if (has_iface_id != NULL) { + if (prefix_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_local_iface"); + } else if (prefix_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_local_iface"); + } else { + return CMD_ERR_NO_MATCH; + } + } else { + if (prefix_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_algo"); + } else if (prefix_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_algo"); + } else { + return CMD_ERR_NO_MATCH; + } + } + /* Prefix */ + if (prefix_ipv4_str != NULL) { + if (!str2prefix(prefix_ipv4_str, &prefix_cli)) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + inet_ntop(AF_INET, &prefix_cli.u.prefix4, buf_prefix, + sizeof(buf_prefix)); + pre_ipaddr.ipa_type = IPADDR_V4; + pre_ipaddr.ip._v4_addr = prefix_cli.u.prefix4; + } else if (prefix_ipv6_str != NULL) { + if (!str2prefix(prefix_ipv6_str, &prefix_cli)) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + inet_ntop(AF_INET6, &prefix_cli.u.prefix6, buf_prefix, + sizeof(buf_prefix)); + pre_ipaddr.ipa_type = IPADDR_V6; + pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6; + } + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, buf_prefix); + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/local-prefix-len", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + prefix_ipv4_str + ? strchr(prefix_ipv4_str, '/') + 1 + : strchr(prefix_ipv6_str, '/') + 1); + /* Alg / Iface */ + if (has_algo != NULL) { + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/algorithm", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, algo_str); + } else { + if (has_iface_id != NULL) { + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/local-interface", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + iface_id_str); + } + } + if (has_algo != NULL) { + ted_sid = path_ted_query_type_c(&prefix_cli, algo); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_err( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_c PREFIX (%pIA/%d) ALGO (%ld) sid:(%d)!", + __func__, &pre_ipaddr, prefix_cli.prefixlen, + algo, ted_sid); + } + } + if (has_iface_id != NULL) { + ted_sid = path_ted_query_type_e(&prefix_cli, iface_id); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_err( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_e PREFIX (%pIA/%d) IFACE (%ld) sid:(%d)!", + __func__, &pre_ipaddr, prefix_cli.prefixlen, + iface_id, ted_sid); + } + } + return CMD_SUCCESS; +} +/* + * XPath: /frr-pathd:pathd/srte/segment-list/segment + */ +/* clang-format off */ +DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, + "index (0-4294967295)$index <[mpls$has_mpls_label label (16-1048575)$label] " + "|" + "[nai$has_nai <" + "prefix <A.B.C.D/M$prefix_ipv4|X:X::X:X/M$prefix_ipv6>" + "<algorithm$has_algo (0-1)$algo| iface$has_iface_id (0-4294967295)$iface_id>" + "| adjacency$has_adj " + "<A.B.C.D$adj_src_ipv4 A.B.C.D$adj_dst_ipv4|X:X::X:X$adj_src_ipv6 X:X::X:X$adj_dst_ipv6>" + ">]" + ">", + "Index\n" + "Index Value\n" + "MPLS or IP Label\n" + "Label\n" + "Label Value\n" + "Segment NAI\n" + "NAI prefix identifier\n" + "NAI IPv4 prefix identifier\n" + "NAI IPv6 prefix identifier\n" + "IGP Algorithm\n" + "Algorithm Value SPF or Strict-SPF\n" + "Interface Id\n" + "Interface Value\n" + "ADJ identifier\n" + "ADJ IPv4 src identifier\n" + "ADJ IPv4 dst identifier\n" + "ADJ IPv6 src identifier\n" + "ADJ IPv6 dst identifier\n") +/* clang-format on */ +{ + char xpath[XPATH_MAXLEN]; + int status = CMD_SUCCESS; + + + snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (has_mpls_label != NULL) { + snprintf(xpath, sizeof(xpath), + "./segment[index='%s']/sid-value", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str); + return nb_cli_apply_changes(vty, NULL); + } + + if (has_adj != NULL) { + status = segment_list_has_src_dst(vty, xpath, index, index_str, + adj_src_ipv4, adj_dst_ipv4, + adj_src_ipv6, adj_dst_ipv6, + adj_src_ipv4_str, adj_dst_ipv4_str, + adj_src_ipv6_str, adj_dst_ipv6_str); + if (status != CMD_SUCCESS) + return status; + } else { + status = segment_list_has_prefix( + vty, xpath, index, index_str, prefix_ipv4, + prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo, + algo, algo_str, has_iface_id, iface_id, iface_id_str); + if (status != CMD_SUCCESS) + return status; + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_segment_list_no_segment, + srte_segment_list_no_segment_cmd, + "no index (0-4294967295)$index", + NO_STR + "Index\n" + "Index Value\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_srte_segment_list_segment(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " index %s", yang_dnode_get_string(dnode, "./index")); + if (yang_dnode_exists(dnode, "./sid-value")) { + vty_out(vty, " mpls label %s", + yang_dnode_get_string(dnode, "./sid-value")); + } + if (yang_dnode_exists(dnode, "./nai")) { + struct ipaddr addr; + struct ipaddr addr_rmt; + + switch (yang_dnode_get_enum(dnode, "./nai/type")) { + case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr_rmt, dnode, + "./nai/remote-address"); + vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4); + vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr_rmt, dnode, + "./nai/remote-address"); + vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6); + vty_out(vty, " %pI6", &addr_rmt.ipaddr_v6); + break; + default: + break; + } + if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) { + vty_out(vty, "/%s", + yang_dnode_get_string( + dnode, "./nai/local-prefix-len")); + } + if (yang_dnode_exists(dnode, "./nai/local-interface")) { + vty_out(vty, " iface %s", + yang_dnode_get_string(dnode, + "./nai/local-interface")); + } + if (yang_dnode_exists(dnode, "./nai/algorithm")) { + vty_out(vty, " algorithm %s", + yang_dnode_get_string(dnode, + "./nai/algorithm")); + } + } + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-pathd:pathd/policy + */ +DEFPY_NOSH( + srte_policy, + srte_policy_cmd, + "policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint", + "Segment Routing Policy\n" + "SR Policy color\n" + "SR Policy color value\n" + "SR Policy endpoint\n" + "SR Policy endpoint IPv4 address\n" + "SR Policy endpoint IPv6 address\n") +{ + char xpath[XPATH_POLICY_BASELEN]; + int ret; + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']", + num_str, endpoint_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(SR_POLICY_NODE, xpath); + + return ret; +} + +DEFPY(srte_no_policy, + srte_no_policy_cmd, + "no policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint", + NO_STR + "Segment Routing Policy\n" + "SR Policy color\n" + "SR Policy color value\n" + "SR Policy endpoint\n" + "SR Policy endpoint IPv4 address\n" + "SR Policy endpoint IPv6 address\n") +{ + char xpath[XPATH_POLICY_BASELEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']", + num_str, endpoint_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " policy color %s endpoint %s\n", + yang_dnode_get_string(dnode, "./color"), + yang_dnode_get_string(dnode, "./endpoint")); +} + +void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode) +{ + vty_out(vty, " exit\n"); +} + +/* + * XPath: /frr-pathd:pathd/srte/policy/name + */ +DEFPY(srte_policy_name, + srte_policy_name_cmd, + "name WORD$name", + "Segment Routing Policy name\n" + "SR Policy name value\n") +{ + nb_cli_enqueue_change(vty, "./name", NB_OP_CREATE, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_policy_no_name, + srte_policy_no_name_cmd, + "no name [WORD]", + NO_STR + "Segment Routing Policy name\n" + "SR Policy name value\n") +{ + nb_cli_enqueue_change(vty, "./name", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + + +void cli_show_srte_policy_name(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " name %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-pathd:pathd/srte/policy/binding-sid + */ +DEFPY(srte_policy_binding_sid, + srte_policy_binding_sid_cmd, + "binding-sid (16-1048575)$label", + "Segment Routing Policy Binding-SID\n" + "SR Policy Binding-SID label\n") +{ + nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_CREATE, label_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_policy_no_binding_sid, + srte_policy_no_binding_sid_cmd, + "no binding-sid [(16-1048575)]", + NO_STR + "Segment Routing Policy Binding-SID\n" + "SR Policy Binding-SID label\n") +{ + nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_srte_policy_binding_sid(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " binding-sid %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-pathd:pathd/srte/policy/candidate-path + */ +DEFPY(srte_policy_candidate_exp, + srte_policy_candidate_exp_cmd, + "candidate-path preference (0-4294967295)$preference name WORD$name \ + explicit segment-list WORD$list_name", + "Segment Routing Policy Candidate Path\n" + "Segment Routing Policy Candidate Path Preference\n" + "Administrative Preference\n" + "Segment Routing Policy Candidate Path Name\n" + "Symbolic Name\n" + "Explicit Path\n" + "List of SIDs\n" + "Name of the Segment List\n") +{ + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str); + nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name); + nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local"); + nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config"); + nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "explicit"); + nb_cli_enqueue_change(vty, "./segment-list-name", NB_OP_MODIFY, + list_name); + return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", + preference_str); +} + +DEFPY_NOSH( + srte_policy_candidate_dyn, + srte_policy_candidate_dyn_cmd, + "candidate-path preference (0-4294967295)$preference name WORD$name dynamic", + "Segment Routing Policy Candidate Path\n" + "Segment Routing Policy Candidate Path Preference\n" + "Administrative Preference\n" + "Segment Routing Policy Candidate Path Name\n" + "Symbolic Name\n" + "Dynamic Path\n") +{ + char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN]; + int ret; + + snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']", + VTY_CURR_XPATH, preference_str); + + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str); + nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name); + nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local"); + nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config"); + nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "dynamic"); + ret = nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", + preference_str); + + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(SR_CANDIDATE_DYN_NODE, xpath); + + return ret; +} + +DEFPY(srte_candidate_bandwidth, + srte_candidate_bandwidth_cmd, + "bandwidth BANDWIDTH$value [required$required]", + "Define a bandwidth constraint\n" + "Bandwidth value\n" + "Required constraint\n") +{ + nb_cli_enqueue_change(vty, "./constraints/bandwidth/required", + NB_OP_MODIFY, required ? "true" : "false"); + nb_cli_enqueue_change(vty, "./constraints/bandwidth/value", + NB_OP_MODIFY, value); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_no_bandwidth, + srte_candidate_no_bandwidth_cmd, + "no bandwidth [BANDWIDTH$value] [required$required]", + NO_STR + "Remove a bandwidth constraint\n" + "Bandwidth value\n" + "Required constraint\n") +{ + nb_cli_enqueue_change(vty, "./constraints/bandwidth", NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_affinity_filter, srte_candidate_affinity_filter_cmd, + "affinity <exclude-any|include-any|include-all>$type BITPATTERN$value", + "Affinity constraint\n" + "Exclude any matching link\n" + "Include any matching link\n" + "Include all matching links\n" + "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n") +{ + uint32_t filter; + char xpath[XPATH_CANDIDATE_MAXLEN]; + char decimal_value[11]; + + if (sscanf(value, "0x%x", &filter) != 1) { + vty_out(vty, "affinity type: fscanf: %s\n", + safe_strerror(errno)); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(decimal_value, sizeof(decimal_value), "%u", filter); + snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, decimal_value); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_no_affinity_filter, srte_candidate_no_affinity_filter_cmd, + "no affinity <exclude-any|include-any|include-all>$type [BITPATTERN$value]", + NO_STR + "Affinity constraint\n" + "Exclude any matching link\n" + "Include any matching link\n" + "Include all matching links\n" + "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n") +{ + char xpath[XPATH_CANDIDATE_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_metric, + srte_candidate_metric_cmd, + "metric [bound$bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type METRIC$value [required$required]", + "Define a metric constraint\n" + "If the metric is bounded\n" + "IGP metric\n" + "TE metric\n" + "Hop Counts\n" + "Aggregate bandwidth consumption\n" + "Load of the most loaded link\n" + "Cumulative IGP cost\n" + "Cumulative TE cost\n" + "P2MP IGP metric\n" + "P2MP TE metric\n" + "P2MP hop count metric\n" + "Segment-ID (SID) Depth.\n" + "Path Delay metric\n" + "Path Delay Variation metric\n" + "Path Loss metric\n" + "P2MP Path Delay metric\n" + "P2MP Path Delay variation metric\n" + "P2MP Path Loss metric\n" + "Number of adaptations on a path\n" + "Number of layers on a path\n" + "Domain Count metric\n" + "Border Node Count metric\n" + "Metric value\n" + "Required constraint\n") +{ + char xpath[XPATH_CANDIDATE_MAXLEN]; + snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']/value", + type); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value); + snprintf(xpath, sizeof(xpath), + "./constraints/metrics[type='%s']/is-bound", type); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + (bound != NULL) ? "true" : "false"); + snprintf(xpath, sizeof(xpath), + "./constraints/metrics[type='%s']/required", type); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + required ? "true" : "false"); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_no_metric, + srte_candidate_no_metric_cmd, + "no metric [bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type [METRIC$value] [required$required]", + NO_STR + "Remove a metric constraint\n" + "If the metric is bounded\n" + "IGP metric\n" + "TE metric\n" + "Hop Counts\n" + "Aggregate bandwidth consumption\n" + "Load of the most loaded link\n" + "Cumulative IGP cost\n" + "Cumulative TE cost\n" + "P2MP IGP metric\n" + "P2MP TE metric\n" + "P2MP hop count metric\n" + "Segment-ID (SID) Depth.\n" + "Path Delay metric\n" + "Path Delay Variation metric\n" + "Path Loss metric\n" + "P2MP Path Delay metric\n" + "P2MP Path Delay variation metric\n" + "P2MP Path Loss metric\n" + "Number of adaptations on a path\n" + "Number of layers on a path\n" + "Domain Count metric\n" + "Border Node Count metric\n" + "Metric value\n" + "Required constraint\n") +{ + char xpath[XPATH_CANDIDATE_MAXLEN]; + snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']", + type); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_policy_no_candidate, + srte_policy_no_candidate_cmd, + "no candidate-path\ + preference (0-4294967295)$preference\ + [name WORD\ + <\ + explicit segment-list WORD\ + |dynamic\ + >]", + NO_STR + "Segment Routing Policy Candidate Path\n" + "Segment Routing Policy Candidate Path Preference\n" + "Administrative Preference\n" + "Segment Routing Policy Candidate Path Name\n" + "Symbolic Name\n" + "Explicit Path\n" + "List of SIDs\n" + "Name of the Segment List\n" + "Dynamic Path\n") +{ + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']", + preference_str); +} + +DEFPY(srte_candidate_objfun, + srte_candidate_objfun_cmd, + "objective-function <mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>$type [required$required]", + "Define an objective function constraint\n" + "Minimum Cost Path\n" + "Minimum Load Path\n" + "Maximum residual Bandwidth Path\n" + "Minimize aggregate Bandwidth Consumption\n" + "Minimize the Load of the most loaded Link\n" + "Minimize the Cumulative Cost of a set of paths\n" + "Shortest Path Tree\n" + "Minimum Cost Tree\n" + "Minimum Packet Loss Path\n" + "Maximum Under-Utilized Path\n" + "Maximum Reserved Under-Utilized Path\n" + "Minimize the number of Transit Domains\n" + "Minimize the number of Border Nodes\n" + "Minimize the number of Common Transit Domains\n" + "Minimize the number of Shared Links\n" + "Minimize the number of Shared SRLGs\n" + "Minimize the number of Shared Nodes\n" + "Required constraint\n") +{ + char xpath[XPATH_CANDIDATE_MAXLEN]; + nb_cli_enqueue_change(vty, "./constraints/objective-function", + NB_OP_DESTROY, NULL); + snprintf(xpath, sizeof(xpath), + "./constraints/objective-function/required"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + required ? "true" : "false"); + nb_cli_enqueue_change(vty, "./constraints/objective-function/type", + NB_OP_MODIFY, type); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY(srte_candidate_no_objfun, + srte_candidate_no_objfun_cmd, + "no objective-function [<mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>] [required$required]", + NO_STR + "Remove an objective function constraint\n" + "Minimum Cost Path\n" + "Minimum Load Path\n" + "Maximum residual Bandwidth Path\n" + "Minimize aggregate Bandwidth Consumption\n" + "Minimize the Load of the most loaded Link\n" + "Minimize the Cumulative Cost of a set of paths\n" + "Shortest Path Tree\n" + "Minimum Cost Tree\n" + "Minimum Packet Loss Path\n" + "Maximum Under-Utilized Path\n" + "Maximum Reserved Under-Utilized Path\n" + "Minimize the number of Transit Domains\n" + "Minimize the number of Border Nodes\n" + "Minimize the number of Common Transit Domains\n" + "Minimize the number of Shared Links\n" + "Minimize the number of Shared SRLGs\n" + "Minimize the number of Shared Nodes\n" + "Required constraint\n") +{ + nb_cli_enqueue_change(vty, "./constraints/objective-function", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static const char *objfun_type_name(enum objfun_type type) +{ + switch (type) { + case OBJFUN_MCP: + return "mcp"; + case OBJFUN_MLP: + return "mlp"; + case OBJFUN_MBP: + return "mbp"; + case OBJFUN_MBC: + return "mbc"; + case OBJFUN_MLL: + return "mll"; + case OBJFUN_MCC: + return "mcc"; + case OBJFUN_SPT: + return "spt"; + case OBJFUN_MCT: + return "mct"; + case OBJFUN_MPLP: + return "mplp"; + case OBJFUN_MUP: + return "mup"; + case OBJFUN_MRUP: + return "mrup"; + case OBJFUN_MTD: + return "mtd"; + case OBJFUN_MBN: + return "mbn"; + case OBJFUN_MCTD: + return "mctd"; + case OBJFUN_MSL: + return "msl"; + case OBJFUN_MSS: + return "mss"; + case OBJFUN_MSN: + return "msn"; + default: + return NULL; + } +} + +DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd, + "show debugging [pathd]", + SHOW_STR + "State of each debugging option\n" + "pathd module debugging\n") +{ + /* nothing to do here */ + return CMD_SUCCESS; +} + +static const char *metric_type_name(enum srte_candidate_metric_type type) +{ + switch (type) { + case SRTE_CANDIDATE_METRIC_TYPE_IGP: + return "igp"; + case SRTE_CANDIDATE_METRIC_TYPE_TE: + return "te"; + case SRTE_CANDIDATE_METRIC_TYPE_HC: + return "hc"; + case SRTE_CANDIDATE_METRIC_TYPE_ABC: + return "abc"; + case SRTE_CANDIDATE_METRIC_TYPE_LMLL: + return "lmll"; + case SRTE_CANDIDATE_METRIC_TYPE_CIGP: + return "cigp"; + case SRTE_CANDIDATE_METRIC_TYPE_CTE: + return "cte"; + case SRTE_CANDIDATE_METRIC_TYPE_PIGP: + return "pigp"; + case SRTE_CANDIDATE_METRIC_TYPE_PTE: + return "pte"; + case SRTE_CANDIDATE_METRIC_TYPE_PHC: + return "phc"; + case SRTE_CANDIDATE_METRIC_TYPE_MSD: + return "msd"; + case SRTE_CANDIDATE_METRIC_TYPE_PD: + return "pd"; + case SRTE_CANDIDATE_METRIC_TYPE_PDV: + return "pdv"; + case SRTE_CANDIDATE_METRIC_TYPE_PL: + return "pl"; + case SRTE_CANDIDATE_METRIC_TYPE_PPD: + return "ppd"; + case SRTE_CANDIDATE_METRIC_TYPE_PPDV: + return "ppdv"; + case SRTE_CANDIDATE_METRIC_TYPE_PPL: + return "ppl"; + case SRTE_CANDIDATE_METRIC_TYPE_NAP: + return "nap"; + case SRTE_CANDIDATE_METRIC_TYPE_NLP: + return "nlp"; + case SRTE_CANDIDATE_METRIC_TYPE_DC: + return "dc"; + case SRTE_CANDIDATE_METRIC_TYPE_BNC: + return "bnc"; + default: + return NULL; + } +} + +static void config_write_float(struct vty *vty, float value) +{ + if (fabs(truncf(value) - value) < FLT_EPSILON) { + vty_out(vty, " %d", (int)value); + return; + } else { + vty_out(vty, " %f", value); + } +} + +static void config_write_metric(struct vty *vty, + enum srte_candidate_metric_type type, + float value, bool required, bool is_bound) +{ + const char *name = metric_type_name(type); + if (name == NULL) + return; + vty_out(vty, " metric %s%s", is_bound ? "bound " : "", + metric_type_name(type)); + config_write_float(vty, value); + vty_out(vty, required ? " required" : ""); + vty_out(vty, "\n"); +} + +static int config_write_metric_cb(const struct lyd_node *dnode, void *arg) +{ + struct vty *vty = arg; + enum srte_candidate_metric_type type; + bool required, is_bound = false; + float value; + + type = yang_dnode_get_enum(dnode, "./type"); + value = (float)yang_dnode_get_dec64(dnode, "./value"); + required = yang_dnode_get_bool(dnode, "./required"); + if (yang_dnode_exists(dnode, "./is-bound")) + is_bound = yang_dnode_get_bool(dnode, "./is-bound"); + + config_write_metric(vty, type, value, required, is_bound); + return YANG_ITER_CONTINUE; +} + +void cli_show_srte_policy_candidate_path(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + float bandwidth; + uint32_t affinity; + bool required; + enum objfun_type objfun_type; + const char *type = yang_dnode_get_string(dnode, "./type"); + + vty_out(vty, " candidate-path preference %s name %s %s", + yang_dnode_get_string(dnode, "./preference"), + yang_dnode_get_string(dnode, "./name"), type); + if (strmatch(type, "explicit")) + vty_out(vty, " segment-list %s", + yang_dnode_get_string(dnode, "./segment-list-name")); + vty_out(vty, "\n"); + + if (strmatch(type, "dynamic")) { + if (yang_dnode_exists(dnode, "./constraints/bandwidth")) { + bandwidth = (float)yang_dnode_get_dec64( + dnode, "./constraints/bandwidth/value"); + required = yang_dnode_get_bool( + dnode, "./constraints/bandwidth/required"); + vty_out(vty, " bandwidth"); + config_write_float(vty, bandwidth); + if (required) + vty_out(vty, " required"); + vty_out(vty, "\n"); + } + if (yang_dnode_exists(dnode, + "./constraints/affinity/exclude-any")) { + affinity = yang_dnode_get_uint32( + dnode, "./constraints/affinity/exclude-any"); + vty_out(vty, " affinity exclude-any 0x%08x\n", + affinity); + } + if (yang_dnode_exists(dnode, + "./constraints/affinity/include-any")) { + affinity = yang_dnode_get_uint32( + dnode, "./constraints/affinity/include-any"); + vty_out(vty, " affinity include-any 0x%08x\n", + affinity); + } + if (yang_dnode_exists(dnode, + "./constraints/affinity/include-all")) { + affinity = yang_dnode_get_uint32( + dnode, "./constraints/affinity/include-all"); + vty_out(vty, " affinity include-all 0x%08x\n", + affinity); + } + yang_dnode_iterate(config_write_metric_cb, vty, dnode, + "./constraints/metrics"); + if (yang_dnode_exists(dnode, + "./constraints/objective-function")) { + objfun_type = yang_dnode_get_enum(dnode, + "./constraints/objective-function/type"); + required = yang_dnode_get_bool(dnode, + "./constraints/objective-function/required"); + vty_out(vty, " objective-function %s%s\n", + objfun_type_name(objfun_type), + required ? " required" : ""); + } + } +} + +void cli_show_srte_policy_candidate_path_end(struct vty *vty, + const struct lyd_node *dnode) +{ + const char *type = yang_dnode_get_string(dnode, "./type"); + + if (strmatch(type, "dynamic")) + vty_out(vty, " exit\n"); +} + +static int config_write_dnode(const struct lyd_node *dnode, void *arg) +{ + struct vty *vty = arg; + + nb_cli_show_dnode_cmds(vty, dnode, false); + + return YANG_ITER_CONTINUE; +} + +int config_write_segment_routing(struct vty *vty) +{ + vty_out(vty, "segment-routing\n"); + vty_out(vty, " traffic-eng\n"); + + path_ted_config_write(vty); + + yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, + "/frr-pathd:pathd/srte/segment-list"); + yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, + "/frr-pathd:pathd/srte/policy"); + + hook_call(pathd_srte_config_write, vty); + + vty_out(vty, " exit\n"); + vty_out(vty, "exit\n"); + + return 1; +} + +void path_cli_init(void) +{ + install_node(&segment_routing_node); + install_node(&sr_traffic_eng_node); + install_node(&srte_segment_list_node); + install_node(&srte_policy_node); + install_node(&srte_candidate_dyn_node); + install_default(SEGMENT_ROUTING_NODE); + install_default(SR_TRAFFIC_ENG_NODE); + install_default(SR_SEGMENT_LIST_NODE); + install_default(SR_POLICY_NODE); + install_default(SR_CANDIDATE_DYN_NODE); + + install_element(ENABLE_NODE, &show_debugging_pathd_cmd); + install_element(ENABLE_NODE, &show_srte_policy_cmd); + install_element(ENABLE_NODE, &show_srte_policy_detail_cmd); + + install_element(CONFIG_NODE, &segment_routing_cmd); + install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &srte_no_segment_list_cmd); + install_element(SR_SEGMENT_LIST_NODE, + &srte_segment_list_segment_cmd); + install_element(SR_SEGMENT_LIST_NODE, + &srte_segment_list_no_segment_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &srte_no_policy_cmd); + install_element(SR_POLICY_NODE, &srte_policy_name_cmd); + install_element(SR_POLICY_NODE, &srte_policy_no_name_cmd); + install_element(SR_POLICY_NODE, &srte_policy_binding_sid_cmd); + install_element(SR_POLICY_NODE, &srte_policy_no_binding_sid_cmd); + install_element(SR_POLICY_NODE, &srte_policy_candidate_exp_cmd); + install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_cmd); + install_element(SR_POLICY_NODE, &srte_policy_no_candidate_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_bandwidth_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_no_bandwidth_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_affinity_filter_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_no_affinity_filter_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_metric_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_no_metric_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_objfun_cmd); + install_element(SR_CANDIDATE_DYN_NODE, + &srte_candidate_no_objfun_cmd); +} |