diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 5cead0ce5df5..251d8b7543f2 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -19,6 +19,7 @@ #include #include +#include #include "log.h" #include "command.h" @@ -37,8 +38,10 @@ #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_nb.h" +#include "pathd/path_pcep_pcc.h" #ifndef VTYSH_EXTRACT_PL #include "pathd/path_pcep_cli_clippy.c" @@ -52,8 +55,8 @@ #define DEFAULT_TIMER_KEEP_ALIVE_MIN 1 #define DEFAULT_TIMER_KEEP_ALIVE_MAX 120 #define DEFAULT_TIMER_DEADTIMER 120 -#define DEFAULT_TIMER_DEADTIMER_MIN 60 -#define DEFAULT_TIMER_DEADTIMER_MAX 240 +#define DEFAULT_TIMER_DEADTIMER_MIN 4 +#define DEFAULT_TIMER_DEADTIMER_MAX 480 #define DEFAULT_TIMER_PCEP_REQUEST 30 #define DEFAULT_TIMER_TIMEOUT_INTERVAL 30 #define DEFAULT_DELEGATION_TIMEOUT_INTERVAL 30 @@ -83,6 +86,8 @@ static void pcep_cli_delete_pcep_config_group(const char *group_name); static int pcep_cli_print_config_group(struct pcep_config_group_opts *group_opts, char *buf); +static void print_pcep_capabilities(char *buf, pcep_configuration *config); +static void print_pcep_session(struct vty *vty, struct pcc_state *pcc_state); /* * Globals. @@ -110,6 +115,18 @@ 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]"; /* Default PCE group that all PCE-Groups and PCEs will inherit from */ struct pcep_config_group_opts default_pcep_config_group_opts = { @@ -802,9 +819,9 @@ static int path_pcep_cli_peer_timers( PCEP_VTYSH_INT_ARG_CHECK(dead_timer_str, dead_timer, config_group->dead_timer_seconds, 0, 241); PCEP_VTYSH_INT_ARG_CHECK(min_peer_dead_timer_str, min_peer_dead_timer, - config_group->min_dead_timer_seconds, 0, 61); + config_group->min_dead_timer_seconds, 3, 61); PCEP_VTYSH_INT_ARG_CHECK(max_peer_dead_timer_str, max_peer_dead_timer, - config_group->max_dead_timer_seconds, 59, 241); + config_group->max_dead_timer_seconds, 59, 481); PCEP_VTYSH_INT_ARG_CHECK(pcep_request_str, pcep_request, config_group->pcep_request_time_seconds, 0, 121); @@ -947,6 +964,217 @@ static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty, return CMD_SUCCESS; } +/* Internal util function to print pcep capabilities to a buffer */ +static void print_pcep_capabilities(char *buf, pcep_configuration *config) +{ + int index = 0; + if (config->support_stateful_pce_lsp_update) { + index += snprintf(buf + index, strlen(PCEP_CLI_CAP_STATEFUL), + PCEP_CLI_CAP_STATEFUL); + } + if (config->support_include_db_version) { + index += snprintf(buf + index, strlen(PCEP_CLI_CAP_INCL_DB_VER), + PCEP_CLI_CAP_INCL_DB_VER); + } + if (config->support_lsp_triggered_resync) { + index += snprintf(buf + index, + strlen(PCEP_CLI_CAP_LSP_TRIGGERED), + PCEP_CLI_CAP_LSP_TRIGGERED); + } + if (config->support_lsp_delta_sync) { + index += snprintf(buf + index, strlen(PCEP_CLI_CAP_LSP_DELTA), + PCEP_CLI_CAP_LSP_DELTA); + } + if (config->support_pce_triggered_initial_sync) { + index += snprintf(buf + index, + strlen(PCEP_CLI_CAP_PCE_TRIGGERED), + PCEP_CLI_CAP_PCE_TRIGGERED); + } + if (config->support_sr_te_pst) { + index += snprintf(buf + index, strlen(PCEP_CLI_CAP_SR_TE_PST), + PCEP_CLI_CAP_SR_TE_PST); + } + if (config->pcc_can_resolve_nai_to_sid) { + index += snprintf(buf + index, + strlen(PCEP_CLI_CAP_PCC_RESOLVE_NAI), + PCEP_CLI_CAP_PCC_RESOLVE_NAI); + } +} + +/* Internal util function to print a pcep session */ +static void print_pcep_session(struct vty *vty, struct pcc_state *pcc_state) +{ + char buf[1024]; + buf[0] = '\0'; + + vty_out(vty, "PCE %s\n", pcc_state->pce_opts->pce_name); + + /* PCE IP */ + if (IS_IPADDR_V4(&pcc_state->pce_opts->addr)) { + vty_out(vty, " PCE IP %pI4 port %d\n", + &pcc_state->pce_opts->addr.ipaddr_v4, + pcc_state->pce_opts->port); + } else if (IS_IPADDR_V6(&pcc_state->pce_opts->addr)) { + vty_out(vty, " PCE IPv6 %pI6 port %d\n", + &pcc_state->pce_opts->addr.ipaddr_v6, + pcc_state->pce_opts->port); + } + + /* PCC IP */ + if (IS_IPADDR_V4(&pcc_state->pcc_addr_tr)) { + vty_out(vty, " PCC IP %pI4 port %d\n", + &pcc_state->pcc_addr_tr.ipaddr_v4, + pcc_state->pcc_opts->port); + } else if (IS_IPADDR_V6(&pcc_state->pcc_addr_tr)) { + vty_out(vty, " PCC IPv6 %pI6 port %d\n", + &pcc_state->pcc_addr_tr.ipaddr_v6, + pcc_state->pcc_opts->port); + } + vty_out(vty, " PCC MSD %d\n", pcc_state->pcc_opts->msd); + + if (pcc_state->status == PCEP_PCC_OPERATING) { + vty_out(vty, " Session Status UP\n"); + } else { + vty_out(vty, " Session Status %s\n", + pcc_status_name(pcc_state->status)); + } + + /* Config Options values */ + struct pcep_config_group_opts *config_opts = + &pcc_state->pce_opts->config_opts; + 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: StateTimeout Interval %d\n", + config_opts->state_timeout_inteval_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"); + } + + /* PCEPlib pcep session values */ + pcep_session *pcep_session = pcc_state->sess; + if (pcc_state->status == PCEP_PCC_SYNCHRONIZING + || pcc_state->status == PCEP_PCC_OPERATING) { + time_t current_time = time(NULL); + struct tm lt; + lt.tm_zone = __tzname[0]; + gmtime_r(&pcep_session->time_connected, <); + vty_out(vty, + " Connected for %ld seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n", + (current_time - pcep_session->time_connected), + lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, + lt.tm_hour, lt.tm_min, lt.tm_sec); + } + + if (config_opts->draft07) { + vty_out(vty, " PCE SR Version draft07\n"); + } else { + vty_out(vty, " PCE SR Version draft16 and RFC8408\n"); + } + + /* PCC capabilities */ + buf[0] = '\0'; + int index = 0; + if (config_opts->pce_initiated) { + index += snprintf(buf, strlen(PCEP_CLI_CAP_PCC_PCE_INITIATED), + PCEP_CLI_CAP_PCC_PCE_INITIATED); + } else { + index += snprintf(buf, strlen(PCEP_CLI_CAP_PCC_INITIATED), + PCEP_CLI_CAP_PCC_INITIATED); + } + print_pcep_capabilities(buf + index, &pcep_session->pcc_config); + vty_out(vty, " PCC Capabilities:%s\n", buf); + + /* PCE capabilities */ + buf[0] = '\0'; + print_pcep_capabilities(buf, &pcep_session->pce_config); + if (buf[0] != '\0') { + vty_out(vty, " PCE Capabilities:%s\n", buf); + } + + vty_out(vty, " Next PcReq ID %d\n", pcc_state->next_reqid); + vty_out(vty, " Next PLSP ID %d\n", pcc_state->next_plspid); + + /* Message Counters */ + struct counters_subgroup *rx_msgs = + find_subgroup(pcep_session->pcep_session_counters, + COUNTER_SUBGROUP_ID_RX_MSG); + struct counters_subgroup *tx_msgs = + find_subgroup(pcep_session->pcep_session_counters, + 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)); + } +} + +static int path_pcep_cli_show_pcep_session(struct vty *vty, + const char *pcc_peer) +{ + struct pce_opts_cli *pce_opts_cli; + struct pcc_state *pcc_state; + + /* 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; + } + + pcc_state = pcep_ctrl_get_pcc_state(pcep_g->fpt, pcc_peer); + if (pcc_state == NULL) { + vty_out(vty, "%% PCC is not connected to PCE [%s]\n", + pcc_peer); + return CMD_WARNING; + } + + print_pcep_session(vty, pcc_state); + + return CMD_SUCCESS; + } + + /* Show all PCEP sessions */ + int num_pcep_sessions = 0; + for (int i = 0; i < MAX_PCE; i++) { + pce_opts_cli = pcep_g->pce_opts_cli[i]; + if (pce_opts_cli == NULL) { + continue; + } + + pcc_state = pcep_ctrl_get_pcc_state( + pcep_g->fpt, pce_opts_cli->pce_opts.pce_name); + if (pcc_state == NULL) { + continue; + } + + num_pcep_sessions++; + print_pcep_session(vty, pcc_state); + } + + vty_out(vty, "\nConnected PCEP Sessions: %d\n", num_pcep_sessions); + + return CMD_SUCCESS; +} + /* * Config Write functions */ @@ -1005,12 +1233,12 @@ int pcep_cli_pcc_config_write(struct vty *vty) } if (pcc_opts->port != PCEP_DEFAULT_PORT) { - index += sprintf(buf + index, " %s %d", PCEP_VTYSH_ARG_PORT, - pcc_opts->port); + index += snprintf(buf + index, 16, " %s %d", + PCEP_VTYSH_ARG_PORT, pcc_opts->port); } if (pcc_opts->msd != DEFAULT_PCC_MSD) { - index += sprintf(buf + index, " %s %d", PCEP_VTYSH_ARG_MSD, - pcc_opts->msd); + index += snprintf(buf + index, 16, " %s %d", PCEP_VTYSH_ARG_MSD, + pcc_opts->msd); } if (IS_IPADDR_V4(&pcc_opts->addr)) { @@ -1037,12 +1265,12 @@ int pcep_cli_pcc_config_write(struct vty *vty) continue; } - index = sprintf(buf, " peer %s", - pce_opts_cli->pce_opts.pce_name); + index = snprintf(buf, 32, " peer %s", + pce_opts_cli->pce_opts.pce_name); if (pce_opts_cli->pce_opts.precedence > 0) { - sprintf(buf + index, " %s %d", - PCEP_VTYSH_ARG_PRECEDENCE, - pce_opts_cli->pce_opts.precedence); + snprintf(buf + index, 32, " %s %d", + PCEP_VTYSH_ARG_PRECEDENCE, + pce_opts_cli->pce_opts.precedence); } vty_out(vty, "%s\n", buf); lines++; @@ -1061,73 +1289,73 @@ pcep_cli_print_config_group(struct pcep_config_group_opts *group_opts, int index = 0; if (group_opts->keep_alive_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_KEEP_ALIVE, - group_opts->keep_alive_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_KEEP_ALIVE, + group_opts->keep_alive_seconds); lines++; } if (group_opts->min_keep_alive_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_KEEP_ALIVE_MIN, - group_opts->min_keep_alive_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_KEEP_ALIVE_MIN, + group_opts->min_keep_alive_seconds); lines++; } if (group_opts->max_keep_alive_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_KEEP_ALIVE_MAX, - group_opts->max_keep_alive_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_KEEP_ALIVE_MAX, + group_opts->max_keep_alive_seconds); lines++; } if (group_opts->dead_timer_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_DEAD_TIMER, - group_opts->dead_timer_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_DEAD_TIMER, + group_opts->dead_timer_seconds); lines++; } if (group_opts->min_dead_timer_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_DEAD_TIMER_MIN, - group_opts->min_dead_timer_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_DEAD_TIMER_MIN, + group_opts->min_dead_timer_seconds); lines++; } if (group_opts->max_dead_timer_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_DEAD_TIMER_MAX, - group_opts->max_dead_timer_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_DEAD_TIMER_MAX, + group_opts->max_dead_timer_seconds); lines++; } if (group_opts->pcep_request_time_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_PCEP_REQUEST, - group_opts->pcep_request_time_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_PCEP_REQUEST, + group_opts->pcep_request_time_seconds); lines++; } if (group_opts->state_timeout_inteval_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_STATE_TIMEOUT, - group_opts->state_timeout_inteval_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_STATE_TIMEOUT, + group_opts->state_timeout_inteval_seconds); lines++; } if (group_opts->delegation_timeout_seconds > 0) { - index += sprintf(buf + index, " %s %d\n", - PCEP_VTYSH_ARG_DELEGATION_TIMEOUT, - group_opts->delegation_timeout_seconds); + index += snprintf(buf + index, 32, " %s %d\n", + PCEP_VTYSH_ARG_DELEGATION_TIMEOUT, + group_opts->delegation_timeout_seconds); lines++; } if (group_opts->tcp_md5_auth[0] != '\0') { - index += sprintf(buf + index, " %s %s\n", - PCEP_VTYSH_ARG_TCP_MD5, - group_opts->tcp_md5_auth); + index += snprintf(buf + index, 32, " %s %s\n", + PCEP_VTYSH_ARG_TCP_MD5, + group_opts->tcp_md5_auth); lines++; } if (group_opts->draft07) { - index += sprintf(buf + index, " %s\n", - PCEP_VTYSH_ARG_SR_DRAFT07); + index += snprintf(buf + index, 32, " %s\n", + PCEP_VTYSH_ARG_SR_DRAFT07); lines++; } if (group_opts->pce_initiated) { - index += - sprintf(buf + index, " %s\n", PCEP_VTYSH_ARG_PCE_INIT); + index += snprintf(buf + index, 32, " %s\n", + PCEP_VTYSH_ARG_PCE_INIT); lines++; } @@ -1319,7 +1547,7 @@ DEFPY(pcep_cli_peer_pcep_config_group, pcep_cli_peer_pcep_config_group_cmd, DEFPY(pcep_cli_peer_timers, pcep_cli_peer_timers_cmd, "timer [keep-alive (1-240)] [min-peer-keep-alive (1-60)] [max-peer-keep-alive (60-240)] " - "[dead-timer (1-240)] [min-peer-dead-timer (1-60)] [max-peer-dead-timer (60-240)] " + "[dead-timer (4-480)] [min-peer-dead-timer (4-60)] [max-peer-dead-timer (60-480)] " "[pcep-request (1-120)] [state-timeout-interval (1-120)] [delegation-timeout (1-60)]", "PCE PCEP Session Timers configuration\n" "PCC Keep Alive Timer\n" @@ -1393,6 +1621,15 @@ DEFPY(pcep_cli_pcc_pcc_peer, pcep_cli_pcc_pcc_peer_cmd, } } +DEFPY(pcep_cli_show_pcep_session, pcep_cli_show_pcep_session_cmd, + "show pcep-session [WORD]$pcc_peer", + SHOW_STR + "Show PCEP Session information\n" + "PCC Peer name\n") +{ + return path_pcep_cli_show_pcep_session(vty, pcc_peer); +} + void pcep_cli_init(void) { hook_register(nb_client_debug_config_write, @@ -1434,4 +1671,6 @@ void pcep_cli_init(void) /* PCC related commands */ install_element(CONFIG_NODE, &pcep_cli_pcc_cmd); install_element(PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd); + + install_element(ENABLE_NODE, &pcep_cli_show_pcep_session_cmd); } diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index 608d382db6c5..a8b776f7093b 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -287,11 +287,28 @@ struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, return args.counters; } +struct pcc_state *pcep_ctrl_get_pcc_state(struct frr_pthread *fpt, + const char *pce_name) +{ + struct ctrl_state *ctrl_state = get_ctrl_state(fpt); + for (int i = 0; i < MAX_PCE; i++) { + if (ctrl_state->pcc[i] == NULL) { + continue; + } + + if (strcmp(ctrl_state->pcc[i]->pce_opts->pce_name, pce_name) + == 0) { + return ctrl_state->pcc[i]; + } + } + + return NULL; +} + bool pcep_ctrl_pcc_has_pce(struct frr_pthread *fpt, const char *pce_name) { struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - int i = 0; - for (; i < MAX_PCC; i++) { + for (int i = 0; i < MAX_PCC; i++) { if (ctrl_state->pcc[i] == NULL) { continue; } diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h index 7bbf7fe6624a..46ea6b9c4d3c 100644 --- a/pathd/path_pcep_controller.h +++ b/pathd/path_pcep_controller.h @@ -96,6 +96,8 @@ int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id); struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, int pcc_id); bool pcep_ctrl_pcc_has_pce(struct frr_pthread *fpt, const char *pce_name); +struct pcc_state *pcep_ctrl_get_pcc_state(struct frr_pthread *fpt, + const char *pce_name); /* Synchronously send a report, the caller is responsible to free the path, * If `pcc_id` is `0` the report is sent by all PCCs */ void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,