/* * 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 #include #include #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 #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 config_write_traffic_eng(struct vty *vty); static int config_write_segment_lists(struct vty *vty); static int config_write_sr_policies(struct vty *vty); DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client"); /* 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)# ", .config_write = config_write_traffic_eng, }; 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)# ", .config_write = config_write_segment_lists, }; 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)# ", .config_write = config_write_sr_policies, }; 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, struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-list %s\n", yang_dnode_get_string(dnode, "./name")); } /* * XPath: /frr-pathd:pathd/srte/segment-list/segment */ DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, "index (0-4294967295)$index mpls label (16-1048575)$label " "[nai$has_nai <" "node " ">]", "Index\n" "Index Value\n" "MPLS or IP Label\n" "Label\n" "Label Value\n" "Segment NAI\n" "NAI node identifier\n" "NAI IPv4 node identifier\n" "NAI IPv6 node identifier\n") { char xpath[XPATH_MAXLEN]; const char *node_id; snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); snprintf(xpath, sizeof(xpath), "./segment[index='%s']/sid-value", index_str); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str); if (has_nai != NULL) { snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai/type", index_str); if (node_ipv4_str != NULL) { nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "ipv4_node"); node_id = node_ipv4_str; } else if (node_ipv6_str != NULL) { nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "ipv6_node"); node_id = node_ipv6_str; } else { return CMD_ERR_NO_MATCH; } snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai/local-address", index_str); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_id); } else { snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai", index_str); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); } 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, struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " index %s mpls label %s", yang_dnode_get_string(dnode, "./index"), yang_dnode_get_string(dnode, "./sid-value")); if (yang_dnode_exists(dnode, "./nai")) { struct ipaddr addr; switch (yang_dnode_get_enum(dnode, "./nai/type")) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); vty_out(vty, " nai node %pI4", &addr.ipaddr_v4); break; case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); vty_out(vty, " nai node %pI6", &addr.ipaddr_v6); break; default: break; } } vty_out(vty, "\n"); } /* * XPath: /frr-pathd:pathd/policy */ DEFPY_NOSH( srte_policy, srte_policy_cmd, "policy color (0-4294967295)$num endpoint $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 $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, 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")); } /* * 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, 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, 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] $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] $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 $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 [] [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, 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, " %sbandwidth", required ? "required " : ""); config_write_float(vty, bandwidth); 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" : ""); } } } static int config_write_dnode(const struct lyd_node *dnode, void *arg) { struct vty *vty = arg; nb_cli_show_dnode_cmds(vty, (struct lyd_node *)dnode, false); return YANG_ITER_CONTINUE; } int config_write_segment_routing(struct vty *vty) { vty_out(vty, "segment-routing\n"); return 1; } int config_write_traffic_eng(struct vty *vty) { vty_out(vty, " traffic-eng\n"); return 1; } int config_write_segment_lists(struct vty *vty) { yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, "/frr-pathd:pathd/srte/segment-list"); return 1; } int config_write_sr_policies(struct vty *vty) { yang_dnode_iterate(config_write_dnode, vty, running_config->dnode, "/frr-pathd:pathd/srte/policy"); 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); }