2025-02-05 10:03:58 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2020 NetDEF, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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"
|
|
|
|
#include "pathd/path_cli_clippy.c"
|
|
|
|
#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[ENDPOINT_STR_LENGTH];
|
|
|
|
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);
|
2025-02-05 10:17:20 +01:00
|
|
|
XFREE(MTYPE_TMP_TTABLE, table);
|
2025-02-05 10:03:58 +01:00
|
|
|
|
|
|
|
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[ENDPOINT_STR_LENGTH];
|
|
|
|
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] [computed$computed]",
|
|
|
|
"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"
|
|
|
|
"Force the PCE to provide the computed path metric\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");
|
|
|
|
snprintf(xpath, sizeof(xpath),
|
|
|
|
"./constraints/metrics[type='%s']/is-computed", type);
|
|
|
|
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
|
|
|
computed ? "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] [computed$computed]",
|
|
|
|
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"
|
|
|
|
"Force the PCE to provide the computed path metric\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";
|
|
|
|
case OBJFUN_UNDEFINED:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"Reached end of function we should never hit");
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
|
|
|
|
"show debugging [pathd]",
|
|
|
|
SHOW_STR
|
|
|
|
"State of each debugging option\n"
|
|
|
|
"pathd module debugging\n")
|
|
|
|
{
|
|
|
|
|
|
|
|
vty_out(vty, "Path debugging status:\n");
|
|
|
|
|
|
|
|
cmd_show_lib_debugs(vty);
|
2025-02-05 10:17:20 +01:00
|
|
|
|
2025-02-05 10:03:58 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
|
|
|
|
NO_STR DEBUG_STR
|
|
|
|
"path debugging\n"
|
|
|
|
"policy debugging\n")
|
|
|
|
{
|
|
|
|
uint32_t mode = DEBUG_NODE2MODE(vty->node);
|
|
|
|
|
|
|
|
DEBUG_MODE_SET(&path_policy_debug, mode, !no);
|
|
|
|
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,
|
|
|
|
bool is_computed)
|
|
|
|
{
|
|
|
|
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, is_computed ? " computed" : "");
|
|
|
|
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, is_computed = 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");
|
|
|
|
if (yang_dnode_exists(dnode, "is-computed"))
|
|
|
|
is_computed = yang_dnode_get_bool(dnode, "is-computed");
|
|
|
|
|
|
|
|
config_write_metric(vty, type, value, required, is_bound, is_computed);
|
|
|
|
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)
|
|
|
|
{
|
2025-02-05 10:17:20 +01:00
|
|
|
debug_install(&path_policy_debug);
|
2025-02-05 10:03:58 +01:00
|
|
|
|
|
|
|
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(ENABLE_NODE, &debug_path_policy_cmd);
|
|
|
|
install_element(CONFIG_NODE, &debug_path_policy_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);
|
|
|
|
}
|