summaryrefslogtreecommitdiffstats
path: root/pathd/path_pcep_cli.c
diff options
context:
space:
mode:
Diffstat (limited to 'pathd/path_pcep_cli.c')
-rw-r--r--pathd/path_pcep_cli.c2064
1 files changed, 2064 insertions, 0 deletions
diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c
new file mode 100644
index 0000000..d2b49a7
--- /dev/null
+++ b/pathd/path_pcep_cli.c
@@ -0,0 +1,2064 @@
+/*
+ * Copyright (C) 2020 Volta Networks, Inc
+ * Brady Johnson
+ *
+ * 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 "pceplib/pcep_utils_counters.h"
+#include "pceplib/pcep_session_logic.h"
+
+#include "log.h"
+#include "command.h"
+#include "libfrr.h"
+#include "printfrr.h"
+#include "lib/version.h"
+#include "northbound.h"
+#include "frr_pthread.h"
+#include "jhash.h"
+#include "termtable.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_errors.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_cli.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_debug.h"
+#include "pathd/path_pcep_lib.h"
+#include "pathd/path_pcep_pcc.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "pathd/path_pcep_cli_clippy.c"
+#endif
+
+#define DEFAULT_PCE_PRECEDENCE 255
+#define DEFAULT_PCC_MSD 4
+#define DEFAULT_SR_DRAFT07 false
+#define DEFAULT_PCE_INITIATED false
+#define DEFAULT_TIMER_KEEP_ALIVE 30
+#define DEFAULT_TIMER_KEEP_ALIVE_MIN 1
+#define DEFAULT_TIMER_KEEP_ALIVE_MAX 255
+#define DEFAULT_TIMER_DEADTIMER 120
+#define DEFAULT_TIMER_DEADTIMER_MIN 4
+#define DEFAULT_TIMER_DEADTIMER_MAX 255
+#define DEFAULT_TIMER_PCEP_REQUEST 30
+#define DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL 30
+#define DEFAULT_DELEGATION_TIMEOUT_INTERVAL 10
+
+/* CLI Function declarations */
+static int pcep_cli_debug_config_write(struct vty *vty);
+static int pcep_cli_debug_set_all(uint32_t flags, bool set);
+static int pcep_cli_pcep_config_write(struct vty *vty);
+static int pcep_cli_pcc_config_write(struct vty *vty);
+static int pcep_cli_pce_config_write(struct vty *vty);
+static int pcep_cli_pcep_pce_config_write(struct vty *vty);
+
+/* Internal Util Function declarations */
+static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name);
+static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli);
+static struct pce_opts_cli *pcep_cli_create_pce_opts(const char *name);
+static void pcep_cli_delete_pce(const char *pce_name);
+static void
+pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli);
+static struct pcep_config_group_opts *
+pcep_cli_find_pcep_pce_config(const char *group_name);
+static bool
+pcep_cli_add_pcep_pce_config(struct pcep_config_group_opts *config_group_opts);
+static struct pcep_config_group_opts *
+pcep_cli_create_pcep_pce_config(const char *group_name);
+static bool pcep_cli_is_pcep_pce_config_used(const char *group_name);
+static void pcep_cli_delete_pcep_pce_config(const char *group_name);
+static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
+ char *buf, size_t buf_len);
+static void print_pcep_capabilities(char *buf, size_t buf_len,
+ pcep_configuration *config);
+static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
+ struct pcep_pcc_info *pcc_info);
+static bool pcep_cli_pcc_has_pce(const char *pce_name);
+static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts);
+static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts);
+static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
+ const char *peer_name,
+ const char *precedence_str,
+ long precedence);
+
+/*
+ * Globals.
+ */
+
+static const char PCEP_VTYSH_ARG_ADDRESS[] = "address";
+static const char PCEP_VTYSH_ARG_SOURCE_ADDRESS[] = "source-address";
+static const char PCEP_VTYSH_ARG_IP[] = "ip";
+static const char PCEP_VTYSH_ARG_IPV6[] = "ipv6";
+static const char PCEP_VTYSH_ARG_PORT[] = "port";
+static const char PCEP_VTYSH_ARG_PRECEDENCE[] = "precedence";
+static const char PCEP_VTYSH_ARG_MSD[] = "msd";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE[] = "keep-alive";
+static const char PCEP_VTYSH_ARG_TIMER[] = "timer";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MIN[] = "min-peer-keep-alive";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MAX[] = "max-peer-keep-alive";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER[] = "dead-timer";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER_MIN[] = "min-peer-dead-timer";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER_MAX[] = "max-peer-dead-timer";
+static const char PCEP_VTYSH_ARG_PCEP_REQUEST[] = "pcep-request";
+static const char PCEP_VTYSH_ARG_SESSION_TIMEOUT[] = "session-timeout-interval";
+static const char PCEP_VTYSH_ARG_DELEGATION_TIMEOUT[] = "delegation-timeout";
+static const char PCEP_VTYSH_ARG_SR_DRAFT07[] = "sr-draft07";
+static const char PCEP_VTYSH_ARG_PCE_INIT[] = "pce-initiated";
+static const char PCEP_VTYSH_ARG_TCP_MD5[] = "tcp-md5-auth";
+static const char PCEP_VTYSH_ARG_BASIC[] = "basic";
+static const char PCEP_VTYSH_ARG_PATH[] = "path";
+static const char PCEP_VTYSH_ARG_MESSAGE[] = "message";
+static const char PCEP_VTYSH_ARG_PCEPLIB[] = "pceplib";
+static const char PCEP_CLI_CAP_STATEFUL[] = " [Stateful PCE]";
+static const char PCEP_CLI_CAP_INCL_DB_VER[] = " [Include DB version]";
+static const char PCEP_CLI_CAP_LSP_TRIGGERED[] = " [LSP Triggered Resync]";
+static const char PCEP_CLI_CAP_LSP_DELTA[] = " [LSP Delta Sync]";
+static const char PCEP_CLI_CAP_PCE_TRIGGERED[] =
+ " [PCE triggered Initial Sync]";
+static const char PCEP_CLI_CAP_SR_TE_PST[] = " [SR TE PST]";
+static const char PCEP_CLI_CAP_PCC_RESOLVE_NAI[] =
+ " [PCC can resolve NAI to SID]";
+static const char PCEP_CLI_CAP_PCC_INITIATED[] = " [PCC Initiated LSPs]";
+static const char PCEP_CLI_CAP_PCC_PCE_INITIATED[] =
+ " [PCC and PCE Initiated LSPs]";
+
+struct pce_connections {
+ int num_connections;
+ struct pce_opts *connections[MAX_PCC];
+};
+
+struct pce_connections pce_connections_g = {.num_connections = 0};
+
+/* Default PCE group that all PCE-Groups and PCEs will inherit from */
+struct pcep_config_group_opts default_pcep_config_group_opts_g = {
+ .name = "default",
+ .tcp_md5_auth = "\0",
+ .draft07 = DEFAULT_SR_DRAFT07,
+ .pce_initiated = DEFAULT_PCE_INITIATED,
+ .keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE,
+ .min_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MIN,
+ .max_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MAX,
+ .dead_timer_seconds = DEFAULT_TIMER_DEADTIMER,
+ .min_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MIN,
+ .max_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MAX,
+ .pcep_request_time_seconds = DEFAULT_TIMER_PCEP_REQUEST,
+ .session_timeout_inteval_seconds =
+ DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL,
+ .delegation_timeout_seconds = DEFAULT_DELEGATION_TIMEOUT_INTERVAL,
+ .source_port = DEFAULT_PCEP_TCP_PORT,
+ .source_ip.ipa_type = IPADDR_NONE,
+};
+
+/* Used by PCEP_PCE_CONFIG_NODE sub-commands to operate on the current pce group
+ */
+struct pcep_config_group_opts *current_pcep_config_group_opts_g = NULL;
+/* Used by PCEP_PCE_NODE sub-commands to operate on the current pce opts */
+struct pce_opts_cli *current_pce_opts_g = NULL;
+short pcc_msd_g = DEFAULT_PCC_MSD;
+bool pcc_msd_configured_g = false;
+
+static struct cmd_node pcep_node = {
+ .name = "srte pcep",
+ .node = PCEP_NODE,
+ .parent_node = SR_TRAFFIC_ENG_NODE,
+ .prompt = "%s(config-sr-te-pcep)# "
+};
+
+static struct cmd_node pcep_pcc_node = {
+ .name = "srte pcep pcc",
+ .node = PCEP_PCC_NODE,
+ .parent_node = PCEP_NODE,
+ .prompt = "%s(config-sr-te-pcep-pcc)# "
+};
+
+static struct cmd_node pcep_pce_node = {
+ .name = "srte pcep pce",
+ .node = PCEP_PCE_NODE,
+ .parent_node = PCEP_NODE,
+ .prompt = "%s(config-sr-te-pcep-pce)# "
+};
+
+static struct cmd_node pcep_pce_config_node = {
+ .name = "srte pcep pce-config",
+ .node = PCEP_PCE_CONFIG_NODE,
+ .parent_node = PCEP_NODE,
+ .prompt = "%s(pce-sr-te-pcep-pce-config)# "
+};
+
+/* Common code used in VTYSH processing for int values */
+#define PCEP_VTYSH_INT_ARG_CHECK(arg_str, arg_val, arg_store, min_value, \
+ max_value) \
+ if (arg_str != NULL) { \
+ if (arg_val <= min_value || arg_val >= max_value) { \
+ vty_out(vty, \
+ "%% Invalid value %ld in range [%d - %d]", \
+ arg_val, min_value, max_value); \
+ return CMD_WARNING; \
+ } \
+ arg_store = arg_val; \
+ }
+
+#define MERGE_COMPARE_CONFIG_GROUP_VALUE(config_param, not_set_value) \
+ pce_opts_cli->pce_opts.config_opts.config_param = \
+ pce_opts_cli->pce_config_group_opts.config_param; \
+ if (pce_opts_cli->pce_config_group_opts.config_param \
+ == not_set_value) { \
+ pce_opts_cli->pce_opts.config_opts.config_param = \
+ ((pce_config != NULL \
+ && pce_config->config_param != not_set_value) \
+ ? pce_config->config_param \
+ : default_pcep_config_group_opts_g \
+ .config_param); \
+ }
+
+/*
+ * Internal Util functions
+ */
+
+/* Check if a pce_opts_cli already exists based on its name and return it,
+ * return NULL otherwise */
+static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ struct pce_opts_cli *pce_rhs_cli = pcep_g->pce_opts_cli[i];
+ if (pce_rhs_cli != NULL) {
+ if (strcmp(pce_name, pce_rhs_cli->pce_opts.pce_name)
+ == 0) {
+ return pce_rhs_cli;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Add a new pce_opts_cli to pcep_g, return false if MAX_PCES, true otherwise */
+static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ if (pcep_g->pce_opts_cli[i] == NULL) {
+ pcep_g->pce_opts_cli[i] = pce_opts_cli;
+ pcep_g->num_pce_opts_cli++;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Create a new pce opts_cli */
+static struct pce_opts_cli *pcep_cli_create_pce_opts(const char *name)
+{
+ struct pce_opts_cli *pce_opts_cli =
+ XCALLOC(MTYPE_PCEP, sizeof(struct pce_opts_cli));
+ strlcpy(pce_opts_cli->pce_opts.pce_name, name,
+ sizeof(pce_opts_cli->pce_opts.pce_name));
+ pce_opts_cli->pce_opts.port = PCEP_DEFAULT_PORT;
+
+ return pce_opts_cli;
+}
+
+static void pcep_cli_delete_pce(const char *pce_name)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ if (pcep_g->pce_opts_cli[i] != NULL) {
+ if (strcmp(pcep_g->pce_opts_cli[i]->pce_opts.pce_name,
+ pce_name)
+ == 0) {
+ XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]);
+ pcep_g->pce_opts_cli[i] = NULL;
+ pcep_g->num_pce_opts_cli--;
+ return;
+ }
+ }
+ }
+}
+
+static void
+pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli)
+{
+ if (pce_opts_cli->merged == true) {
+ return;
+ }
+
+ struct pcep_config_group_opts *pce_config =
+ pcep_cli_find_pcep_pce_config(pce_opts_cli->config_group_name);
+
+ /* Configuration priorities:
+ * 1) pce_opts->config_opts, if present, overwrite pce_config
+ * config_opts 2) pce_config config_opts, if present, overwrite
+ * default config_opts 3) If neither pce_opts->config_opts nor
+ * pce_config config_opts are set, then the default config_opts value
+ * will be used.
+ */
+
+ const char *tcp_md5_auth_str =
+ pce_opts_cli->pce_config_group_opts.tcp_md5_auth;
+ if (pce_opts_cli->pce_config_group_opts.tcp_md5_auth[0] == '\0') {
+ if (pce_config != NULL && pce_config->tcp_md5_auth[0] != '\0') {
+ tcp_md5_auth_str = pce_config->tcp_md5_auth;
+ } else {
+ tcp_md5_auth_str =
+ default_pcep_config_group_opts_g.tcp_md5_auth;
+ }
+ }
+ strlcpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
+ tcp_md5_auth_str,
+ sizeof(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth));
+
+ struct ipaddr *source_ip =
+ &pce_opts_cli->pce_config_group_opts.source_ip;
+ if (pce_opts_cli->pce_config_group_opts.source_ip.ipa_type
+ == IPADDR_NONE) {
+ if (pce_config != NULL
+ && pce_config->source_ip.ipa_type != IPADDR_NONE) {
+ source_ip = &pce_config->source_ip;
+ } else {
+ source_ip = &default_pcep_config_group_opts_g.source_ip;
+ }
+ }
+ memcpy(&pce_opts_cli->pce_opts.config_opts.source_ip, source_ip,
+ sizeof(struct ipaddr));
+
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(draft07, false);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(pce_initiated, false);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(keep_alive_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(min_keep_alive_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(max_keep_alive_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(dead_timer_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(min_dead_timer_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(max_dead_timer_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(pcep_request_time_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(session_timeout_inteval_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(delegation_timeout_seconds, 0);
+ MERGE_COMPARE_CONFIG_GROUP_VALUE(source_port, 0);
+
+ pce_opts_cli->merged = true;
+}
+
+/* Check if a pcep_config_group_opts already exists based on its name and return
+ * it, return NULL otherwise */
+static struct pcep_config_group_opts *
+pcep_cli_find_pcep_pce_config(const char *group_name)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ struct pcep_config_group_opts *pcep_pce_config_rhs =
+ pcep_g->config_group_opts[i];
+ if (pcep_pce_config_rhs != NULL) {
+ if (strcmp(group_name, pcep_pce_config_rhs->name)
+ == 0) {
+ return pcep_pce_config_rhs;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Add a new pcep_config_group_opts to pcep_g, return false if MAX_PCE,
+ * true otherwise */
+static bool pcep_cli_add_pcep_pce_config(
+ struct pcep_config_group_opts *pcep_config_group_opts)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ if (pcep_g->config_group_opts[i] == NULL) {
+ pcep_g->config_group_opts[i] = pcep_config_group_opts;
+ pcep_g->num_config_group_opts++;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Create a new pce group, inheriting its values from the default pce group */
+static struct pcep_config_group_opts *
+pcep_cli_create_pcep_pce_config(const char *group_name)
+{
+ struct pcep_config_group_opts *pcep_config_group_opts =
+ XCALLOC(MTYPE_PCEP, sizeof(struct pcep_config_group_opts));
+ strlcpy(pcep_config_group_opts->name, group_name,
+ sizeof(pcep_config_group_opts->name));
+
+ return pcep_config_group_opts;
+}
+
+/* Iterate the pce_opts and return true if the pce-group-name is referenced,
+ * false otherwise. */
+static bool pcep_cli_is_pcep_pce_config_used(const char *group_name)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ if (pcep_g->pce_opts_cli[i] != NULL) {
+ if (strcmp(pcep_g->pce_opts_cli[i]->config_group_name,
+ group_name)
+ == 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void pcep_cli_delete_pcep_pce_config(const char *group_name)
+{
+ for (int i = 0; i < MAX_PCE; i++) {
+ if (pcep_g->config_group_opts[i] != NULL) {
+ if (strcmp(pcep_g->config_group_opts[i]->name,
+ group_name)
+ == 0) {
+ XFREE(MTYPE_PCEP, pcep_g->config_group_opts[i]);
+ pcep_g->config_group_opts[i] = NULL;
+ pcep_g->num_config_group_opts--;
+ return;
+ }
+ }
+ }
+}
+
+static bool pcep_cli_pcc_has_pce(const char *pce_name)
+{
+ for (int i = 0; i < MAX_PCC; i++) {
+ struct pce_opts *pce_opts = pce_connections_g.connections[i];
+ if (pce_opts == NULL) {
+ continue;
+ }
+
+ if (strcmp(pce_opts->pce_name, pce_name) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts)
+{
+ for (int i = 0; i < MAX_PCC; i++) {
+ if (pce_connections_g.connections[i] == NULL) {
+ pce_connections_g.num_connections++;
+ pce_connections_g.connections[i] = pce_opts;
+ return;
+ }
+ }
+}
+
+static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts)
+{
+ for (int i = 0; i < MAX_PCC; i++) {
+ if (pce_connections_g.connections[i] == pce_opts) {
+ pce_connections_g.num_connections--;
+ pce_connections_g.connections[i] = NULL;
+ return;
+ }
+ }
+}
+
+/*
+ * VTY command implementations
+ */
+
+static int path_pcep_cli_debug(struct vty *vty, const char *no_str,
+ const char *basic_str, const char *path_str,
+ const char *message_str, const char *pceplib_str)
+{
+ uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool no = (no_str != NULL);
+
+ DEBUG_MODE_SET(&pcep_g->dbg, mode, !no);
+
+ if (basic_str != NULL) {
+ DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, !no);
+ }
+ if (path_str != NULL) {
+ DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, !no);
+ }
+ if (message_str != NULL) {
+ DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, !no);
+ }
+ if (pceplib_str != NULL) {
+ DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, !no);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_counters(struct vty *vty)
+{
+ int i, j, row;
+ time_t diff_time;
+ struct tm tm_info;
+ char tm_buffer[26];
+ struct counters_group *group;
+ struct counters_subgroup *subgroup;
+ struct counter *counter;
+ const char *group_name, *empty_string = "";
+ struct ttable *tt;
+ char *table;
+
+ group = pcep_ctrl_get_counters(pcep_g->fpt, 1);
+
+ if (group == NULL) {
+ vty_out(vty, "No counters to display.\n\n");
+ return CMD_SUCCESS;
+ }
+
+ diff_time = time(NULL) - group->start_time;
+ localtime_r(&group->start_time, &tm_info);
+ strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", &tm_info);
+
+ vty_out(vty, "PCEP counters since %s (%uh %um %us):\n", tm_buffer,
+ (uint32_t)(diff_time / 3600), (uint32_t)((diff_time / 60) % 60),
+ (uint32_t)(diff_time % 60));
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Group|Name|Value");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+ for (row = 0, i = 0; i <= group->num_subgroups; i++) {
+ subgroup = group->subgroups[i];
+ if (subgroup != NULL) {
+ group_name = subgroup->counters_subgroup_name;
+ for (j = 0; j <= subgroup->num_counters; j++) {
+ counter = subgroup->counters[j];
+ if (counter != NULL) {
+ ttable_add_row(tt, "%s|%s|%u",
+ group_name,
+ counter->counter_name,
+ counter->counter_value);
+ row++;
+ group_name = empty_string;
+ }
+ }
+ ttable_rowseps(tt, row, BOTTOM, true, '-');
+ }
+ }
+
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+
+ ttable_del(tt);
+
+ pcep_lib_free_counters(group);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcep_pce_config(struct vty *vty,
+ const char *pcep_pce_config)
+{
+ struct pcep_config_group_opts *pce_config =
+ pcep_cli_find_pcep_pce_config(pcep_pce_config);
+ if (pce_config == NULL) {
+ pce_config = pcep_cli_create_pcep_pce_config(pcep_pce_config);
+ if (pcep_cli_add_pcep_pce_config(pce_config) == false) {
+ vty_out(vty,
+ "%% Cannot create pce-config, as the Maximum limit of %d pce-config has been reached.\n",
+ MAX_PCE);
+ XFREE(MTYPE_PCEP, pce_config);
+ return CMD_WARNING;
+ }
+ } else {
+ vty_out(vty,
+ "Notice: changes to this pce-config will not affect PCEs already configured with this group\n");
+ }
+
+ current_pcep_config_group_opts_g = pce_config;
+ vty->node = PCEP_PCE_CONFIG_NODE;
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcep_pce_config_delete(struct vty *vty,
+ const char *pcep_pce_config)
+{
+ struct pcep_config_group_opts *pce_config =
+ pcep_cli_find_pcep_pce_config(pcep_pce_config);
+ if (pce_config == NULL) {
+ vty_out(vty,
+ "%% Cannot delete pce-config, since it does not exist.\n");
+ return CMD_WARNING;
+ }
+
+ if (pcep_cli_is_pcep_pce_config_used(pce_config->name)) {
+ vty_out(vty,
+ "%% Cannot delete pce-config, since it is in use by a peer.\n");
+ return CMD_WARNING;
+ }
+
+ pcep_cli_delete_pcep_pce_config(pce_config->name);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_pce_config(struct vty *vty,
+ const char *pcep_pce_config)
+{
+ char buf[1024] = "";
+
+ /* Only show 1 Peer config group */
+ struct pcep_config_group_opts *group_opts;
+ if (pcep_pce_config != NULL) {
+ if (strcmp(pcep_pce_config, "default") == 0) {
+ group_opts = &default_pcep_config_group_opts_g;
+ } else {
+ group_opts =
+ pcep_cli_find_pcep_pce_config(pcep_pce_config);
+ }
+ if (group_opts == NULL) {
+ vty_out(vty, "%% pce-config [%s] does not exist.\n",
+ pcep_pce_config);
+ return CMD_WARNING;
+ }
+
+ vty_out(vty, "pce-config: %s\n", group_opts->name);
+ pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+ vty_out(vty, "%s", buf);
+ return CMD_SUCCESS;
+ }
+
+ /* Show all Peer config groups */
+ for (int i = 0; i < MAX_PCE; i++) {
+ group_opts = pcep_g->config_group_opts[i];
+ if (group_opts == NULL) {
+ continue;
+ }
+
+ vty_out(vty, "pce-config: %s\n", group_opts->name);
+ pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+ vty_out(vty, "%s", buf);
+ buf[0] = 0;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pce(struct vty *vty, const char *pce_peer_name)
+{
+ /* If it already exists, it will be updated in the sub-commands */
+ struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
+ if (pce_opts_cli == NULL) {
+ pce_opts_cli = pcep_cli_create_pce_opts(pce_peer_name);
+
+ if (!pcep_cli_add_pce(pce_opts_cli)) {
+ vty_out(vty,
+ "%% Cannot create PCE, as the Maximum limit of %d PCEs has been reached.\n",
+ MAX_PCE);
+ XFREE(MTYPE_PCEP, pce_opts_cli);
+ return CMD_WARNING;
+ }
+ }
+
+ current_pce_opts_g = pce_opts_cli;
+ vty->node = PCEP_PCE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pce_delete(struct vty *vty, const char *pce_peer_name)
+{
+ struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
+ if (pce_opts_cli == NULL) {
+ vty_out(vty, "%% PCC peer does not exist.\n");
+ return CMD_WARNING;
+ }
+
+ /* To better work with frr-reload, go ahead and delete it if its in use
+ */
+ if (pcep_cli_pcc_has_pce(pce_peer_name)) {
+ vty_out(vty,
+ "%% Notice: the pce is in use by a PCC, also disconnecting.\n");
+ path_pcep_cli_pcc_pcc_peer_delete(vty, pce_peer_name, NULL, 0);
+ }
+
+ pcep_cli_delete_pce(pce_peer_name);
+
+ return CMD_SUCCESS;
+}
+
+/* Internal Util func to show an individual PCE,
+ * only used by path_pcep_cli_show_srte_pcep_pce() */
+static void show_pce_peer(struct vty *vty, struct pce_opts_cli *pce_opts_cli)
+{
+ struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+ vty_out(vty, "PCE: %s\n", pce_opts->pce_name);
+
+ /* Remote PCE IP address */
+ if (IS_IPADDR_V6(&pce_opts->addr)) {
+ vty_out(vty, " %s %s %pI6 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
+ PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6,
+ PCEP_VTYSH_ARG_PORT, pce_opts->port);
+ } else {
+ vty_out(vty, " %s %s %pI4 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
+ PCEP_VTYSH_ARG_IP, &pce_opts->addr.ipaddr_v4,
+ PCEP_VTYSH_ARG_PORT, pce_opts->port);
+ }
+
+ if (pce_opts_cli->config_group_name[0] != '\0') {
+ vty_out(vty, " pce-config: %s\n",
+ pce_opts_cli->config_group_name);
+ }
+
+ char buf[1024] = "";
+ pcep_cli_print_pce_config(&pce_opts->config_opts, buf, sizeof(buf));
+ vty_out(vty, "%s", buf);
+}
+
+static int path_pcep_cli_show_srte_pcep_pce(struct vty *vty,
+ const char *pce_peer)
+{
+ /* Only show 1 PCE */
+ struct pce_opts_cli *pce_opts_cli;
+ if (pce_peer != NULL) {
+ pce_opts_cli = pcep_cli_find_pce(pce_peer);
+ if (pce_opts_cli == NULL) {
+ vty_out(vty, "%% PCE [%s] does not exist.\n", pce_peer);
+ return CMD_WARNING;
+ }
+
+ pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+ show_pce_peer(vty, pce_opts_cli);
+
+ return CMD_SUCCESS;
+ }
+
+ /* Show all PCEs */
+ for (int i = 0; i < MAX_PCE; i++) {
+ pce_opts_cli = pcep_g->pce_opts_cli[i];
+ if (pce_opts_cli == NULL) {
+ continue;
+ }
+
+ pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+ show_pce_peer(vty, pce_opts_cli);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_sr_draft07(struct vty *vty)
+{
+ struct pcep_config_group_opts *pce_config = NULL;
+
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_config = &current_pce_opts_g->pce_config_group_opts;
+ current_pce_opts_g->merged = false;
+ } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+ pce_config = current_pcep_config_group_opts_g;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ pce_config->draft07 = true;
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_pce_initiated(struct vty *vty)
+{
+ struct pcep_config_group_opts *pce_config = NULL;
+
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_config = &current_pce_opts_g->pce_config_group_opts;
+ current_pce_opts_g->merged = false;
+ } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+ pce_config = current_pcep_config_group_opts_g;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ pce_config->pce_initiated = true;
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty,
+ const char *tcp_md5_auth)
+{
+ struct pcep_config_group_opts *pce_config = NULL;
+
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_config = &current_pce_opts_g->pce_config_group_opts;
+ current_pce_opts_g->merged = false;
+ } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+ pce_config = current_pcep_config_group_opts_g;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth,
+ sizeof(pce_config->tcp_md5_auth));
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_address(struct vty *vty, const char *ip_str,
+ struct in_addr *ip, const char *ipv6_str,
+ struct in6_addr *ipv6,
+ const char *port_str, long port)
+{
+ struct pce_opts *pce_opts = NULL;
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_opts = &current_pce_opts_g->pce_opts;
+ current_pce_opts_g->merged = false;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (ipv6_str != NULL) {
+ pce_opts->addr.ipa_type = IPADDR_V6;
+ memcpy(&pce_opts->addr.ipaddr_v6, ipv6,
+ sizeof(struct in6_addr));
+ } else if (ip_str != NULL) {
+ pce_opts->addr.ipa_type = IPADDR_V4;
+ memcpy(&pce_opts->addr.ipaddr_v4, ip, sizeof(struct in_addr));
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Handle the optional port */
+ pce_opts->port = PCEP_DEFAULT_PORT;
+ PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_opts->port, 0, 65535);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_source_address(struct vty *vty,
+ const char *ip_str,
+ struct in_addr *ip,
+ const char *ipv6_str,
+ struct in6_addr *ipv6,
+ const char *port_str, long port)
+{
+ struct pcep_config_group_opts *pce_config = NULL;
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_config = &current_pce_opts_g->pce_config_group_opts;
+ current_pce_opts_g->merged = false;
+ } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+ pce_config = current_pcep_config_group_opts_g;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Handle the optional source IP */
+ if (ipv6_str != NULL) {
+ pce_config->source_ip.ipa_type = IPADDR_V6;
+ memcpy(&pce_config->source_ip.ipaddr_v6, ipv6,
+ sizeof(struct in6_addr));
+ } else if (ip_str != NULL) {
+ pce_config->source_ip.ipa_type = IPADDR_V4;
+ memcpy(&pce_config->source_ip.ipaddr_v4, ip,
+ sizeof(struct in_addr));
+ }
+
+ /* Handle the optional port */
+ PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_config->source_port, 0,
+ 65535);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_pcep_pce_config_ref(struct vty *vty,
+ const char *config_group_name)
+{
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ current_pce_opts_g->merged = false;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ struct pcep_config_group_opts *pce_config =
+ pcep_cli_find_pcep_pce_config(config_group_name);
+ if (pce_config == NULL) {
+ vty_out(vty, "%% pce-config [%s] does not exist.\n",
+ config_group_name);
+ return CMD_WARNING;
+ }
+
+ strlcpy(current_pce_opts_g->config_group_name, config_group_name,
+ sizeof(current_pce_opts_g->config_group_name));
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_timers(
+ struct vty *vty, const char *keep_alive_str, long keep_alive,
+ const char *min_peer_keep_alive_str, long min_peer_keep_alive,
+ const char *max_peer_keep_alive_str, long max_peer_keep_alive,
+ const char *dead_timer_str, long dead_timer,
+ const char *min_peer_dead_timer_str, long min_peer_dead_timer,
+ const char *max_peer_dead_timer_str, long max_peer_dead_timer,
+ const char *pcep_request_str, long pcep_request,
+ const char *session_timeout_interval_str, long session_timeout_interval,
+ const char *delegation_timeout_str, long delegation_timeout)
+{
+ struct pcep_config_group_opts *pce_config = NULL;
+ if (vty->node == PCEP_PCE_NODE) {
+ /* TODO need to see if the pce is in use, and reset the
+ * connection */
+ pce_config = &current_pce_opts_g->pce_config_group_opts;
+ current_pce_opts_g->merged = false;
+ } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+ pce_config = current_pcep_config_group_opts_g;
+ } else {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (min_peer_keep_alive && max_peer_keep_alive)
+ if (min_peer_keep_alive >= max_peer_keep_alive) {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (min_peer_dead_timer && max_peer_dead_timer)
+ if (min_peer_dead_timer >= max_peer_dead_timer) {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Handle the arguments */
+ PCEP_VTYSH_INT_ARG_CHECK(keep_alive_str, keep_alive,
+ pce_config->keep_alive_seconds, 0, 64);
+ PCEP_VTYSH_INT_ARG_CHECK(min_peer_keep_alive_str, min_peer_keep_alive,
+ pce_config->min_keep_alive_seconds, 0, 256);
+ PCEP_VTYSH_INT_ARG_CHECK(max_peer_keep_alive_str, max_peer_keep_alive,
+ pce_config->max_keep_alive_seconds, 0, 256);
+ PCEP_VTYSH_INT_ARG_CHECK(dead_timer_str, dead_timer,
+ pce_config->dead_timer_seconds, 3, 256);
+ PCEP_VTYSH_INT_ARG_CHECK(min_peer_dead_timer_str, min_peer_dead_timer,
+ pce_config->min_dead_timer_seconds, 3, 256);
+ PCEP_VTYSH_INT_ARG_CHECK(max_peer_dead_timer_str, max_peer_dead_timer,
+ pce_config->max_dead_timer_seconds, 3, 256);
+ PCEP_VTYSH_INT_ARG_CHECK(pcep_request_str, pcep_request,
+ pce_config->pcep_request_time_seconds, 0, 121);
+ PCEP_VTYSH_INT_ARG_CHECK(
+ session_timeout_interval_str, session_timeout_interval,
+ pce_config->session_timeout_inteval_seconds, 0, 121);
+ PCEP_VTYSH_INT_ARG_CHECK(delegation_timeout_str, delegation_timeout,
+ pce_config->delegation_timeout_seconds, 0, 61);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc(struct vty *vty)
+{
+ VTY_PUSH_CONTEXT_NULL(PCEP_PCC_NODE);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_delete(struct vty *vty)
+{
+ /* Clear the pce_connections */
+ memset(&pce_connections_g, 0, sizeof(pce_connections_g));
+ pcc_msd_configured_g = false;
+
+ pcep_ctrl_remove_pcc(pcep_g->fpt, NULL);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_msd(struct vty *vty, const char *msd_str,
+ long msd)
+{
+ pcc_msd_configured_g = true;
+ PCEP_VTYSH_INT_ARG_CHECK(msd_str, msd, pcc_msd_g, 0, 33);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name,
+ const char *precedence_str,
+ long precedence)
+{
+ /* Check if the pcc-peer exists */
+ struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
+ if (pce_opts_cli == NULL) {
+ vty_out(vty, "%% PCE [%s] does not exist.\n", peer_name);
+ return CMD_WARNING;
+ }
+ struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+
+ /* Check if the pcc-peer is duplicated */
+ if (pcep_cli_pcc_has_pce(peer_name)) {
+ vty_out(vty, "%% The peer [%s] has already been configured.\n",
+ peer_name);
+ return CMD_WARNING;
+ }
+
+ /* Get the optional precedence argument */
+ pce_opts->precedence = DEFAULT_PCE_PRECEDENCE;
+ PCEP_VTYSH_INT_ARG_CHECK(precedence_str, precedence,
+ pce_opts->precedence, 0, 256);
+
+ /* Finalize the pce_opts config values */
+ pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+ pcep_cli_add_pce_connection(&pce_opts_cli->pce_opts);
+
+ /* Verify the PCE has the IP set */
+ struct in6_addr zero_v6_addr;
+ memset(&zero_v6_addr, 0, sizeof(zero_v6_addr));
+ if (memcmp(&pce_opts->addr.ip, &zero_v6_addr, IPADDRSZ(&pce_opts->addr))
+ == 0) {
+ vty_out(vty,
+ "%% The peer [%s] does not have an IP set and cannot be used until it does.\n",
+ peer_name);
+ return CMD_WARNING;
+ }
+
+ /* Update the pcc_opts with the source ip, port, and msd */
+ struct pcc_opts *pcc_opts_copy =
+ XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts));
+ memcpy(&pcc_opts_copy->addr,
+ &pce_opts_cli->pce_opts.config_opts.source_ip,
+ sizeof(pcc_opts_copy->addr));
+ pcc_opts_copy->msd = pcc_msd_g;
+ pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port;
+ if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) {
+ return CMD_WARNING;
+ }
+
+ /* Send a copy of the pce_opts, this one is only used for the CLI */
+ struct pce_opts *pce_opts_copy =
+ XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
+ memcpy(pce_opts_copy, pce_opts, sizeof(struct pce_opts));
+ if (pcep_ctrl_update_pce_options(pcep_g->fpt, pce_opts_copy)) {
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
+ const char *peer_name,
+ const char *precedence_str,
+ long precedence)
+{
+ /* Check if the pcc-peer is connected to the PCC */
+ if (!pcep_cli_pcc_has_pce(peer_name)) {
+ vty_out(vty,
+ "%% WARN: The peer [%s] is not connected to the PCC.\n",
+ peer_name);
+ return CMD_WARNING;
+ }
+
+ struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
+ pcep_cli_remove_pce_connection(&pce_opts_cli->pce_opts);
+
+ /* Send a copy of the pce_opts, this one is used for CLI only */
+ struct pce_opts *pce_opts_copy =
+ XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
+ memcpy(pce_opts_copy, &pce_opts_cli->pce_opts, sizeof(struct pce_opts));
+ pcep_ctrl_remove_pcc(pcep_g->fpt, pce_opts_copy);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_pcc(struct vty *vty)
+{
+ vty_out(vty, "pcc msd %d\n", pcc_msd_g);
+
+ return CMD_SUCCESS;
+}
+
+/* Internal util function to print pcep capabilities to a buffer */
+static void print_pcep_capabilities(char *buf, size_t buf_len,
+ pcep_configuration *config)
+{
+ if (config->support_stateful_pce_lsp_update) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_STATEFUL);
+ }
+ if (config->support_include_db_version) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_INCL_DB_VER);
+ }
+ if (config->support_lsp_triggered_resync) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_TRIGGERED);
+ }
+ if (config->support_lsp_delta_sync) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_DELTA);
+ }
+ if (config->support_pce_triggered_initial_sync) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCE_TRIGGERED);
+ }
+ if (config->support_sr_te_pst) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_SR_TE_PST);
+ }
+ if (config->pcc_can_resolve_nai_to_sid) {
+ csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCC_RESOLVE_NAI);
+ }
+}
+
+/* Internal util function to print a pcep session */
+static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
+ struct pcep_pcc_info *pcc_info)
+{
+ char buf[1024];
+ buf[0] = '\0';
+
+ vty_out(vty, "\nPCE %s\n", pce_opts->pce_name);
+
+ /* PCE IP */
+ if (IS_IPADDR_V4(&pce_opts->addr)) {
+ vty_out(vty, " PCE IP %pI4 port %d\n",
+ &pce_opts->addr.ipaddr_v4, pce_opts->port);
+ } else if (IS_IPADDR_V6(&pce_opts->addr)) {
+ vty_out(vty, " PCE IPv6 %pI6 port %d\n",
+ &pce_opts->addr.ipaddr_v6, pce_opts->port);
+ }
+
+ /* PCC IP */
+ if (IS_IPADDR_V4(&pcc_info->pcc_addr)) {
+ vty_out(vty, " PCC IP %pI4 port %d\n",
+ &pcc_info->pcc_addr.ipaddr_v4, pcc_info->pcc_port);
+ } else if (IS_IPADDR_V6(&pcc_info->pcc_addr)) {
+ vty_out(vty, " PCC IPv6 %pI6 port %d\n",
+ &pcc_info->pcc_addr.ipaddr_v6, pcc_info->pcc_port);
+ }
+ vty_out(vty, " PCC MSD %d\n", pcc_info->msd);
+
+ if (pcc_info->status == PCEP_PCC_OPERATING) {
+ vty_out(vty, " Session Status UP\n");
+ } else {
+ vty_out(vty, " Session Status %s\n",
+ pcc_status_name(pcc_info->status));
+ }
+
+ if (pcc_info->is_best_multi_pce) {
+ vty_out(vty, " Precedence %d, best candidate\n",
+ ((pcc_info->precedence > 0) ? pcc_info->precedence
+ : DEFAULT_PCE_PRECEDENCE));
+ } else {
+ vty_out(vty, " Precedence %d\n",
+ ((pcc_info->precedence > 0) ? pcc_info->precedence
+ : DEFAULT_PCE_PRECEDENCE));
+ }
+ vty_out(vty, " Confidence %s\n",
+ ((pcc_info->previous_best) ? "low"
+ : "normal"));
+
+ /* PCEPlib pcep session values, get a thread safe copy of the counters
+ */
+ pcep_session *session =
+ pcep_ctrl_get_pcep_session(pcep_g->fpt, pcc_info->pcc_id);
+
+ /* Config Options values */
+ struct pcep_config_group_opts *config_opts = &pce_opts->config_opts;
+ if (session != NULL) {
+ vty_out(vty, " Timer: KeepAlive config %d, pce-negotiated %d\n",
+ config_opts->keep_alive_seconds,
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds);
+ vty_out(vty, " Timer: DeadTimer config %d, pce-negotiated %d\n",
+ config_opts->dead_timer_seconds,
+ session->pcc_config.dead_timer_pce_negotiated_seconds);
+ } else {
+ vty_out(vty, " Timer: KeepAlive %d\n",
+ config_opts->keep_alive_seconds);
+ vty_out(vty, " Timer: DeadTimer %d\n",
+ config_opts->dead_timer_seconds);
+ }
+ vty_out(vty, " Timer: PcRequest %d\n",
+ config_opts->pcep_request_time_seconds);
+ vty_out(vty, " Timer: SessionTimeout Interval %d\n",
+ config_opts->session_timeout_inteval_seconds);
+ vty_out(vty, " Timer: Delegation Timeout %d\n",
+ config_opts->delegation_timeout_seconds);
+ if (strlen(config_opts->tcp_md5_auth) > 0) {
+ vty_out(vty, " TCP MD5 Auth Str: %s\n",
+ config_opts->tcp_md5_auth);
+ } else {
+ vty_out(vty, " No TCP MD5 Auth\n");
+ }
+
+ if (config_opts->draft07) {
+ vty_out(vty, " PCE SR Version draft07\n");
+ } else {
+ vty_out(vty, " PCE SR Version draft16 and RFC8408\n");
+ }
+
+ vty_out(vty, " Next PcReq ID %d\n", pcc_info->next_reqid);
+ vty_out(vty, " Next PLSP ID %d\n", pcc_info->next_plspid);
+
+ if (session != NULL) {
+ if (pcc_info->status == PCEP_PCC_SYNCHRONIZING
+ || pcc_info->status == PCEP_PCC_OPERATING) {
+ time_t current_time = time(NULL);
+ struct tm lt = {0};
+ /* Just for the timezone */
+ localtime_r(&current_time, &lt);
+ gmtime_r(&session->time_connected, &lt);
+ vty_out(vty,
+ " Connected for %u seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
+ (uint32_t)(current_time
+ - session->time_connected),
+ lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
+ lt.tm_hour, lt.tm_min, lt.tm_sec);
+ }
+
+ /* PCC capabilities */
+ buf[0] = '\0';
+ int index = 0;
+ if (config_opts->pce_initiated) {
+ index += csnprintfrr(buf, sizeof(buf), "%s",
+ PCEP_CLI_CAP_PCC_PCE_INITIATED);
+ } else {
+ index += csnprintfrr(buf, sizeof(buf), "%s",
+ PCEP_CLI_CAP_PCC_INITIATED);
+ }
+ print_pcep_capabilities(buf, sizeof(buf) - index,
+ &session->pcc_config);
+ vty_out(vty, " PCC Capabilities:%s\n", buf);
+
+ /* PCE capabilities */
+ buf[0] = '\0';
+ print_pcep_capabilities(buf, sizeof(buf), &session->pce_config);
+ if (buf[0] != '\0') {
+ vty_out(vty, " PCE Capabilities:%s\n", buf);
+ }
+ XFREE(MTYPE_PCEP, session);
+ } else {
+ vty_out(vty, " Detailed session information not available\n");
+ }
+
+ /* Message Counters, get a thread safe copy of the counters */
+ struct counters_group *group =
+ pcep_ctrl_get_counters(pcep_g->fpt, pcc_info->pcc_id);
+
+ if (group != NULL) {
+ struct counters_subgroup *rx_msgs =
+ find_subgroup(group, COUNTER_SUBGROUP_ID_RX_MSG);
+ struct counters_subgroup *tx_msgs =
+ find_subgroup(group, COUNTER_SUBGROUP_ID_TX_MSG);
+
+ if (rx_msgs != NULL && tx_msgs != NULL) {
+ vty_out(vty, " PCEP Message Statistics\n");
+ vty_out(vty, " %27s %6s\n", "Sent", "Rcvd");
+ for (int i = 0; i < rx_msgs->max_counters; i++) {
+ struct counter *rx_counter =
+ rx_msgs->counters[i];
+ struct counter *tx_counter =
+ tx_msgs->counters[i];
+ if (rx_counter != NULL && tx_counter != NULL) {
+ vty_out(vty, " %20s: %5d %5d\n",
+ tx_counter->counter_name,
+ tx_counter->counter_value,
+ rx_counter->counter_value);
+ }
+ }
+ vty_out(vty, " %20s: %5d %5d\n", "Total",
+ subgroup_counters_total(tx_msgs),
+ subgroup_counters_total(rx_msgs));
+ }
+ pcep_lib_free_counters(group);
+ } else {
+ vty_out(vty, " Counters not available\n");
+ }
+
+ XFREE(MTYPE_PCEP, pcc_info);
+}
+
+static int path_pcep_cli_show_srte_pcep_session(struct vty *vty,
+ const char *pcc_peer)
+{
+ struct pce_opts_cli *pce_opts_cli;
+ struct pcep_pcc_info *pcc_info;
+
+ /* Only show 1 PCEP session */
+ if (pcc_peer != NULL) {
+ pce_opts_cli = pcep_cli_find_pce(pcc_peer);
+ if (pce_opts_cli == NULL) {
+ vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
+ return CMD_WARNING;
+ }
+
+ if (!pcep_cli_pcc_has_pce(pcc_peer)) {
+ vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
+ pcc_peer);
+ return CMD_WARNING;
+ }
+
+ pcc_info = pcep_ctrl_get_pcc_info(pcep_g->fpt, pcc_peer);
+ if (pcc_info == NULL) {
+ vty_out(vty,
+ "%% Cannot retrieve PCEP session info for PCE [%s]\n",
+ pcc_peer);
+ return CMD_WARNING;
+ }
+
+ print_pcep_session(vty, &pce_opts_cli->pce_opts, pcc_info);
+
+ return CMD_SUCCESS;
+ }
+
+ /* Show all PCEP sessions */
+ struct pce_opts *pce_opts;
+ int num_pcep_sessions_conf = 0;
+ int num_pcep_sessions_conn = 0;
+ for (int i = 0; i < MAX_PCC; i++) {
+ pce_opts = pce_connections_g.connections[i];
+ if (pce_opts == NULL) {
+ continue;
+ }
+
+ pcc_info =
+ pcep_ctrl_get_pcc_info(pcep_g->fpt, pce_opts->pce_name);
+ if (pcc_info == NULL) {
+ vty_out(vty,
+ "%% Cannot retrieve PCEP session info for PCE [%s]\n",
+ pce_opts->pce_name);
+ continue;
+ }
+
+ num_pcep_sessions_conn +=
+ pcc_info->status == PCEP_PCC_OPERATING ? 1 : 0;
+ num_pcep_sessions_conf++;
+ print_pcep_session(vty, pce_opts, pcc_info);
+ }
+
+ vty_out(vty, "PCEP Sessions => Configured %d ; Connected %d\n",
+ num_pcep_sessions_conf, num_pcep_sessions_conn);
+
+ return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_clear_srte_pcep_session(struct vty *vty,
+ const char *pcc_peer)
+{
+ struct pce_opts_cli *pce_opts_cli;
+
+ /* Only clear 1 PCEP session */
+ if (pcc_peer != NULL) {
+ pce_opts_cli = pcep_cli_find_pce(pcc_peer);
+ if (pce_opts_cli == NULL) {
+ vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
+ return CMD_WARNING;
+ }
+
+ if (!pcep_cli_pcc_has_pce(pcc_peer)) {
+ vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
+ pcc_peer);
+ return CMD_WARNING;
+ }
+
+ pcep_ctrl_reset_pcc_session(pcep_g->fpt,
+ pce_opts_cli->pce_opts.pce_name);
+ vty_out(vty, "PCEP session cleared for peer %s\n", pcc_peer);
+
+ return CMD_SUCCESS;
+ }
+
+ /* Clear all PCEP sessions */
+ struct pce_opts *pce_opts;
+ int num_pcep_sessions = 0;
+ for (int i = 0; i < MAX_PCC; i++) {
+ pce_opts = pce_connections_g.connections[i];
+ if (pce_opts == NULL) {
+ continue;
+ }
+
+ num_pcep_sessions++;
+ pcep_ctrl_reset_pcc_session(pcep_g->fpt, pce_opts->pce_name);
+ vty_out(vty, "PCEP session cleared for peer %s\n",
+ pce_opts->pce_name);
+ }
+
+ vty_out(vty, "Cleared [%d] PCEP sessions\n", num_pcep_sessions);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Config Write functions
+ */
+
+int pcep_cli_debug_config_write(struct vty *vty)
+{
+ char buff[128] = "";
+
+ if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
+ csnprintfrr(buff, sizeof(buff), " %s",
+ PCEP_VTYSH_ARG_BASIC);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
+ csnprintfrr(buff, sizeof(buff), " %s",
+ PCEP_VTYSH_ARG_PATH);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
+ csnprintfrr(buff, sizeof(buff), " %s",
+ PCEP_VTYSH_ARG_MESSAGE);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
+ csnprintfrr(buff, sizeof(buff), " %s",
+ PCEP_VTYSH_ARG_PCEPLIB);
+ vty_out(vty, "debug pathd pcep%s\n", buff);
+ buff[0] = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int pcep_cli_debug_set_all(uint32_t flags, bool set)
+{
+ DEBUG_FLAGS_SET(&pcep_g->dbg, flags, set);
+
+ /* If all modes have been turned off, don't preserve options. */
+ if (!DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_ALL))
+ DEBUG_CLEAR(&pcep_g->dbg);
+
+ return 0;
+}
+
+int pcep_cli_pcep_config_write(struct vty *vty)
+{
+ vty_out(vty, " pcep\n");
+ pcep_cli_pcep_pce_config_write(vty);
+ pcep_cli_pce_config_write(vty);
+ pcep_cli_pcc_config_write(vty);
+ vty_out(vty, " exit\n");
+ return 1;
+}
+
+int pcep_cli_pcc_config_write(struct vty *vty)
+{
+ struct pce_opts *pce_opts;
+ char buf[128] = "";
+ int lines = 0;
+
+ /* The MSD, nor any PCE peers have been configured on the PCC */
+ if (!pcc_msd_configured_g && pce_connections_g.num_connections == 0) {
+ return lines;
+ }
+
+ vty_out(vty, " pcc\n");
+ lines++;
+
+ /* Prepare the MSD, if present */
+ if (pcc_msd_configured_g) {
+ vty_out(vty, " %s %d\n", PCEP_VTYSH_ARG_MSD, pcc_msd_g);
+ lines++;
+ }
+
+ if (pce_connections_g.num_connections == 0) {
+ goto exit;
+ }
+
+ buf[0] = 0;
+ for (int i = 0; i < MAX_PCC; i++) {
+ pce_opts = pce_connections_g.connections[i];
+ if (pce_opts == NULL) {
+ continue;
+ }
+
+ /* Only show the PCEs configured in the pcc sub-command */
+ if (!pcep_cli_pcc_has_pce(pce_opts->pce_name)) {
+ continue;
+ }
+
+ csnprintfrr(buf, sizeof(buf), " peer %s",
+ pce_opts->pce_name);
+ if (pce_opts->precedence > 0
+ && pce_opts->precedence != DEFAULT_PCE_PRECEDENCE) {
+ csnprintfrr(buf, sizeof(buf), " %s %d",
+ PCEP_VTYSH_ARG_PRECEDENCE,
+ pce_opts->precedence);
+ }
+ vty_out(vty, "%s\n", buf);
+ lines++;
+ buf[0] = 0;
+ }
+exit:
+ vty_out(vty, " exit\n");
+
+ return lines;
+}
+
+/* Internal function used by pcep_cli_pce_config_write()
+ * and pcep_cli_pcep_pce_config_write() */
+static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
+ char *buf, size_t buf_len)
+{
+ int lines = 0;
+
+ if (group_opts->source_ip.ipa_type != IPADDR_NONE
+ || group_opts->source_port != 0) {
+ csnprintfrr(buf, buf_len, " ");
+ if (IS_IPADDR_V4(&group_opts->source_ip)) {
+ csnprintfrr(buf, buf_len, " %s %s %pI4",
+ PCEP_VTYSH_ARG_SOURCE_ADDRESS,
+ PCEP_VTYSH_ARG_IP,
+ &group_opts->source_ip.ipaddr_v4);
+ } else if (IS_IPADDR_V6(&group_opts->source_ip)) {
+ csnprintfrr(buf, buf_len, " %s %s %pI6",
+ PCEP_VTYSH_ARG_SOURCE_ADDRESS,
+ PCEP_VTYSH_ARG_IPV6,
+ &group_opts->source_ip.ipaddr_v6);
+ }
+ if (group_opts->source_port > 0) {
+ csnprintfrr(buf, buf_len, " %s %d", PCEP_VTYSH_ARG_PORT,
+ group_opts->source_port);
+ }
+ csnprintfrr(buf, buf_len, "\n");
+ lines++;
+ }
+ /* Group the keep-alive together for devman */
+ if ((group_opts->keep_alive_seconds > 0)
+ || (group_opts->min_keep_alive_seconds > 0)
+ || (group_opts->max_keep_alive_seconds > 0)) {
+ csnprintfrr(buf, buf_len, " %s", PCEP_VTYSH_ARG_TIMER);
+
+ if (group_opts->keep_alive_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_KEEP_ALIVE,
+ group_opts->keep_alive_seconds);
+ }
+ if (group_opts->min_keep_alive_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_KEEP_ALIVE_MIN,
+ group_opts->min_keep_alive_seconds);
+ }
+ if (group_opts->max_keep_alive_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_KEEP_ALIVE_MAX,
+ group_opts->max_keep_alive_seconds);
+ }
+ csnprintfrr(buf, buf_len, "\n");
+ lines++;
+ }
+
+ /* Group the dead-timer together for devman */
+ if ((group_opts->dead_timer_seconds > 0)
+ || (group_opts->min_dead_timer_seconds > 0)
+ || (group_opts->max_dead_timer_seconds > 0)) {
+ csnprintfrr(buf, buf_len, " %s", PCEP_VTYSH_ARG_TIMER);
+
+ if (group_opts->dead_timer_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_DEAD_TIMER,
+ group_opts->dead_timer_seconds);
+ }
+ if (group_opts->min_dead_timer_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_DEAD_TIMER_MIN,
+ group_opts->min_dead_timer_seconds);
+ }
+ if (group_opts->max_dead_timer_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %d",
+ PCEP_VTYSH_ARG_DEAD_TIMER_MAX,
+ group_opts->max_dead_timer_seconds);
+ }
+ csnprintfrr(buf, buf_len, "\n");
+ lines++;
+ }
+
+ if (group_opts->pcep_request_time_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %s %d\n",
+ PCEP_VTYSH_ARG_TIMER, PCEP_VTYSH_ARG_PCEP_REQUEST,
+ group_opts->pcep_request_time_seconds);
+ lines++;
+ }
+ if (group_opts->delegation_timeout_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %s %d\n",
+ PCEP_VTYSH_ARG_TIMER,
+ PCEP_VTYSH_ARG_DELEGATION_TIMEOUT,
+ group_opts->delegation_timeout_seconds);
+ lines++;
+ }
+ if (group_opts->session_timeout_inteval_seconds > 0) {
+ csnprintfrr(buf, buf_len, " %s %s %d\n",
+ PCEP_VTYSH_ARG_TIMER,
+ PCEP_VTYSH_ARG_SESSION_TIMEOUT,
+ group_opts->session_timeout_inteval_seconds);
+ lines++;
+ }
+ if (group_opts->tcp_md5_auth[0] != '\0') {
+ csnprintfrr(buf, buf_len, " %s %s\n", PCEP_VTYSH_ARG_TCP_MD5,
+ group_opts->tcp_md5_auth);
+ lines++;
+ }
+ if (group_opts->draft07) {
+ csnprintfrr(buf, buf_len, " %s\n",
+ PCEP_VTYSH_ARG_SR_DRAFT07);
+ lines++;
+ }
+ if (group_opts->pce_initiated) {
+ csnprintfrr(buf, buf_len, " %s\n", PCEP_VTYSH_ARG_PCE_INIT);
+ lines++;
+ }
+
+ return lines;
+}
+
+int pcep_cli_pce_config_write(struct vty *vty)
+{
+ int lines = 0;
+ char buf[1024] = "";
+
+ for (int i = 0; i < MAX_PCE; i++) {
+ struct pce_opts_cli *pce_opts_cli = pcep_g->pce_opts_cli[i];
+ if (pce_opts_cli == NULL) {
+ continue;
+ }
+ struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+
+ vty_out(vty, " pce %s\n", pce_opts->pce_name);
+ if (IS_IPADDR_V6(&pce_opts->addr)) {
+ vty_out(vty, " %s %s %pI6", PCEP_VTYSH_ARG_ADDRESS,
+ PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6);
+ } else if (IS_IPADDR_V4(&pce_opts->addr)) {
+ vty_out(vty, " address %s %pI4", PCEP_VTYSH_ARG_IP,
+ &pce_opts->addr.ipaddr_v4);
+ }
+ if (pce_opts->port != PCEP_DEFAULT_PORT) {
+ vty_out(vty, " %s %d", PCEP_VTYSH_ARG_PORT,
+ pce_opts->port);
+ }
+ vty_out(vty, "%s\n", buf);
+ lines += 2;
+
+ if (pce_opts_cli->config_group_name[0] != '\0') {
+ vty_out(vty, " config %s\n",
+ pce_opts_cli->config_group_name);
+ lines++;
+ }
+
+ /* Only display the values configured on the PCE, not the values
+ * from its optional pce-config-group, nor the default values */
+ lines += pcep_cli_print_pce_config(
+ &pce_opts_cli->pce_config_group_opts, buf, sizeof(buf));
+
+ vty_out(vty, "%s", buf);
+ buf[0] = '\0';
+
+ vty_out(vty, " exit\n");
+ }
+
+ return lines;
+}
+
+int pcep_cli_pcep_pce_config_write(struct vty *vty)
+{
+ int lines = 0;
+ char buf[1024] = "";
+
+ for (int i = 0; i < MAX_PCE; i++) {
+ struct pcep_config_group_opts *group_opts =
+ pcep_g->config_group_opts[i];
+ if (group_opts == NULL) {
+ continue;
+ }
+
+ vty_out(vty, " pce-config %s\n", group_opts->name);
+ lines += 1;
+
+ lines +=
+ pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+ vty_out(vty, "%s", buf);
+ buf[0] = 0;
+
+ vty_out(vty, " exit\n");
+ }
+
+ return lines;
+}
+
+/*
+ * VTYSH command syntax definitions
+ * The param names are taken from the path_pcep_cli_clippy.c generated file.
+ */
+
+DEFPY(show_debugging_pathd_pcep,
+ show_debugging_pathd_pcep_cmd,
+ "show debugging pathd-pcep",
+ SHOW_STR
+ "State of each debugging option\n"
+ "pathd pcep module debugging\n")
+{
+ vty_out(vty, "Pathd pcep debugging status:\n");
+
+ if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
+ vty_out(vty, " Pathd pcep %s debugging is on\n",
+ PCEP_VTYSH_ARG_BASIC);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
+ vty_out(vty, " Pathd pcep %s debugging is on\n",
+ PCEP_VTYSH_ARG_PATH);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
+ vty_out(vty, " Pathd pcep %s debugging is on\n",
+ PCEP_VTYSH_ARG_MESSAGE);
+ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
+ vty_out(vty, " Pathd pcep %s debugging is on\n",
+ PCEP_VTYSH_ARG_PCEPLIB);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(pcep_cli_debug,
+ pcep_cli_debug_cmd,
+ "[no] debug pathd pcep [basic]$basic_str [path]$path_str [message]$message_str [pceplib]$pceplib_str",
+ NO_STR DEBUG_STR
+ "pathd debugging\n"
+ "pcep module debugging\n"
+ "module basic debugging\n"
+ "path structures debugging\n"
+ "pcep message debugging\n"
+ "pceplib debugging\n")
+{
+ return path_pcep_cli_debug(vty, no, basic_str, path_str, message_str,
+ pceplib_str);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_counters,
+ pcep_cli_show_srte_pcep_counters_cmd,
+ "show sr-te pcep counters",
+ SHOW_STR
+ "SR-TE info\n"
+ "PCEP info\n"
+ "PCEP counters\n")
+{
+ return path_pcep_cli_show_srte_pcep_counters(vty);
+}
+
+DEFPY_NOSH(
+ pcep_cli_pcep,
+ pcep_cli_pcep_cmd,
+ "pcep",
+ "PCEP configuration\n")
+{
+ vty->node = PCEP_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFPY_NOSH(
+ pcep_cli_pcep_pce_config,
+ pcep_cli_pcep_pce_config_cmd,
+ "pce-config WORD$name",
+ "Shared configuration\n"
+ "Shared configuration name\n")
+{
+ return path_pcep_cli_pcep_pce_config(vty, name);
+}
+
+DEFPY(pcep_cli_pcep_no_pce_config,
+ pcep_cli_pcep_no_pce_config_cmd,
+ "no pce-config WORD$name",
+ NO_STR
+ "Shared configuration\n"
+ "Shared configuration name\n")
+{
+ return path_pcep_cli_pcep_pce_config_delete(vty, name);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_pce_config,
+ pcep_cli_show_srte_pcep_pce_config_cmd,
+ "show sr-te pcep pce-config [<default|WORD>$name]",
+ SHOW_STR
+ "SR-TE info\n"
+ "PCEP info\n"
+ "Show shared PCE configuration\n"
+ "Show default hard-coded values\n"
+ "Shared configuration name\n")
+{
+ return path_pcep_cli_show_srte_pcep_pce_config(vty, name);
+}
+
+DEFPY_NOSH(
+ pcep_cli_pce,
+ pcep_cli_pce_cmd,
+ "pce WORD$name",
+ "PCE configuration, address sub-config is mandatory\n"
+ "PCE name\n")
+{
+ return path_pcep_cli_pce(vty, name);
+}
+
+DEFPY(pcep_cli_no_pce,
+ pcep_cli_no_pce_cmd,
+ "no pce WORD$name",
+ NO_STR
+ "PCE configuration, address sub-config is mandatory\n"
+ "PCE name\n")
+{
+ return path_pcep_cli_pce_delete(vty, name);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_pce,
+ pcep_cli_show_srte_pcep_pce_cmd,
+ "show sr-te pcep pce [WORD$name]",
+ SHOW_STR
+ "SR-TE info\n"
+ "PCEP info\n"
+ "Show detailed pce values\n"
+ "pce name\n")
+{
+ return path_pcep_cli_show_srte_pcep_pce(vty, name);
+}
+
+DEFPY(pcep_cli_peer_sr_draft07,
+ pcep_cli_peer_sr_draft07_cmd,
+ "sr-draft07",
+ "Configure PCC to send PCEP Open with SR draft07\n")
+{
+ return path_pcep_cli_peer_sr_draft07(vty);
+}
+
+DEFPY(pcep_cli_peer_pce_initiated,
+ pcep_cli_peer_pce_initiated_cmd,
+ "pce-initiated",
+ "Configure PCC to accept PCE initiated LSPs\n")
+{
+ return path_pcep_cli_peer_pce_initiated(vty);
+}
+
+DEFPY(pcep_cli_peer_tcp_md5_auth,
+ pcep_cli_peer_tcp_md5_auth_cmd,
+ "tcp-md5-auth WORD",
+ "Configure PCC TCP-MD5 RFC2385 Authentication\n"
+ "TCP-MD5 Authentication string\n")
+{
+ return path_pcep_cli_peer_tcp_md5_auth(vty, tcp_md5_auth);
+}
+
+DEFPY(pcep_cli_peer_address,
+ pcep_cli_peer_address_cmd,
+ "address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)]",
+ "PCE IP Address configuration, mandatory configuration\n"
+ "PCE IPv4 address\n"
+ "Remote PCE server IPv4 address\n"
+ "PCE IPv6 address\n"
+ "Remote PCE server IPv6 address\n"
+ "Remote PCE server port\n"
+ "Remote PCE server port value\n")
+{
+ return path_pcep_cli_peer_address(vty, ip_str, &ip, ipv6_str, &ipv6,
+ port_str, port);
+}
+
+DEFPY(pcep_cli_peer_source_address,
+ pcep_cli_peer_source_address_cmd,
+ "source-address [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)]",
+ "PCE source IP Address configuration\n"
+ "PCE source IPv4 address\n"
+ "PCE source IPv4 address value\n"
+ "PCE source IPv6 address\n"
+ "PCE source IPv6 address value\n"
+ "Source PCE server port\n"
+ "Source PCE server port value\n")
+{
+ return path_pcep_cli_peer_source_address(vty, ip_str, &ip, ipv6_str,
+ &ipv6, port_str, port);
+}
+
+DEFPY(pcep_cli_peer_pcep_pce_config_ref,
+ pcep_cli_peer_pcep_pce_config_ref_cmd,
+ "config WORD$name",
+ "PCE shared configuration to use\n"
+ "Shared configuration name\n")
+{
+ return path_pcep_cli_peer_pcep_pce_config_ref(vty, name);
+}
+
+DEFPY(pcep_cli_peer_timers,
+ pcep_cli_peer_timers_cmd,
+ "timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] "
+ "[dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] "
+ "[pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)]",
+ "PCE PCEP Session Timers configuration\n"
+ "PCC Keep Alive Timer\n"
+ "PCC Keep Alive Timer value in seconds\n"
+ "Min Acceptable PCE Keep Alive Timer\n"
+ "Min Acceptable PCE Keep Alive Timer value in seconds\n"
+ "Max Acceptable PCE Keep Alive Timer\n"
+ "Max Acceptable PCE Keep Alive Timer value in seconds\n"
+ "PCC Dead Timer\n"
+ "PCC Dead Timer value in seconds\n"
+ "Min Acceptable PCE Dead Timer\n"
+ "Min Acceptable PCE Dead Timer value in seconds\n"
+ "Max Acceptable PCE Dead Timer\n"
+ "Max Acceptable PCE Dead Timer value in seconds\n"
+ "PCC PCEP Request Timer\n"
+ "PCC PCEP Request Timer value in seconds\n"
+ "PCC Session Timeout Interval\n"
+ "PCC Session Timeout Interval value in seconds\n"
+ "Multi-PCE delegation timeout\n"
+ "Multi-PCE delegation timeout value in seconds\n")
+{
+ return path_pcep_cli_peer_timers(
+ vty, keep_alive_str, keep_alive, min_peer_keep_alive_str,
+ min_peer_keep_alive, max_peer_keep_alive_str,
+ max_peer_keep_alive, dead_timer_str, dead_timer,
+ min_peer_dead_timer_str, min_peer_dead_timer,
+ max_peer_dead_timer_str, max_peer_dead_timer, pcep_request_str,
+ pcep_request, session_timeout_interval_str,
+ session_timeout_interval, delegation_timeout_str,
+ delegation_timeout);
+}
+
+DEFPY_NOSH(
+ pcep_cli_pcc,
+ pcep_cli_pcc_cmd,
+ "pcc",
+ "PCC configuration\n")
+{
+ return path_pcep_cli_pcc(vty);
+}
+
+DEFPY(pcep_cli_no_pcc,
+ pcep_cli_no_pcc_cmd,
+ "no pcc",
+ NO_STR
+ "PCC configuration\n")
+{
+ return path_pcep_cli_pcc_delete(vty);
+}
+
+DEFPY(pcep_cli_pcc_pcc_msd,
+ pcep_cli_pcc_pcc_msd_cmd,
+ "msd (1-32)",
+ "PCC maximum SID depth \n"
+ "PCC maximum SID depth value\n")
+{
+ return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd);
+}
+
+DEFPY(pcep_cli_pcc_pcc_peer,
+ pcep_cli_pcc_pcc_peer_cmd,
+ "[no] peer WORD [precedence (1-255)]",
+ NO_STR
+ "PCC PCE peer\n"
+ "PCC PCE name\n"
+ "PCC Multi-PCE precedence\n"
+ "PCE precedence\n")
+{
+ if (no != NULL) {
+ return path_pcep_cli_pcc_pcc_peer_delete(
+ vty, peer, precedence_str, precedence);
+ } else {
+ return path_pcep_cli_pcc_pcc_peer(vty, peer, precedence_str,
+ precedence);
+ }
+}
+
+DEFPY(pcep_cli_show_srte_pcc,
+ pcep_cli_show_srte_pcc_cmd,
+ "show sr-te pcep pcc",
+ SHOW_STR
+ "SR-TE info\n"
+ "PCEP info\n"
+ "Show current PCC configuration\n")
+{
+ return path_pcep_cli_show_srte_pcep_pcc(vty);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_session,
+ pcep_cli_show_srte_pcep_session_cmd,
+ "show sr-te pcep session [WORD]$pce",
+ SHOW_STR
+ "SR-TE info\n"
+ "PCEP info\n"
+ "Show PCEP Session information\n"
+ "PCE name\n")
+{
+ return path_pcep_cli_show_srte_pcep_session(vty, pce);
+}
+
+DEFPY(pcep_cli_clear_srte_pcep_session,
+ pcep_cli_clear_srte_pcep_session_cmd,
+ "clear sr-te pcep session [WORD]$pce",
+ CLEAR_STR
+ "SR-TE\n"
+ "PCEP\n"
+ "Reset PCEP connection\n"
+ "PCE name\n")
+{
+ return path_pcep_cli_clear_srte_pcep_session(vty, pce);
+}
+
+void pcep_cli_init(void)
+{
+ hook_register(pathd_srte_config_write, pcep_cli_pcep_config_write);
+ hook_register(nb_client_debug_config_write,
+ pcep_cli_debug_config_write);
+ hook_register(nb_client_debug_set_all, pcep_cli_debug_set_all);
+
+ memset(&pce_connections_g, 0, sizeof(pce_connections_g));
+
+ install_node(&pcep_node);
+ install_node(&pcep_pcc_node);
+ install_node(&pcep_pce_node);
+ install_node(&pcep_pce_config_node);
+
+ install_default(PCEP_PCE_CONFIG_NODE);
+ install_default(PCEP_PCE_NODE);
+ install_default(PCEP_PCC_NODE);
+ install_default(PCEP_NODE);
+
+ install_element(SR_TRAFFIC_ENG_NODE, &pcep_cli_pcep_cmd);
+
+ /* PCEP configuration group related configuration commands */
+ install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
+ install_element(PCEP_NODE, &pcep_cli_pcep_no_pce_config_cmd);
+ install_element(PCEP_PCE_CONFIG_NODE,
+ &pcep_cli_peer_source_address_cmd);
+ install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_timers_cmd);
+ install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_sr_draft07_cmd);
+ install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_pce_initiated_cmd);
+ install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
+
+ /* PCE peer related configuration commands */
+ install_element(PCEP_NODE, &pcep_cli_pce_cmd);
+ install_element(PCEP_NODE, &pcep_cli_no_pce_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_address_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_source_address_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_pcep_pce_config_ref_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_timers_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_sr_draft07_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_pce_initiated_cmd);
+ install_element(PCEP_PCE_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
+
+ /* PCC related configuration commands */
+ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcc_cmd);
+ install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
+ install_element(PCEP_NODE, &pcep_cli_no_pcc_cmd);
+ install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd);
+ install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_msd_cmd);
+
+ /* Top commands */
+ install_element(CONFIG_NODE, &pcep_cli_debug_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_debug_cmd);
+ install_element(ENABLE_NODE, &show_debugging_pathd_pcep_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_counters_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_config_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_session_cmd);
+ install_element(ENABLE_NODE, &pcep_cli_clear_srte_pcep_session_cmd);
+}