]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_cli.c
Merge pull request #9318 from Prerana-GB/ibgp_knob
[mirror_frr.git] / pathd / path_pcep_cli.c
1 /*
2 * Copyright (C) 2020 Volta Networks, Inc
3 * Brady Johnson
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21 #include "pceplib/pcep_utils_counters.h"
22 #include "pceplib/pcep_session_logic.h"
23
24 #include "log.h"
25 #include "command.h"
26 #include "libfrr.h"
27 #include "printfrr.h"
28 #include "lib/version.h"
29 #include "northbound.h"
30 #include "frr_pthread.h"
31 #include "jhash.h"
32 #include "termtable.h"
33
34 #include "pathd/pathd.h"
35 #include "pathd/path_errors.h"
36 #include "pathd/path_pcep.h"
37 #include "pathd/path_pcep_cli.h"
38 #include "pathd/path_pcep_controller.h"
39 #include "pathd/path_pcep_debug.h"
40 #include "pathd/path_pcep_lib.h"
41 #include "pathd/path_pcep_pcc.h"
42
43 #ifndef VTYSH_EXTRACT_PL
44 #include "pathd/path_pcep_cli_clippy.c"
45 #endif
46
47 #define DEFAULT_PCE_PRECEDENCE 255
48 #define DEFAULT_PCC_MSD 4
49 #define DEFAULT_SR_DRAFT07 false
50 #define DEFAULT_PCE_INITIATED false
51 #define DEFAULT_TIMER_KEEP_ALIVE 30
52 #define DEFAULT_TIMER_KEEP_ALIVE_MIN 1
53 #define DEFAULT_TIMER_KEEP_ALIVE_MAX 255
54 #define DEFAULT_TIMER_DEADTIMER 120
55 #define DEFAULT_TIMER_DEADTIMER_MIN 4
56 #define DEFAULT_TIMER_DEADTIMER_MAX 255
57 #define DEFAULT_TIMER_PCEP_REQUEST 30
58 #define DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL 30
59 #define DEFAULT_DELEGATION_TIMEOUT_INTERVAL 10
60
61 /* CLI Function declarations */
62 static int pcep_cli_debug_config_write(struct vty *vty);
63 static int pcep_cli_debug_set_all(uint32_t flags, bool set);
64 static int pcep_cli_pcep_config_write(struct vty *vty);
65 static int pcep_cli_pcc_config_write(struct vty *vty);
66 static int pcep_cli_pce_config_write(struct vty *vty);
67 static int pcep_cli_pcep_pce_config_write(struct vty *vty);
68
69 /* Internal Util Function declarations */
70 static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name);
71 static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli);
72 static struct pce_opts_cli *pcep_cli_create_pce_opts();
73 static void pcep_cli_delete_pce(const char *pce_name);
74 static void
75 pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli);
76 static struct pcep_config_group_opts *
77 pcep_cli_find_pcep_pce_config(const char *group_name);
78 static bool
79 pcep_cli_add_pcep_pce_config(struct pcep_config_group_opts *config_group_opts);
80 static struct pcep_config_group_opts *
81 pcep_cli_create_pcep_pce_config(const char *group_name);
82 static bool pcep_cli_is_pcep_pce_config_used(const char *group_name);
83 static void pcep_cli_delete_pcep_pce_config(const char *group_name);
84 static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
85 char *buf, size_t buf_len);
86 static void print_pcep_capabilities(char *buf, size_t buf_len,
87 pcep_configuration *config);
88 static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
89 struct pcep_pcc_info *pcc_info);
90 static bool pcep_cli_pcc_has_pce(const char *pce_name);
91 static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts);
92 static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts);
93 static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
94 const char *peer_name,
95 const char *precedence_str,
96 long precedence);
97
98 /*
99 * Globals.
100 */
101
102 static const char PCEP_VTYSH_ARG_ADDRESS[] = "address";
103 static const char PCEP_VTYSH_ARG_SOURCE_ADDRESS[] = "source-address";
104 static const char PCEP_VTYSH_ARG_IP[] = "ip";
105 static const char PCEP_VTYSH_ARG_IPV6[] = "ipv6";
106 static const char PCEP_VTYSH_ARG_PORT[] = "port";
107 static const char PCEP_VTYSH_ARG_PRECEDENCE[] = "precedence";
108 static const char PCEP_VTYSH_ARG_MSD[] = "msd";
109 static const char PCEP_VTYSH_ARG_KEEP_ALIVE[] = "keep-alive";
110 static const char PCEP_VTYSH_ARG_TIMER[] = "timer";
111 static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MIN[] = "min-peer-keep-alive";
112 static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MAX[] = "max-peer-keep-alive";
113 static const char PCEP_VTYSH_ARG_DEAD_TIMER[] = "dead-timer";
114 static const char PCEP_VTYSH_ARG_DEAD_TIMER_MIN[] = "min-peer-dead-timer";
115 static const char PCEP_VTYSH_ARG_DEAD_TIMER_MAX[] = "max-peer-dead-timer";
116 static const char PCEP_VTYSH_ARG_PCEP_REQUEST[] = "pcep-request";
117 static const char PCEP_VTYSH_ARG_SESSION_TIMEOUT[] = "session-timeout-interval";
118 static const char PCEP_VTYSH_ARG_DELEGATION_TIMEOUT[] = "delegation-timeout";
119 static const char PCEP_VTYSH_ARG_SR_DRAFT07[] = "sr-draft07";
120 static const char PCEP_VTYSH_ARG_PCE_INIT[] = "pce-initiated";
121 static const char PCEP_VTYSH_ARG_TCP_MD5[] = "tcp-md5-auth";
122 static const char PCEP_VTYSH_ARG_BASIC[] = "basic";
123 static const char PCEP_VTYSH_ARG_PATH[] = "path";
124 static const char PCEP_VTYSH_ARG_MESSAGE[] = "message";
125 static const char PCEP_VTYSH_ARG_PCEPLIB[] = "pceplib";
126 static const char PCEP_CLI_CAP_STATEFUL[] = " [Stateful PCE]";
127 static const char PCEP_CLI_CAP_INCL_DB_VER[] = " [Include DB version]";
128 static const char PCEP_CLI_CAP_LSP_TRIGGERED[] = " [LSP Triggered Resync]";
129 static const char PCEP_CLI_CAP_LSP_DELTA[] = " [LSP Delta Sync]";
130 static const char PCEP_CLI_CAP_PCE_TRIGGERED[] =
131 " [PCE triggered Initial Sync]";
132 static const char PCEP_CLI_CAP_SR_TE_PST[] = " [SR TE PST]";
133 static const char PCEP_CLI_CAP_PCC_RESOLVE_NAI[] =
134 " [PCC can resolve NAI to SID]";
135 static const char PCEP_CLI_CAP_PCC_INITIATED[] = " [PCC Initiated LSPs]";
136 static const char PCEP_CLI_CAP_PCC_PCE_INITIATED[] =
137 " [PCC and PCE Initiated LSPs]";
138
139 struct pce_connections {
140 int num_connections;
141 struct pce_opts *connections[MAX_PCC];
142 };
143
144 struct pce_connections pce_connections_g = {.num_connections = 0};
145
146 /* Default PCE group that all PCE-Groups and PCEs will inherit from */
147 struct pcep_config_group_opts default_pcep_config_group_opts_g = {
148 .name = "default",
149 .tcp_md5_auth = "\0",
150 .draft07 = DEFAULT_SR_DRAFT07,
151 .pce_initiated = DEFAULT_PCE_INITIATED,
152 .keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE,
153 .min_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MIN,
154 .max_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MAX,
155 .dead_timer_seconds = DEFAULT_TIMER_DEADTIMER,
156 .min_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MIN,
157 .max_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MAX,
158 .pcep_request_time_seconds = DEFAULT_TIMER_PCEP_REQUEST,
159 .session_timeout_inteval_seconds =
160 DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL,
161 .delegation_timeout_seconds = DEFAULT_DELEGATION_TIMEOUT_INTERVAL,
162 .source_port = DEFAULT_PCEP_TCP_PORT,
163 .source_ip.ipa_type = IPADDR_NONE,
164 };
165
166 /* Used by PCEP_PCE_CONFIG_NODE sub-commands to operate on the current pce group
167 */
168 struct pcep_config_group_opts *current_pcep_config_group_opts_g = NULL;
169 /* Used by PCEP_PCE_NODE sub-commands to operate on the current pce opts */
170 struct pce_opts_cli *current_pce_opts_g = NULL;
171 short pcc_msd_g = DEFAULT_PCC_MSD;
172 bool pcc_msd_configured_g = false;
173
174 static struct cmd_node pcep_node = {
175 .name = "srte pcep",
176 .node = PCEP_NODE,
177 .parent_node = SR_TRAFFIC_ENG_NODE,
178 .prompt = "%s(config-sr-te-pcep)# "
179 };
180
181 static struct cmd_node pcep_pcc_node = {
182 .name = "srte pcep pcc",
183 .node = PCEP_PCC_NODE,
184 .parent_node = PCEP_NODE,
185 .prompt = "%s(config-sr-te-pcep-pcc)# "
186 };
187
188 static struct cmd_node pcep_pce_node = {
189 .name = "srte pcep pce",
190 .node = PCEP_PCE_NODE,
191 .parent_node = PCEP_NODE,
192 .prompt = "%s(config-sr-te-pcep-pce)# "
193 };
194
195 static struct cmd_node pcep_pce_config_node = {
196 .name = "srte pcep pce-config",
197 .node = PCEP_PCE_CONFIG_NODE,
198 .parent_node = PCEP_NODE,
199 .prompt = "%s(pce-sr-te-pcep-pce-config)# "
200 };
201
202 /* Common code used in VTYSH processing for int values */
203 #define PCEP_VTYSH_INT_ARG_CHECK(arg_str, arg_val, arg_store, min_value, \
204 max_value) \
205 if (arg_str != NULL) { \
206 if (arg_val <= min_value || arg_val >= max_value) { \
207 vty_out(vty, \
208 "%% Invalid value %ld in range [%d - %d]", \
209 arg_val, min_value, max_value); \
210 return CMD_WARNING; \
211 } \
212 arg_store = arg_val; \
213 }
214
215 #define MERGE_COMPARE_CONFIG_GROUP_VALUE(config_param, not_set_value) \
216 pce_opts_cli->pce_opts.config_opts.config_param = \
217 pce_opts_cli->pce_config_group_opts.config_param; \
218 if (pce_opts_cli->pce_config_group_opts.config_param \
219 == not_set_value) { \
220 pce_opts_cli->pce_opts.config_opts.config_param = \
221 ((pce_config != NULL \
222 && pce_config->config_param != not_set_value) \
223 ? pce_config->config_param \
224 : default_pcep_config_group_opts_g \
225 .config_param); \
226 }
227
228 /*
229 * Internal Util functions
230 */
231
232 /* Check if a pce_opts_cli already exists based on its name and return it,
233 * return NULL otherwise */
234 static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name)
235 {
236 for (int i = 0; i < MAX_PCE; i++) {
237 struct pce_opts_cli *pce_rhs_cli = pcep_g->pce_opts_cli[i];
238 if (pce_rhs_cli != NULL) {
239 if (strcmp(pce_name, pce_rhs_cli->pce_opts.pce_name)
240 == 0) {
241 return pce_rhs_cli;
242 }
243 }
244 }
245
246 return NULL;
247 }
248
249 /* Add a new pce_opts_cli to pcep_g, return false if MAX_PCES, true otherwise */
250 static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli)
251 {
252 for (int i = 0; i < MAX_PCE; i++) {
253 if (pcep_g->pce_opts_cli[i] == NULL) {
254 pcep_g->pce_opts_cli[i] = pce_opts_cli;
255 pcep_g->num_pce_opts_cli++;
256 return true;
257 }
258 }
259
260 return false;
261 }
262
263 /* Create a new pce opts_cli */
264 static struct pce_opts_cli *pcep_cli_create_pce_opts(const char *name)
265 {
266 struct pce_opts_cli *pce_opts_cli =
267 XCALLOC(MTYPE_PCEP, sizeof(struct pce_opts_cli));
268 strlcpy(pce_opts_cli->pce_opts.pce_name, name,
269 sizeof(pce_opts_cli->pce_opts.pce_name));
270 pce_opts_cli->pce_opts.port = PCEP_DEFAULT_PORT;
271
272 return pce_opts_cli;
273 }
274
275 static void pcep_cli_delete_pce(const char *pce_name)
276 {
277 for (int i = 0; i < MAX_PCE; i++) {
278 if (pcep_g->pce_opts_cli[i] != NULL) {
279 if (strcmp(pcep_g->pce_opts_cli[i]->pce_opts.pce_name,
280 pce_name)
281 == 0) {
282 XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]);
283 pcep_g->pce_opts_cli[i] = NULL;
284 pcep_g->num_pce_opts_cli--;
285 return;
286 }
287 }
288 }
289 }
290
291 static void
292 pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli)
293 {
294 if (pce_opts_cli->merged == true) {
295 return;
296 }
297
298 struct pcep_config_group_opts *pce_config =
299 pcep_cli_find_pcep_pce_config(pce_opts_cli->config_group_name);
300
301 /* Configuration priorities:
302 * 1) pce_opts->config_opts, if present, overwrite pce_config
303 * config_opts 2) pce_config config_opts, if present, overwrite
304 * default config_opts 3) If neither pce_opts->config_opts nor
305 * pce_config config_opts are set, then the default config_opts value
306 * will be used.
307 */
308
309 const char *tcp_md5_auth_str =
310 pce_opts_cli->pce_config_group_opts.tcp_md5_auth;
311 if (pce_opts_cli->pce_config_group_opts.tcp_md5_auth[0] == '\0') {
312 if (pce_config != NULL && pce_config->tcp_md5_auth[0] != '\0') {
313 tcp_md5_auth_str = pce_config->tcp_md5_auth;
314 } else {
315 tcp_md5_auth_str =
316 default_pcep_config_group_opts_g.tcp_md5_auth;
317 }
318 }
319 strlcpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
320 tcp_md5_auth_str,
321 sizeof(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth));
322
323 struct ipaddr *source_ip =
324 &pce_opts_cli->pce_config_group_opts.source_ip;
325 if (pce_opts_cli->pce_config_group_opts.source_ip.ipa_type
326 == IPADDR_NONE) {
327 if (pce_config != NULL
328 && pce_config->source_ip.ipa_type != IPADDR_NONE) {
329 source_ip = &pce_config->source_ip;
330 } else {
331 source_ip = &default_pcep_config_group_opts_g.source_ip;
332 }
333 }
334 memcpy(&pce_opts_cli->pce_opts.config_opts.source_ip, source_ip,
335 sizeof(struct ipaddr));
336
337 MERGE_COMPARE_CONFIG_GROUP_VALUE(draft07, false);
338 MERGE_COMPARE_CONFIG_GROUP_VALUE(pce_initiated, false);
339 MERGE_COMPARE_CONFIG_GROUP_VALUE(keep_alive_seconds, 0);
340 MERGE_COMPARE_CONFIG_GROUP_VALUE(min_keep_alive_seconds, 0);
341 MERGE_COMPARE_CONFIG_GROUP_VALUE(max_keep_alive_seconds, 0);
342 MERGE_COMPARE_CONFIG_GROUP_VALUE(dead_timer_seconds, 0);
343 MERGE_COMPARE_CONFIG_GROUP_VALUE(min_dead_timer_seconds, 0);
344 MERGE_COMPARE_CONFIG_GROUP_VALUE(max_dead_timer_seconds, 0);
345 MERGE_COMPARE_CONFIG_GROUP_VALUE(pcep_request_time_seconds, 0);
346 MERGE_COMPARE_CONFIG_GROUP_VALUE(session_timeout_inteval_seconds, 0);
347 MERGE_COMPARE_CONFIG_GROUP_VALUE(delegation_timeout_seconds, 0);
348 MERGE_COMPARE_CONFIG_GROUP_VALUE(source_port, 0);
349
350 pce_opts_cli->merged = true;
351 }
352
353 /* Check if a pcep_config_group_opts already exists based on its name and return
354 * it, return NULL otherwise */
355 static struct pcep_config_group_opts *
356 pcep_cli_find_pcep_pce_config(const char *group_name)
357 {
358 for (int i = 0; i < MAX_PCE; i++) {
359 struct pcep_config_group_opts *pcep_pce_config_rhs =
360 pcep_g->config_group_opts[i];
361 if (pcep_pce_config_rhs != NULL) {
362 if (strcmp(group_name, pcep_pce_config_rhs->name)
363 == 0) {
364 return pcep_pce_config_rhs;
365 }
366 }
367 }
368
369 return NULL;
370 }
371
372 /* Add a new pcep_config_group_opts to pcep_g, return false if MAX_PCE,
373 * true otherwise */
374 static bool pcep_cli_add_pcep_pce_config(
375 struct pcep_config_group_opts *pcep_config_group_opts)
376 {
377 for (int i = 0; i < MAX_PCE; i++) {
378 if (pcep_g->config_group_opts[i] == NULL) {
379 pcep_g->config_group_opts[i] = pcep_config_group_opts;
380 pcep_g->num_config_group_opts++;
381 return true;
382 }
383 }
384
385 return false;
386 }
387
388 /* Create a new pce group, inheriting its values from the default pce group */
389 static struct pcep_config_group_opts *
390 pcep_cli_create_pcep_pce_config(const char *group_name)
391 {
392 struct pcep_config_group_opts *pcep_config_group_opts =
393 XCALLOC(MTYPE_PCEP, sizeof(struct pcep_config_group_opts));
394 strlcpy(pcep_config_group_opts->name, group_name,
395 sizeof(pcep_config_group_opts->name));
396
397 return pcep_config_group_opts;
398 }
399
400 /* Iterate the pce_opts and return true if the pce-group-name is referenced,
401 * false otherwise. */
402 static bool pcep_cli_is_pcep_pce_config_used(const char *group_name)
403 {
404 for (int i = 0; i < MAX_PCE; i++) {
405 if (pcep_g->pce_opts_cli[i] != NULL) {
406 if (strcmp(pcep_g->pce_opts_cli[i]->config_group_name,
407 group_name)
408 == 0) {
409 return true;
410 }
411 }
412 }
413
414 return false;
415 }
416
417 static void pcep_cli_delete_pcep_pce_config(const char *group_name)
418 {
419 for (int i = 0; i < MAX_PCE; i++) {
420 if (pcep_g->config_group_opts[i] != NULL) {
421 if (strcmp(pcep_g->config_group_opts[i]->name,
422 group_name)
423 == 0) {
424 XFREE(MTYPE_PCEP, pcep_g->config_group_opts[i]);
425 pcep_g->config_group_opts[i] = NULL;
426 pcep_g->num_config_group_opts--;
427 return;
428 }
429 }
430 }
431 }
432
433 static bool pcep_cli_pcc_has_pce(const char *pce_name)
434 {
435 for (int i = 0; i < MAX_PCC; i++) {
436 struct pce_opts *pce_opts = pce_connections_g.connections[i];
437 if (pce_opts == NULL) {
438 continue;
439 }
440
441 if (strcmp(pce_opts->pce_name, pce_name) == 0) {
442 return true;
443 }
444 }
445
446 return false;
447 }
448
449 static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts)
450 {
451 for (int i = 0; i < MAX_PCC; i++) {
452 if (pce_connections_g.connections[i] == NULL) {
453 pce_connections_g.num_connections++;
454 pce_connections_g.connections[i] = pce_opts;
455 return;
456 }
457 }
458 }
459
460 static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts)
461 {
462 for (int i = 0; i < MAX_PCC; i++) {
463 if (pce_connections_g.connections[i] == pce_opts) {
464 pce_connections_g.num_connections--;
465 pce_connections_g.connections[i] = NULL;
466 return;
467 }
468 }
469 }
470
471 /*
472 * VTY command implementations
473 */
474
475 static int path_pcep_cli_debug(struct vty *vty, const char *no_str,
476 const char *basic_str, const char *path_str,
477 const char *message_str, const char *pceplib_str)
478 {
479 uint32_t mode = DEBUG_NODE2MODE(vty->node);
480 bool no = (no_str != NULL);
481
482 DEBUG_MODE_SET(&pcep_g->dbg, mode, !no);
483
484 if (basic_str != NULL) {
485 DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, !no);
486 }
487 if (path_str != NULL) {
488 DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, !no);
489 }
490 if (message_str != NULL) {
491 DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, !no);
492 }
493 if (pceplib_str != NULL) {
494 DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, !no);
495 }
496
497 return CMD_SUCCESS;
498 }
499
500 static int path_pcep_cli_show_srte_pcep_counters(struct vty *vty)
501 {
502 int i, j, row;
503 time_t diff_time;
504 struct tm tm_info;
505 char tm_buffer[26];
506 struct counters_group *group;
507 struct counters_subgroup *subgroup;
508 struct counter *counter;
509 const char *group_name, *empty_string = "";
510 struct ttable *tt;
511 char *table;
512
513 group = pcep_ctrl_get_counters(pcep_g->fpt, 1);
514
515 if (group == NULL) {
516 vty_out(vty, "No counters to display.\n\n");
517 return CMD_SUCCESS;
518 }
519
520 diff_time = time(NULL) - group->start_time;
521 localtime_r(&group->start_time, &tm_info);
522 strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", &tm_info);
523
524 vty_out(vty, "PCEP counters since %s (%uh %um %us):\n", tm_buffer,
525 (uint32_t)(diff_time / 3600), (uint32_t)((diff_time / 60) % 60),
526 (uint32_t)(diff_time % 60));
527
528 /* Prepare table. */
529 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
530 ttable_add_row(tt, "Group|Name|Value");
531 tt->style.cell.rpad = 2;
532 tt->style.corner = '+';
533 ttable_restyle(tt);
534 ttable_rowseps(tt, 0, BOTTOM, true, '-');
535
536 for (row = 0, i = 0; i <= group->num_subgroups; i++) {
537 subgroup = group->subgroups[i];
538 if (subgroup != NULL) {
539 group_name = subgroup->counters_subgroup_name;
540 for (j = 0; j <= subgroup->num_counters; j++) {
541 counter = subgroup->counters[j];
542 if (counter != NULL) {
543 ttable_add_row(tt, "%s|%s|%u",
544 group_name,
545 counter->counter_name,
546 counter->counter_value);
547 row++;
548 group_name = empty_string;
549 }
550 }
551 ttable_rowseps(tt, row, BOTTOM, true, '-');
552 }
553 }
554
555 /* Dump the generated table. */
556 table = ttable_dump(tt, "\n");
557 vty_out(vty, "%s\n", table);
558 XFREE(MTYPE_TMP, table);
559
560 ttable_del(tt);
561
562 pcep_lib_free_counters(group);
563
564 return CMD_SUCCESS;
565 }
566
567 static int path_pcep_cli_pcep_pce_config(struct vty *vty,
568 const char *pcep_pce_config)
569 {
570 struct pcep_config_group_opts *pce_config =
571 pcep_cli_find_pcep_pce_config(pcep_pce_config);
572 if (pce_config == NULL) {
573 pce_config = pcep_cli_create_pcep_pce_config(pcep_pce_config);
574 if (pcep_cli_add_pcep_pce_config(pce_config) == false) {
575 vty_out(vty,
576 "%% Cannot create pce-config, as the Maximum limit of %d pce-config has been reached.\n",
577 MAX_PCE);
578 XFREE(MTYPE_PCEP, pce_config);
579 return CMD_WARNING;
580 }
581 } else {
582 vty_out(vty,
583 "Notice: changes to this pce-config will not affect PCEs already configured with this group\n");
584 }
585
586 current_pcep_config_group_opts_g = pce_config;
587 vty->node = PCEP_PCE_CONFIG_NODE;
588
589 return CMD_SUCCESS;
590 }
591
592 static int path_pcep_cli_pcep_pce_config_delete(struct vty *vty,
593 const char *pcep_pce_config)
594 {
595 struct pcep_config_group_opts *pce_config =
596 pcep_cli_find_pcep_pce_config(pcep_pce_config);
597 if (pce_config == NULL) {
598 vty_out(vty,
599 "%% Cannot delete pce-config, since it does not exist.\n");
600 return CMD_WARNING;
601 }
602
603 if (pcep_cli_is_pcep_pce_config_used(pce_config->name)) {
604 vty_out(vty,
605 "%% Cannot delete pce-config, since it is in use by a peer.\n");
606 return CMD_WARNING;
607 }
608
609 pcep_cli_delete_pcep_pce_config(pce_config->name);
610
611 return CMD_SUCCESS;
612 }
613
614 static int path_pcep_cli_show_srte_pcep_pce_config(struct vty *vty,
615 const char *pcep_pce_config)
616 {
617 char buf[1024] = "";
618
619 /* Only show 1 Peer config group */
620 struct pcep_config_group_opts *group_opts;
621 if (pcep_pce_config != NULL) {
622 if (strcmp(pcep_pce_config, "default") == 0) {
623 group_opts = &default_pcep_config_group_opts_g;
624 } else {
625 group_opts =
626 pcep_cli_find_pcep_pce_config(pcep_pce_config);
627 }
628 if (group_opts == NULL) {
629 vty_out(vty, "%% pce-config [%s] does not exist.\n",
630 pcep_pce_config);
631 return CMD_WARNING;
632 }
633
634 vty_out(vty, "pce-config: %s\n", group_opts->name);
635 pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
636 vty_out(vty, "%s", buf);
637 return CMD_SUCCESS;
638 }
639
640 /* Show all Peer config groups */
641 for (int i = 0; i < MAX_PCE; i++) {
642 group_opts = pcep_g->config_group_opts[i];
643 if (group_opts == NULL) {
644 continue;
645 }
646
647 vty_out(vty, "pce-config: %s\n", group_opts->name);
648 pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
649 vty_out(vty, "%s", buf);
650 buf[0] = 0;
651 }
652
653 return CMD_SUCCESS;
654 }
655
656 static int path_pcep_cli_pce(struct vty *vty, const char *pce_peer_name)
657 {
658 /* If it already exists, it will be updated in the sub-commands */
659 struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
660 if (pce_opts_cli == NULL) {
661 pce_opts_cli = pcep_cli_create_pce_opts(pce_peer_name);
662
663 if (!pcep_cli_add_pce(pce_opts_cli)) {
664 vty_out(vty,
665 "%% Cannot create PCE, as the Maximum limit of %d PCEs has been reached.\n",
666 MAX_PCE);
667 XFREE(MTYPE_PCEP, pce_opts_cli);
668 return CMD_WARNING;
669 }
670 }
671
672 current_pce_opts_g = pce_opts_cli;
673 vty->node = PCEP_PCE_NODE;
674
675 return CMD_SUCCESS;
676 }
677
678 static int path_pcep_cli_pce_delete(struct vty *vty, const char *pce_peer_name)
679 {
680 struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
681 if (pce_opts_cli == NULL) {
682 vty_out(vty, "%% PCC peer does not exist.\n");
683 return CMD_WARNING;
684 }
685
686 /* To better work with frr-reload, go ahead and delete it if its in use
687 */
688 if (pcep_cli_pcc_has_pce(pce_peer_name)) {
689 vty_out(vty,
690 "%% Notice: the pce is in use by a PCC, also disconnecting.\n");
691 path_pcep_cli_pcc_pcc_peer_delete(vty, pce_peer_name, NULL, 0);
692 }
693
694 pcep_cli_delete_pce(pce_peer_name);
695
696 return CMD_SUCCESS;
697 }
698
699 /* Internal Util func to show an individual PCE,
700 * only used by path_pcep_cli_show_srte_pcep_pce() */
701 static void show_pce_peer(struct vty *vty, struct pce_opts_cli *pce_opts_cli)
702 {
703 struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
704 vty_out(vty, "PCE: %s\n", pce_opts->pce_name);
705
706 /* Remote PCE IP address */
707 if (IS_IPADDR_V6(&pce_opts->addr)) {
708 vty_out(vty, " %s %s %pI6 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
709 PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6,
710 PCEP_VTYSH_ARG_PORT, pce_opts->port);
711 } else {
712 vty_out(vty, " %s %s %pI4 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
713 PCEP_VTYSH_ARG_IP, &pce_opts->addr.ipaddr_v4,
714 PCEP_VTYSH_ARG_PORT, pce_opts->port);
715 }
716
717 if (pce_opts_cli->config_group_name[0] != '\0') {
718 vty_out(vty, " pce-config: %s\n",
719 pce_opts_cli->config_group_name);
720 }
721
722 char buf[1024] = "";
723 pcep_cli_print_pce_config(&pce_opts->config_opts, buf, sizeof(buf));
724 vty_out(vty, "%s", buf);
725 }
726
727 static int path_pcep_cli_show_srte_pcep_pce(struct vty *vty,
728 const char *pce_peer)
729 {
730 /* Only show 1 PCE */
731 struct pce_opts_cli *pce_opts_cli;
732 if (pce_peer != NULL) {
733 pce_opts_cli = pcep_cli_find_pce(pce_peer);
734 if (pce_opts_cli == NULL) {
735 vty_out(vty, "%% PCE [%s] does not exist.\n", pce_peer);
736 return CMD_WARNING;
737 }
738
739 pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
740 show_pce_peer(vty, pce_opts_cli);
741
742 return CMD_SUCCESS;
743 }
744
745 /* Show all PCEs */
746 for (int i = 0; i < MAX_PCE; i++) {
747 pce_opts_cli = pcep_g->pce_opts_cli[i];
748 if (pce_opts_cli == NULL) {
749 continue;
750 }
751
752 pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
753 show_pce_peer(vty, pce_opts_cli);
754 }
755
756 return CMD_SUCCESS;
757 }
758
759 static int path_pcep_cli_peer_sr_draft07(struct vty *vty)
760 {
761 struct pcep_config_group_opts *pce_config = NULL;
762
763 if (vty->node == PCEP_PCE_NODE) {
764 /* TODO need to see if the pce is in use, and reset the
765 * connection */
766 pce_config = &current_pce_opts_g->pce_config_group_opts;
767 current_pce_opts_g->merged = false;
768 } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
769 pce_config = current_pcep_config_group_opts_g;
770 } else {
771 return CMD_ERR_NO_MATCH;
772 }
773
774 pce_config->draft07 = true;
775
776 return CMD_SUCCESS;
777 }
778
779 static int path_pcep_cli_peer_pce_initiated(struct vty *vty)
780 {
781 struct pcep_config_group_opts *pce_config = NULL;
782
783 if (vty->node == PCEP_PCE_NODE) {
784 /* TODO need to see if the pce is in use, and reset the
785 * connection */
786 pce_config = &current_pce_opts_g->pce_config_group_opts;
787 current_pce_opts_g->merged = false;
788 } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
789 pce_config = current_pcep_config_group_opts_g;
790 } else {
791 return CMD_ERR_NO_MATCH;
792 }
793
794 pce_config->pce_initiated = true;
795
796 return CMD_SUCCESS;
797 }
798
799 static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty,
800 const char *tcp_md5_auth)
801 {
802 struct pcep_config_group_opts *pce_config = NULL;
803
804 if (vty->node == PCEP_PCE_NODE) {
805 /* TODO need to see if the pce is in use, and reset the
806 * connection */
807 pce_config = &current_pce_opts_g->pce_config_group_opts;
808 current_pce_opts_g->merged = false;
809 } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
810 pce_config = current_pcep_config_group_opts_g;
811 } else {
812 return CMD_ERR_NO_MATCH;
813 }
814
815 strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth,
816 sizeof(pce_config->tcp_md5_auth));
817
818 return CMD_SUCCESS;
819 }
820
821 static int path_pcep_cli_peer_address(struct vty *vty, const char *ip_str,
822 struct in_addr *ip, const char *ipv6_str,
823 struct in6_addr *ipv6,
824 const char *port_str, long port)
825 {
826 struct pce_opts *pce_opts = NULL;
827 if (vty->node == PCEP_PCE_NODE) {
828 /* TODO need to see if the pce is in use, and reset the
829 * connection */
830 pce_opts = &current_pce_opts_g->pce_opts;
831 current_pce_opts_g->merged = false;
832 } else {
833 return CMD_ERR_NO_MATCH;
834 }
835
836 if (ipv6_str != NULL) {
837 pce_opts->addr.ipa_type = IPADDR_V6;
838 memcpy(&pce_opts->addr.ipaddr_v6, ipv6,
839 sizeof(struct in6_addr));
840 } else if (ip_str != NULL) {
841 pce_opts->addr.ipa_type = IPADDR_V4;
842 memcpy(&pce_opts->addr.ipaddr_v4, ip, sizeof(struct in_addr));
843 } else {
844 return CMD_ERR_NO_MATCH;
845 }
846
847 /* Handle the optional port */
848 pce_opts->port = PCEP_DEFAULT_PORT;
849 PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_opts->port, 0, 65535);
850
851 return CMD_SUCCESS;
852 }
853
854 static int path_pcep_cli_peer_source_address(struct vty *vty,
855 const char *ip_str,
856 struct in_addr *ip,
857 const char *ipv6_str,
858 struct in6_addr *ipv6,
859 const char *port_str, long port)
860 {
861 struct pcep_config_group_opts *pce_config = NULL;
862 if (vty->node == PCEP_PCE_NODE) {
863 /* TODO need to see if the pce is in use, and reset the
864 * connection */
865 pce_config = &current_pce_opts_g->pce_config_group_opts;
866 current_pce_opts_g->merged = false;
867 } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
868 pce_config = current_pcep_config_group_opts_g;
869 } else {
870 return CMD_ERR_NO_MATCH;
871 }
872
873 /* Handle the optional source IP */
874 if (ipv6_str != NULL) {
875 pce_config->source_ip.ipa_type = IPADDR_V6;
876 memcpy(&pce_config->source_ip.ipaddr_v6, ipv6,
877 sizeof(struct in6_addr));
878 } else if (ip_str != NULL) {
879 pce_config->source_ip.ipa_type = IPADDR_V4;
880 memcpy(&pce_config->source_ip.ipaddr_v4, ip,
881 sizeof(struct in_addr));
882 }
883
884 /* Handle the optional port */
885 PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_config->source_port, 0,
886 65535);
887
888 return CMD_SUCCESS;
889 }
890
891 static int path_pcep_cli_peer_pcep_pce_config_ref(struct vty *vty,
892 const char *config_group_name)
893 {
894 if (vty->node == PCEP_PCE_NODE) {
895 /* TODO need to see if the pce is in use, and reset the
896 * connection */
897 current_pce_opts_g->merged = false;
898 } else {
899 return CMD_ERR_NO_MATCH;
900 }
901
902 struct pcep_config_group_opts *pce_config =
903 pcep_cli_find_pcep_pce_config(config_group_name);
904 if (pce_config == NULL) {
905 vty_out(vty, "%% pce-config [%s] does not exist.\n",
906 config_group_name);
907 return CMD_WARNING;
908 }
909
910 strlcpy(current_pce_opts_g->config_group_name, config_group_name,
911 sizeof(current_pce_opts_g->config_group_name));
912
913 return CMD_SUCCESS;
914 }
915
916 static int path_pcep_cli_peer_timers(
917 struct vty *vty, const char *keep_alive_str, long keep_alive,
918 const char *min_peer_keep_alive_str, long min_peer_keep_alive,
919 const char *max_peer_keep_alive_str, long max_peer_keep_alive,
920 const char *dead_timer_str, long dead_timer,
921 const char *min_peer_dead_timer_str, long min_peer_dead_timer,
922 const char *max_peer_dead_timer_str, long max_peer_dead_timer,
923 const char *pcep_request_str, long pcep_request,
924 const char *session_timeout_interval_str, long session_timeout_interval,
925 const char *delegation_timeout_str, long delegation_timeout)
926 {
927 struct pcep_config_group_opts *pce_config = NULL;
928 if (vty->node == PCEP_PCE_NODE) {
929 /* TODO need to see if the pce is in use, and reset the
930 * connection */
931 pce_config = &current_pce_opts_g->pce_config_group_opts;
932 current_pce_opts_g->merged = false;
933 } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
934 pce_config = current_pcep_config_group_opts_g;
935 } else {
936 return CMD_ERR_NO_MATCH;
937 }
938
939 if (min_peer_keep_alive && max_peer_keep_alive)
940 if (min_peer_keep_alive >= max_peer_keep_alive) {
941 return CMD_ERR_NO_MATCH;
942 }
943
944 if (min_peer_dead_timer && max_peer_dead_timer)
945 if (min_peer_dead_timer >= max_peer_dead_timer) {
946 return CMD_ERR_NO_MATCH;
947 }
948
949 /* Handle the arguments */
950 PCEP_VTYSH_INT_ARG_CHECK(keep_alive_str, keep_alive,
951 pce_config->keep_alive_seconds, 0, 64);
952 PCEP_VTYSH_INT_ARG_CHECK(min_peer_keep_alive_str, min_peer_keep_alive,
953 pce_config->min_keep_alive_seconds, 0, 256);
954 PCEP_VTYSH_INT_ARG_CHECK(max_peer_keep_alive_str, max_peer_keep_alive,
955 pce_config->max_keep_alive_seconds, 0, 256);
956 PCEP_VTYSH_INT_ARG_CHECK(dead_timer_str, dead_timer,
957 pce_config->dead_timer_seconds, 3, 256);
958 PCEP_VTYSH_INT_ARG_CHECK(min_peer_dead_timer_str, min_peer_dead_timer,
959 pce_config->min_dead_timer_seconds, 3, 256);
960 PCEP_VTYSH_INT_ARG_CHECK(max_peer_dead_timer_str, max_peer_dead_timer,
961 pce_config->max_dead_timer_seconds, 3, 256);
962 PCEP_VTYSH_INT_ARG_CHECK(pcep_request_str, pcep_request,
963 pce_config->pcep_request_time_seconds, 0, 121);
964 PCEP_VTYSH_INT_ARG_CHECK(
965 session_timeout_interval_str, session_timeout_interval,
966 pce_config->session_timeout_inteval_seconds, 0, 121);
967 PCEP_VTYSH_INT_ARG_CHECK(delegation_timeout_str, delegation_timeout,
968 pce_config->delegation_timeout_seconds, 0, 61);
969
970 return CMD_SUCCESS;
971 }
972
973 static int path_pcep_cli_pcc(struct vty *vty)
974 {
975 VTY_PUSH_CONTEXT_NULL(PCEP_PCC_NODE);
976
977 return CMD_SUCCESS;
978 }
979
980 static int path_pcep_cli_pcc_delete(struct vty *vty)
981 {
982 /* Clear the pce_connections */
983 memset(&pce_connections_g, 0, sizeof(pce_connections_g));
984 pcc_msd_configured_g = false;
985
986 pcep_ctrl_remove_pcc(pcep_g->fpt, NULL);
987
988 return CMD_SUCCESS;
989 }
990
991 static int path_pcep_cli_pcc_pcc_msd(struct vty *vty, const char *msd_str,
992 long msd)
993 {
994 pcc_msd_configured_g = true;
995 PCEP_VTYSH_INT_ARG_CHECK(msd_str, msd, pcc_msd_g, 0, 33);
996
997 return CMD_SUCCESS;
998 }
999
1000 static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name,
1001 const char *precedence_str,
1002 long precedence)
1003 {
1004 /* Check if the pcc-peer exists */
1005 struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
1006 if (pce_opts_cli == NULL) {
1007 vty_out(vty, "%% PCE [%s] does not exist.\n", peer_name);
1008 return CMD_WARNING;
1009 }
1010 struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
1011
1012 /* Check if the pcc-peer is duplicated */
1013 if (pcep_cli_pcc_has_pce(peer_name)) {
1014 vty_out(vty, "%% The peer [%s] has already been configured.\n",
1015 peer_name);
1016 return CMD_WARNING;
1017 }
1018
1019 /* Get the optional precedence argument */
1020 pce_opts->precedence = DEFAULT_PCE_PRECEDENCE;
1021 PCEP_VTYSH_INT_ARG_CHECK(precedence_str, precedence,
1022 pce_opts->precedence, 0, 256);
1023
1024 /* Finalize the pce_opts config values */
1025 pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
1026 pcep_cli_add_pce_connection(&pce_opts_cli->pce_opts);
1027
1028 /* Verify the PCE has the IP set */
1029 struct in6_addr zero_v6_addr;
1030 memset(&zero_v6_addr, 0, sizeof(struct in6_addr));
1031 if (memcmp(&pce_opts->addr.ip, &zero_v6_addr, IPADDRSZ(&pce_opts->addr))
1032 == 0) {
1033 vty_out(vty,
1034 "%% The peer [%s] does not have an IP set and cannot be used until it does.\n",
1035 peer_name);
1036 return CMD_WARNING;
1037 }
1038
1039 /* Update the pcc_opts with the source ip, port, and msd */
1040 struct pcc_opts *pcc_opts_copy =
1041 XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts));
1042 memcpy(&pcc_opts_copy->addr,
1043 &pce_opts_cli->pce_opts.config_opts.source_ip,
1044 sizeof(pcc_opts_copy->addr));
1045 pcc_opts_copy->msd = pcc_msd_g;
1046 pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port;
1047 if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) {
1048 return CMD_WARNING;
1049 }
1050
1051 /* Send a copy of the pce_opts, this one is only used for the CLI */
1052 struct pce_opts *pce_opts_copy =
1053 XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
1054 memcpy(pce_opts_copy, pce_opts, sizeof(struct pce_opts));
1055 if (pcep_ctrl_update_pce_options(pcep_g->fpt, pce_opts_copy)) {
1056 return CMD_WARNING;
1057 }
1058
1059 return CMD_SUCCESS;
1060 }
1061
1062 static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
1063 const char *peer_name,
1064 const char *precedence_str,
1065 long precedence)
1066 {
1067 /* Check if the pcc-peer is connected to the PCC */
1068 if (!pcep_cli_pcc_has_pce(peer_name)) {
1069 vty_out(vty,
1070 "%% WARN: The peer [%s] is not connected to the PCC.\n",
1071 peer_name);
1072 return CMD_WARNING;
1073 }
1074
1075 struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
1076 pcep_cli_remove_pce_connection(&pce_opts_cli->pce_opts);
1077
1078 /* Send a copy of the pce_opts, this one is used for CLI only */
1079 struct pce_opts *pce_opts_copy =
1080 XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
1081 memcpy(pce_opts_copy, &pce_opts_cli->pce_opts, sizeof(struct pce_opts));
1082 pcep_ctrl_remove_pcc(pcep_g->fpt, pce_opts_copy);
1083
1084 return CMD_SUCCESS;
1085 }
1086
1087 static int path_pcep_cli_show_srte_pcep_pcc(struct vty *vty)
1088 {
1089 vty_out(vty, "pcc msd %d\n", pcc_msd_g);
1090
1091 return CMD_SUCCESS;
1092 }
1093
1094 /* Internal util function to print pcep capabilities to a buffer */
1095 static void print_pcep_capabilities(char *buf, size_t buf_len,
1096 pcep_configuration *config)
1097 {
1098 if (config->support_stateful_pce_lsp_update) {
1099 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_STATEFUL);
1100 }
1101 if (config->support_include_db_version) {
1102 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_INCL_DB_VER);
1103 }
1104 if (config->support_lsp_triggered_resync) {
1105 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_TRIGGERED);
1106 }
1107 if (config->support_lsp_delta_sync) {
1108 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_DELTA);
1109 }
1110 if (config->support_pce_triggered_initial_sync) {
1111 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCE_TRIGGERED);
1112 }
1113 if (config->support_sr_te_pst) {
1114 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_SR_TE_PST);
1115 }
1116 if (config->pcc_can_resolve_nai_to_sid) {
1117 csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCC_RESOLVE_NAI);
1118 }
1119 }
1120
1121 /* Internal util function to print a pcep session */
1122 static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
1123 struct pcep_pcc_info *pcc_info)
1124 {
1125 char buf[1024];
1126 buf[0] = '\0';
1127
1128 vty_out(vty, "\nPCE %s\n", pce_opts->pce_name);
1129
1130 /* PCE IP */
1131 if (IS_IPADDR_V4(&pce_opts->addr)) {
1132 vty_out(vty, " PCE IP %pI4 port %d\n",
1133 &pce_opts->addr.ipaddr_v4, pce_opts->port);
1134 } else if (IS_IPADDR_V6(&pce_opts->addr)) {
1135 vty_out(vty, " PCE IPv6 %pI6 port %d\n",
1136 &pce_opts->addr.ipaddr_v6, pce_opts->port);
1137 }
1138
1139 /* PCC IP */
1140 if (IS_IPADDR_V4(&pcc_info->pcc_addr)) {
1141 vty_out(vty, " PCC IP %pI4 port %d\n",
1142 &pcc_info->pcc_addr.ipaddr_v4, pcc_info->pcc_port);
1143 } else if (IS_IPADDR_V6(&pcc_info->pcc_addr)) {
1144 vty_out(vty, " PCC IPv6 %pI6 port %d\n",
1145 &pcc_info->pcc_addr.ipaddr_v6, pcc_info->pcc_port);
1146 }
1147 vty_out(vty, " PCC MSD %d\n", pcc_info->msd);
1148
1149 if (pcc_info->status == PCEP_PCC_OPERATING) {
1150 vty_out(vty, " Session Status UP\n");
1151 } else {
1152 vty_out(vty, " Session Status %s\n",
1153 pcc_status_name(pcc_info->status));
1154 }
1155
1156 if (pcc_info->is_best_multi_pce) {
1157 vty_out(vty, " Precedence %d, best candidate\n",
1158 ((pcc_info->precedence > 0) ? pcc_info->precedence
1159 : DEFAULT_PCE_PRECEDENCE));
1160 } else {
1161 vty_out(vty, " Precedence %d\n",
1162 ((pcc_info->precedence > 0) ? pcc_info->precedence
1163 : DEFAULT_PCE_PRECEDENCE));
1164 }
1165 vty_out(vty, " Confidence %s\n",
1166 ((pcc_info->previous_best) ? "low"
1167 : "normal"));
1168
1169 /* PCEPlib pcep session values, get a thread safe copy of the counters
1170 */
1171 pcep_session *session =
1172 pcep_ctrl_get_pcep_session(pcep_g->fpt, pcc_info->pcc_id);
1173
1174 /* Config Options values */
1175 struct pcep_config_group_opts *config_opts = &pce_opts->config_opts;
1176 if (session != NULL) {
1177 vty_out(vty, " Timer: KeepAlive config %d, pce-negotiated %d\n",
1178 config_opts->keep_alive_seconds,
1179 session->pcc_config
1180 .keep_alive_pce_negotiated_timer_seconds);
1181 vty_out(vty, " Timer: DeadTimer config %d, pce-negotiated %d\n",
1182 config_opts->dead_timer_seconds,
1183 session->pcc_config.dead_timer_pce_negotiated_seconds);
1184 } else {
1185 vty_out(vty, " Timer: KeepAlive %d\n",
1186 config_opts->keep_alive_seconds);
1187 vty_out(vty, " Timer: DeadTimer %d\n",
1188 config_opts->dead_timer_seconds);
1189 }
1190 vty_out(vty, " Timer: PcRequest %d\n",
1191 config_opts->pcep_request_time_seconds);
1192 vty_out(vty, " Timer: SessionTimeout Interval %d\n",
1193 config_opts->session_timeout_inteval_seconds);
1194 vty_out(vty, " Timer: Delegation Timeout %d\n",
1195 config_opts->delegation_timeout_seconds);
1196 if (strlen(config_opts->tcp_md5_auth) > 0) {
1197 vty_out(vty, " TCP MD5 Auth Str: %s\n",
1198 config_opts->tcp_md5_auth);
1199 } else {
1200 vty_out(vty, " No TCP MD5 Auth\n");
1201 }
1202
1203 if (config_opts->draft07) {
1204 vty_out(vty, " PCE SR Version draft07\n");
1205 } else {
1206 vty_out(vty, " PCE SR Version draft16 and RFC8408\n");
1207 }
1208
1209 vty_out(vty, " Next PcReq ID %d\n", pcc_info->next_reqid);
1210 vty_out(vty, " Next PLSP ID %d\n", pcc_info->next_plspid);
1211
1212 if (session != NULL) {
1213 if (pcc_info->status == PCEP_PCC_SYNCHRONIZING
1214 || pcc_info->status == PCEP_PCC_OPERATING) {
1215 time_t current_time = time(NULL);
1216 struct tm lt = {0};
1217 /* Just for the timezone */
1218 localtime_r(&current_time, &lt);
1219 gmtime_r(&session->time_connected, &lt);
1220 vty_out(vty,
1221 " Connected for %u seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
1222 (uint32_t)(current_time
1223 - session->time_connected),
1224 lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
1225 lt.tm_hour, lt.tm_min, lt.tm_sec);
1226 }
1227
1228 /* PCC capabilities */
1229 buf[0] = '\0';
1230 int index = 0;
1231 if (config_opts->pce_initiated) {
1232 index += csnprintfrr(buf, sizeof(buf), "%s",
1233 PCEP_CLI_CAP_PCC_PCE_INITIATED);
1234 } else {
1235 index += csnprintfrr(buf, sizeof(buf), "%s",
1236 PCEP_CLI_CAP_PCC_INITIATED);
1237 }
1238 print_pcep_capabilities(buf, sizeof(buf) - index,
1239 &session->pcc_config);
1240 vty_out(vty, " PCC Capabilities:%s\n", buf);
1241
1242 /* PCE capabilities */
1243 buf[0] = '\0';
1244 print_pcep_capabilities(buf, sizeof(buf), &session->pce_config);
1245 if (buf[0] != '\0') {
1246 vty_out(vty, " PCE Capabilities:%s\n", buf);
1247 }
1248 XFREE(MTYPE_PCEP, session);
1249 } else {
1250 vty_out(vty, " Detailed session information not available\n");
1251 }
1252
1253 /* Message Counters, get a thread safe copy of the counters */
1254 struct counters_group *group =
1255 pcep_ctrl_get_counters(pcep_g->fpt, pcc_info->pcc_id);
1256
1257 if (group != NULL) {
1258 struct counters_subgroup *rx_msgs =
1259 find_subgroup(group, COUNTER_SUBGROUP_ID_RX_MSG);
1260 struct counters_subgroup *tx_msgs =
1261 find_subgroup(group, COUNTER_SUBGROUP_ID_TX_MSG);
1262
1263 if (rx_msgs != NULL && tx_msgs != NULL) {
1264 vty_out(vty, " PCEP Message Statistics\n");
1265 vty_out(vty, " %27s %6s\n", "Sent", "Rcvd");
1266 for (int i = 0; i < rx_msgs->max_counters; i++) {
1267 struct counter *rx_counter =
1268 rx_msgs->counters[i];
1269 struct counter *tx_counter =
1270 tx_msgs->counters[i];
1271 if (rx_counter != NULL && tx_counter != NULL) {
1272 vty_out(vty, " %20s: %5d %5d\n",
1273 tx_counter->counter_name,
1274 tx_counter->counter_value,
1275 rx_counter->counter_value);
1276 }
1277 }
1278 vty_out(vty, " %20s: %5d %5d\n", "Total",
1279 subgroup_counters_total(tx_msgs),
1280 subgroup_counters_total(rx_msgs));
1281 }
1282 pcep_lib_free_counters(group);
1283 } else {
1284 vty_out(vty, " Counters not available\n");
1285 }
1286
1287 XFREE(MTYPE_PCEP, pcc_info);
1288 }
1289
1290 static int path_pcep_cli_show_srte_pcep_session(struct vty *vty,
1291 const char *pcc_peer)
1292 {
1293 struct pce_opts_cli *pce_opts_cli;
1294 struct pcep_pcc_info *pcc_info;
1295
1296 /* Only show 1 PCEP session */
1297 if (pcc_peer != NULL) {
1298 pce_opts_cli = pcep_cli_find_pce(pcc_peer);
1299 if (pce_opts_cli == NULL) {
1300 vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
1301 return CMD_WARNING;
1302 }
1303
1304 if (!pcep_cli_pcc_has_pce(pcc_peer)) {
1305 vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
1306 pcc_peer);
1307 return CMD_WARNING;
1308 }
1309
1310 pcc_info = pcep_ctrl_get_pcc_info(pcep_g->fpt, pcc_peer);
1311 if (pcc_info == NULL) {
1312 vty_out(vty,
1313 "%% Cannot retrieve PCEP session info for PCE [%s]\n",
1314 pcc_peer);
1315 return CMD_WARNING;
1316 }
1317
1318 print_pcep_session(vty, &pce_opts_cli->pce_opts, pcc_info);
1319
1320 return CMD_SUCCESS;
1321 }
1322
1323 /* Show all PCEP sessions */
1324 struct pce_opts *pce_opts;
1325 int num_pcep_sessions_conf = 0;
1326 int num_pcep_sessions_conn = 0;
1327 for (int i = 0; i < MAX_PCC; i++) {
1328 pce_opts = pce_connections_g.connections[i];
1329 if (pce_opts == NULL) {
1330 continue;
1331 }
1332
1333 pcc_info =
1334 pcep_ctrl_get_pcc_info(pcep_g->fpt, pce_opts->pce_name);
1335 if (pcc_info == NULL) {
1336 vty_out(vty,
1337 "%% Cannot retrieve PCEP session info for PCE [%s]\n",
1338 pce_opts->pce_name);
1339 continue;
1340 }
1341
1342 num_pcep_sessions_conn +=
1343 pcc_info->status == PCEP_PCC_OPERATING ? 1 : 0;
1344 num_pcep_sessions_conf++;
1345 print_pcep_session(vty, pce_opts, pcc_info);
1346 }
1347
1348 vty_out(vty, "PCEP Sessions => Configured %d ; Connected %d\n",
1349 num_pcep_sessions_conf, num_pcep_sessions_conn);
1350
1351 return CMD_SUCCESS;
1352 }
1353
1354 static int path_pcep_cli_clear_srte_pcep_session(struct vty *vty,
1355 const char *pcc_peer)
1356 {
1357 struct pce_opts_cli *pce_opts_cli;
1358
1359 /* Only clear 1 PCEP session */
1360 if (pcc_peer != NULL) {
1361 pce_opts_cli = pcep_cli_find_pce(pcc_peer);
1362 if (pce_opts_cli == NULL) {
1363 vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
1364 return CMD_WARNING;
1365 }
1366
1367 if (!pcep_cli_pcc_has_pce(pcc_peer)) {
1368 vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
1369 pcc_peer);
1370 return CMD_WARNING;
1371 }
1372
1373 pcep_ctrl_reset_pcc_session(pcep_g->fpt,
1374 pce_opts_cli->pce_opts.pce_name);
1375 vty_out(vty, "PCEP session cleared for peer %s\n", pcc_peer);
1376
1377 return CMD_SUCCESS;
1378 }
1379
1380 /* Clear all PCEP sessions */
1381 struct pce_opts *pce_opts;
1382 int num_pcep_sessions = 0;
1383 for (int i = 0; i < MAX_PCC; i++) {
1384 pce_opts = pce_connections_g.connections[i];
1385 if (pce_opts == NULL) {
1386 continue;
1387 }
1388
1389 num_pcep_sessions++;
1390 pcep_ctrl_reset_pcc_session(pcep_g->fpt, pce_opts->pce_name);
1391 vty_out(vty, "PCEP session cleared for peer %s\n",
1392 pce_opts->pce_name);
1393 }
1394
1395 vty_out(vty, "Cleared [%d] PCEP sessions\n", num_pcep_sessions);
1396
1397 return CMD_SUCCESS;
1398 }
1399
1400 /*
1401 * Config Write functions
1402 */
1403
1404 int pcep_cli_debug_config_write(struct vty *vty)
1405 {
1406 char buff[128] = "";
1407
1408 if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
1409 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
1410 csnprintfrr(buff, sizeof(buff), " %s",
1411 PCEP_VTYSH_ARG_BASIC);
1412 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
1413 csnprintfrr(buff, sizeof(buff), " %s",
1414 PCEP_VTYSH_ARG_PATH);
1415 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
1416 csnprintfrr(buff, sizeof(buff), " %s",
1417 PCEP_VTYSH_ARG_MESSAGE);
1418 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
1419 csnprintfrr(buff, sizeof(buff), " %s",
1420 PCEP_VTYSH_ARG_PCEPLIB);
1421 vty_out(vty, "debug pathd pcep%s\n", buff);
1422 buff[0] = 0;
1423 return 1;
1424 }
1425
1426 return 0;
1427 }
1428
1429 int pcep_cli_debug_set_all(uint32_t flags, bool set)
1430 {
1431 DEBUG_FLAGS_SET(&pcep_g->dbg, flags, set);
1432
1433 /* If all modes have been turned off, don't preserve options. */
1434 if (!DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_ALL))
1435 DEBUG_CLEAR(&pcep_g->dbg);
1436
1437 return 0;
1438 }
1439
1440 int pcep_cli_pcep_config_write(struct vty *vty)
1441 {
1442 vty_out(vty, " pcep\n");
1443 pcep_cli_pcep_pce_config_write(vty);
1444 pcep_cli_pce_config_write(vty);
1445 pcep_cli_pcc_config_write(vty);
1446 vty_out(vty, " exit\n");
1447 return 1;
1448 }
1449
1450 int pcep_cli_pcc_config_write(struct vty *vty)
1451 {
1452 struct pce_opts *pce_opts;
1453 char buf[128] = "";
1454 int lines = 0;
1455
1456 /* The MSD, nor any PCE peers have been configured on the PCC */
1457 if (!pcc_msd_configured_g && pce_connections_g.num_connections == 0) {
1458 return lines;
1459 }
1460
1461 vty_out(vty, " pcc\n");
1462 lines++;
1463
1464 /* Prepare the MSD, if present */
1465 if (pcc_msd_configured_g) {
1466 vty_out(vty, " %s %d\n", PCEP_VTYSH_ARG_MSD, pcc_msd_g);
1467 lines++;
1468 }
1469
1470 if (pce_connections_g.num_connections == 0) {
1471 goto exit;
1472 }
1473
1474 buf[0] = 0;
1475 for (int i = 0; i < MAX_PCC; i++) {
1476 pce_opts = pce_connections_g.connections[i];
1477 if (pce_opts == NULL) {
1478 continue;
1479 }
1480
1481 /* Only show the PCEs configured in the pcc sub-command */
1482 if (!pcep_cli_pcc_has_pce(pce_opts->pce_name)) {
1483 continue;
1484 }
1485
1486 csnprintfrr(buf, sizeof(buf), " peer %s",
1487 pce_opts->pce_name);
1488 if (pce_opts->precedence > 0
1489 && pce_opts->precedence != DEFAULT_PCE_PRECEDENCE) {
1490 csnprintfrr(buf, sizeof(buf), " %s %d",
1491 PCEP_VTYSH_ARG_PRECEDENCE,
1492 pce_opts->precedence);
1493 }
1494 vty_out(vty, "%s\n", buf);
1495 lines++;
1496 buf[0] = 0;
1497 }
1498 exit:
1499 vty_out(vty, " exit\n");
1500
1501 return lines;
1502 }
1503
1504 /* Internal function used by pcep_cli_pce_config_write()
1505 * and pcep_cli_pcep_pce_config_write() */
1506 static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
1507 char *buf, size_t buf_len)
1508 {
1509 int lines = 0;
1510
1511 if (group_opts->source_ip.ipa_type != IPADDR_NONE
1512 || group_opts->source_port != 0) {
1513 csnprintfrr(buf, buf_len, " ");
1514 if (IS_IPADDR_V4(&group_opts->source_ip)) {
1515 csnprintfrr(buf, buf_len, " %s %s %pI4",
1516 PCEP_VTYSH_ARG_SOURCE_ADDRESS,
1517 PCEP_VTYSH_ARG_IP,
1518 &group_opts->source_ip.ipaddr_v4);
1519 } else if (IS_IPADDR_V6(&group_opts->source_ip)) {
1520 csnprintfrr(buf, buf_len, " %s %s %pI6",
1521 PCEP_VTYSH_ARG_SOURCE_ADDRESS,
1522 PCEP_VTYSH_ARG_IPV6,
1523 &group_opts->source_ip.ipaddr_v6);
1524 }
1525 if (group_opts->source_port > 0) {
1526 csnprintfrr(buf, buf_len, " %s %d", PCEP_VTYSH_ARG_PORT,
1527 group_opts->source_port);
1528 }
1529 csnprintfrr(buf, buf_len, "\n");
1530 lines++;
1531 }
1532 /* Group the keep-alive together for devman */
1533 if ((group_opts->keep_alive_seconds > 0)
1534 || (group_opts->min_keep_alive_seconds > 0)
1535 || (group_opts->max_keep_alive_seconds > 0)) {
1536 csnprintfrr(buf, buf_len, " %s", PCEP_VTYSH_ARG_TIMER);
1537
1538 if (group_opts->keep_alive_seconds > 0) {
1539 csnprintfrr(buf, buf_len, " %s %d",
1540 PCEP_VTYSH_ARG_KEEP_ALIVE,
1541 group_opts->keep_alive_seconds);
1542 }
1543 if (group_opts->min_keep_alive_seconds > 0) {
1544 csnprintfrr(buf, buf_len, " %s %d",
1545 PCEP_VTYSH_ARG_KEEP_ALIVE_MIN,
1546 group_opts->min_keep_alive_seconds);
1547 }
1548 if (group_opts->max_keep_alive_seconds > 0) {
1549 csnprintfrr(buf, buf_len, " %s %d",
1550 PCEP_VTYSH_ARG_KEEP_ALIVE_MAX,
1551 group_opts->max_keep_alive_seconds);
1552 }
1553 csnprintfrr(buf, buf_len, "\n");
1554 lines++;
1555 }
1556
1557 /* Group the dead-timer together for devman */
1558 if ((group_opts->dead_timer_seconds > 0)
1559 || (group_opts->min_dead_timer_seconds > 0)
1560 || (group_opts->max_dead_timer_seconds > 0)) {
1561 csnprintfrr(buf, buf_len, " %s", PCEP_VTYSH_ARG_TIMER);
1562
1563 if (group_opts->dead_timer_seconds > 0) {
1564 csnprintfrr(buf, buf_len, " %s %d",
1565 PCEP_VTYSH_ARG_DEAD_TIMER,
1566 group_opts->dead_timer_seconds);
1567 }
1568 if (group_opts->min_dead_timer_seconds > 0) {
1569 csnprintfrr(buf, buf_len, " %s %d",
1570 PCEP_VTYSH_ARG_DEAD_TIMER_MIN,
1571 group_opts->min_dead_timer_seconds);
1572 }
1573 if (group_opts->max_dead_timer_seconds > 0) {
1574 csnprintfrr(buf, buf_len, " %s %d",
1575 PCEP_VTYSH_ARG_DEAD_TIMER_MAX,
1576 group_opts->max_dead_timer_seconds);
1577 }
1578 csnprintfrr(buf, buf_len, "\n");
1579 lines++;
1580 }
1581
1582 if (group_opts->pcep_request_time_seconds > 0) {
1583 csnprintfrr(buf, buf_len, " %s %s %d\n",
1584 PCEP_VTYSH_ARG_TIMER, PCEP_VTYSH_ARG_PCEP_REQUEST,
1585 group_opts->pcep_request_time_seconds);
1586 lines++;
1587 }
1588 if (group_opts->delegation_timeout_seconds > 0) {
1589 csnprintfrr(buf, buf_len, " %s %s %d\n",
1590 PCEP_VTYSH_ARG_TIMER,
1591 PCEP_VTYSH_ARG_DELEGATION_TIMEOUT,
1592 group_opts->delegation_timeout_seconds);
1593 lines++;
1594 }
1595 if (group_opts->session_timeout_inteval_seconds > 0) {
1596 csnprintfrr(buf, buf_len, " %s %s %d\n",
1597 PCEP_VTYSH_ARG_TIMER,
1598 PCEP_VTYSH_ARG_SESSION_TIMEOUT,
1599 group_opts->session_timeout_inteval_seconds);
1600 lines++;
1601 }
1602 if (group_opts->tcp_md5_auth[0] != '\0') {
1603 csnprintfrr(buf, buf_len, " %s %s\n", PCEP_VTYSH_ARG_TCP_MD5,
1604 group_opts->tcp_md5_auth);
1605 lines++;
1606 }
1607 if (group_opts->draft07) {
1608 csnprintfrr(buf, buf_len, " %s\n",
1609 PCEP_VTYSH_ARG_SR_DRAFT07);
1610 lines++;
1611 }
1612 if (group_opts->pce_initiated) {
1613 csnprintfrr(buf, buf_len, " %s\n", PCEP_VTYSH_ARG_PCE_INIT);
1614 lines++;
1615 }
1616
1617 return lines;
1618 }
1619
1620 int pcep_cli_pce_config_write(struct vty *vty)
1621 {
1622 int lines = 0;
1623 char buf[1024] = "";
1624
1625 for (int i = 0; i < MAX_PCE; i++) {
1626 struct pce_opts_cli *pce_opts_cli = pcep_g->pce_opts_cli[i];
1627 if (pce_opts_cli == NULL) {
1628 continue;
1629 }
1630 struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
1631
1632 vty_out(vty, " pce %s\n", pce_opts->pce_name);
1633 if (IS_IPADDR_V6(&pce_opts->addr)) {
1634 vty_out(vty, " %s %s %pI6", PCEP_VTYSH_ARG_ADDRESS,
1635 PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6);
1636 } else if (IS_IPADDR_V4(&pce_opts->addr)) {
1637 vty_out(vty, " address %s %pI4", PCEP_VTYSH_ARG_IP,
1638 &pce_opts->addr.ipaddr_v4);
1639 }
1640 if (pce_opts->port != PCEP_DEFAULT_PORT) {
1641 vty_out(vty, " %s %d", PCEP_VTYSH_ARG_PORT,
1642 pce_opts->port);
1643 }
1644 vty_out(vty, "%s\n", buf);
1645 lines += 2;
1646
1647 if (pce_opts_cli->config_group_name[0] != '\0') {
1648 vty_out(vty, " config %s\n",
1649 pce_opts_cli->config_group_name);
1650 lines++;
1651 }
1652
1653 /* Only display the values configured on the PCE, not the values
1654 * from its optional pce-config-group, nor the default values */
1655 lines += pcep_cli_print_pce_config(
1656 &pce_opts_cli->pce_config_group_opts, buf, sizeof(buf));
1657
1658 vty_out(vty, "%s", buf);
1659 buf[0] = '\0';
1660
1661 vty_out(vty, " exit\n");
1662 }
1663
1664 return lines;
1665 }
1666
1667 int pcep_cli_pcep_pce_config_write(struct vty *vty)
1668 {
1669 int lines = 0;
1670 char buf[1024] = "";
1671
1672 for (int i = 0; i < MAX_PCE; i++) {
1673 struct pcep_config_group_opts *group_opts =
1674 pcep_g->config_group_opts[i];
1675 if (group_opts == NULL) {
1676 continue;
1677 }
1678
1679 vty_out(vty, " pce-config %s\n", group_opts->name);
1680 lines += 1;
1681
1682 lines +=
1683 pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
1684 vty_out(vty, "%s", buf);
1685 buf[0] = 0;
1686
1687 vty_out(vty, " exit\n");
1688 }
1689
1690 return lines;
1691 }
1692
1693 /*
1694 * VTYSH command syntax definitions
1695 * The param names are taken from the path_pcep_cli_clippy.c generated file.
1696 */
1697
1698 DEFPY(show_debugging_pathd_pcep,
1699 show_debugging_pathd_pcep_cmd,
1700 "show debugging pathd-pcep",
1701 SHOW_STR
1702 "State of each debugging option\n"
1703 "pathd pcep module debugging\n")
1704 {
1705 vty_out(vty, "Pathd pcep debugging status:\n");
1706
1707 if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
1708 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
1709 vty_out(vty, " Pathd pcep %s debugging is on\n",
1710 PCEP_VTYSH_ARG_BASIC);
1711 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
1712 vty_out(vty, " Pathd pcep %s debugging is on\n",
1713 PCEP_VTYSH_ARG_PATH);
1714 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
1715 vty_out(vty, " Pathd pcep %s debugging is on\n",
1716 PCEP_VTYSH_ARG_MESSAGE);
1717 if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
1718 vty_out(vty, " Pathd pcep %s debugging is on\n",
1719 PCEP_VTYSH_ARG_PCEPLIB);
1720 }
1721
1722 return CMD_SUCCESS;
1723 }
1724
1725 DEFPY(pcep_cli_debug,
1726 pcep_cli_debug_cmd,
1727 "[no] debug pathd pcep [basic]$basic_str [path]$path_str [message]$message_str [pceplib]$pceplib_str",
1728 NO_STR DEBUG_STR
1729 "pathd debugging\n"
1730 "pcep module debugging\n"
1731 "module basic debugging\n"
1732 "path structures debugging\n"
1733 "pcep message debugging\n"
1734 "pceplib debugging\n")
1735 {
1736 return path_pcep_cli_debug(vty, no, basic_str, path_str, message_str,
1737 pceplib_str);
1738 }
1739
1740 DEFPY(pcep_cli_show_srte_pcep_counters,
1741 pcep_cli_show_srte_pcep_counters_cmd,
1742 "show sr-te pcep counters",
1743 SHOW_STR
1744 "SR-TE info\n"
1745 "PCEP info\n"
1746 "PCEP counters\n")
1747 {
1748 return path_pcep_cli_show_srte_pcep_counters(vty);
1749 }
1750
1751 DEFPY_NOSH(
1752 pcep_cli_pcep,
1753 pcep_cli_pcep_cmd,
1754 "pcep",
1755 "PCEP configuration\n")
1756 {
1757 vty->node = PCEP_NODE;
1758 return CMD_SUCCESS;
1759 }
1760
1761 DEFPY_NOSH(
1762 pcep_cli_pcep_pce_config,
1763 pcep_cli_pcep_pce_config_cmd,
1764 "pce-config WORD$name",
1765 "Shared configuration\n"
1766 "Shared configuration name\n")
1767 {
1768 return path_pcep_cli_pcep_pce_config(vty, name);
1769 }
1770
1771 DEFPY(pcep_cli_pcep_no_pce_config,
1772 pcep_cli_pcep_no_pce_config_cmd,
1773 "no pce-config WORD$name",
1774 NO_STR
1775 "Shared configuration\n"
1776 "Shared configuration name\n")
1777 {
1778 return path_pcep_cli_pcep_pce_config_delete(vty, name);
1779 }
1780
1781 DEFPY(pcep_cli_show_srte_pcep_pce_config,
1782 pcep_cli_show_srte_pcep_pce_config_cmd,
1783 "show sr-te pcep pce-config [<default|WORD>$name]",
1784 SHOW_STR
1785 "SR-TE info\n"
1786 "PCEP info\n"
1787 "Show shared PCE configuration\n"
1788 "Show default hard-coded values\n"
1789 "Shared configuration name\n")
1790 {
1791 return path_pcep_cli_show_srte_pcep_pce_config(vty, name);
1792 }
1793
1794 DEFPY_NOSH(
1795 pcep_cli_pce,
1796 pcep_cli_pce_cmd,
1797 "pce WORD$name",
1798 "PCE configuration, address sub-config is mandatory\n"
1799 "PCE name\n")
1800 {
1801 return path_pcep_cli_pce(vty, name);
1802 }
1803
1804 DEFPY(pcep_cli_no_pce,
1805 pcep_cli_no_pce_cmd,
1806 "no pce WORD$name",
1807 NO_STR
1808 "PCE configuration, address sub-config is mandatory\n"
1809 "PCE name\n")
1810 {
1811 return path_pcep_cli_pce_delete(vty, name);
1812 }
1813
1814 DEFPY(pcep_cli_show_srte_pcep_pce,
1815 pcep_cli_show_srte_pcep_pce_cmd,
1816 "show sr-te pcep pce [WORD$name]",
1817 SHOW_STR
1818 "SR-TE info\n"
1819 "PCEP info\n"
1820 "Show detailed pce values\n"
1821 "pce name\n")
1822 {
1823 return path_pcep_cli_show_srte_pcep_pce(vty, name);
1824 }
1825
1826 DEFPY(pcep_cli_peer_sr_draft07,
1827 pcep_cli_peer_sr_draft07_cmd,
1828 "sr-draft07",
1829 "Configure PCC to send PCEP Open with SR draft07\n")
1830 {
1831 return path_pcep_cli_peer_sr_draft07(vty);
1832 }
1833
1834 DEFPY(pcep_cli_peer_pce_initiated,
1835 pcep_cli_peer_pce_initiated_cmd,
1836 "pce-initiated",
1837 "Configure PCC to accept PCE initiated LSPs\n")
1838 {
1839 return path_pcep_cli_peer_pce_initiated(vty);
1840 }
1841
1842 DEFPY(pcep_cli_peer_tcp_md5_auth,
1843 pcep_cli_peer_tcp_md5_auth_cmd,
1844 "tcp-md5-auth WORD",
1845 "Configure PCC TCP-MD5 RFC2385 Authentication\n"
1846 "TCP-MD5 Authentication string\n")
1847 {
1848 return path_pcep_cli_peer_tcp_md5_auth(vty, tcp_md5_auth);
1849 }
1850
1851 DEFPY(pcep_cli_peer_address,
1852 pcep_cli_peer_address_cmd,
1853 "address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)]",
1854 "PCE IP Address configuration, mandatory configuration\n"
1855 "PCE IPv4 address\n"
1856 "Remote PCE server IPv4 address\n"
1857 "PCE IPv6 address\n"
1858 "Remote PCE server IPv6 address\n"
1859 "Remote PCE server port\n"
1860 "Remote PCE server port value\n")
1861 {
1862 return path_pcep_cli_peer_address(vty, ip_str, &ip, ipv6_str, &ipv6,
1863 port_str, port);
1864 }
1865
1866 DEFPY(pcep_cli_peer_source_address,
1867 pcep_cli_peer_source_address_cmd,
1868 "source-address [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)]",
1869 "PCE source IP Address configuration\n"
1870 "PCE source IPv4 address\n"
1871 "PCE source IPv4 address value\n"
1872 "PCE source IPv6 address\n"
1873 "PCE source IPv6 address value\n"
1874 "Source PCE server port\n"
1875 "Source PCE server port value\n")
1876 {
1877 return path_pcep_cli_peer_source_address(vty, ip_str, &ip, ipv6_str,
1878 &ipv6, port_str, port);
1879 }
1880
1881 DEFPY(pcep_cli_peer_pcep_pce_config_ref,
1882 pcep_cli_peer_pcep_pce_config_ref_cmd,
1883 "config WORD$name",
1884 "PCE shared configuration to use\n"
1885 "Shared configuration name\n")
1886 {
1887 return path_pcep_cli_peer_pcep_pce_config_ref(vty, name);
1888 }
1889
1890 DEFPY(pcep_cli_peer_timers,
1891 pcep_cli_peer_timers_cmd,
1892 "timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] "
1893 "[dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] "
1894 "[pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)]",
1895 "PCE PCEP Session Timers configuration\n"
1896 "PCC Keep Alive Timer\n"
1897 "PCC Keep Alive Timer value in seconds\n"
1898 "Min Acceptable PCE Keep Alive Timer\n"
1899 "Min Acceptable PCE Keep Alive Timer value in seconds\n"
1900 "Max Acceptable PCE Keep Alive Timer\n"
1901 "Max Acceptable PCE Keep Alive Timer value in seconds\n"
1902 "PCC Dead Timer\n"
1903 "PCC Dead Timer value in seconds\n"
1904 "Min Acceptable PCE Dead Timer\n"
1905 "Min Acceptable PCE Dead Timer value in seconds\n"
1906 "Max Acceptable PCE Dead Timer\n"
1907 "Max Acceptable PCE Dead Timer value in seconds\n"
1908 "PCC PCEP Request Timer\n"
1909 "PCC PCEP Request Timer value in seconds\n"
1910 "PCC Session Timeout Interval\n"
1911 "PCC Session Timeout Interval value in seconds\n"
1912 "Multi-PCE delegation timeout\n"
1913 "Multi-PCE delegation timeout value in seconds\n")
1914 {
1915 return path_pcep_cli_peer_timers(
1916 vty, keep_alive_str, keep_alive, min_peer_keep_alive_str,
1917 min_peer_keep_alive, max_peer_keep_alive_str,
1918 max_peer_keep_alive, dead_timer_str, dead_timer,
1919 min_peer_dead_timer_str, min_peer_dead_timer,
1920 max_peer_dead_timer_str, max_peer_dead_timer, pcep_request_str,
1921 pcep_request, session_timeout_interval_str,
1922 session_timeout_interval, delegation_timeout_str,
1923 delegation_timeout);
1924 }
1925
1926 DEFPY_NOSH(
1927 pcep_cli_pcc,
1928 pcep_cli_pcc_cmd,
1929 "pcc",
1930 "PCC configuration\n")
1931 {
1932 return path_pcep_cli_pcc(vty);
1933 }
1934
1935 DEFPY(pcep_cli_no_pcc,
1936 pcep_cli_no_pcc_cmd,
1937 "no pcc",
1938 NO_STR
1939 "PCC configuration\n")
1940 {
1941 return path_pcep_cli_pcc_delete(vty);
1942 }
1943
1944 DEFPY(pcep_cli_pcc_pcc_msd,
1945 pcep_cli_pcc_pcc_msd_cmd,
1946 "msd (1-32)",
1947 "PCC maximum SID depth \n"
1948 "PCC maximum SID depth value\n")
1949 {
1950 return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd);
1951 }
1952
1953 DEFPY(pcep_cli_pcc_pcc_peer,
1954 pcep_cli_pcc_pcc_peer_cmd,
1955 "[no] peer WORD [precedence (1-255)]",
1956 NO_STR
1957 "PCC PCE peer\n"
1958 "PCC PCE name\n"
1959 "PCC Multi-PCE precedence\n"
1960 "PCE precedence\n")
1961 {
1962 if (no != NULL) {
1963 return path_pcep_cli_pcc_pcc_peer_delete(
1964 vty, peer, precedence_str, precedence);
1965 } else {
1966 return path_pcep_cli_pcc_pcc_peer(vty, peer, precedence_str,
1967 precedence);
1968 }
1969 }
1970
1971 DEFPY(pcep_cli_show_srte_pcc,
1972 pcep_cli_show_srte_pcc_cmd,
1973 "show sr-te pcep pcc",
1974 SHOW_STR
1975 "SR-TE info\n"
1976 "PCEP info\n"
1977 "Show current PCC configuration\n")
1978 {
1979 return path_pcep_cli_show_srte_pcep_pcc(vty);
1980 }
1981
1982 DEFPY(pcep_cli_show_srte_pcep_session,
1983 pcep_cli_show_srte_pcep_session_cmd,
1984 "show sr-te pcep session [WORD]$pce",
1985 SHOW_STR
1986 "SR-TE info\n"
1987 "PCEP info\n"
1988 "Show PCEP Session information\n"
1989 "PCE name\n")
1990 {
1991 return path_pcep_cli_show_srte_pcep_session(vty, pce);
1992 }
1993
1994 DEFPY(pcep_cli_clear_srte_pcep_session,
1995 pcep_cli_clear_srte_pcep_session_cmd,
1996 "clear sr-te pcep session [WORD]$pce",
1997 CLEAR_STR
1998 "SR-TE\n"
1999 "PCEP\n"
2000 "Reset PCEP connection\n"
2001 "PCE name\n")
2002 {
2003 return path_pcep_cli_clear_srte_pcep_session(vty, pce);
2004 }
2005
2006 void pcep_cli_init(void)
2007 {
2008 hook_register(pathd_srte_config_write, pcep_cli_pcep_config_write);
2009 hook_register(nb_client_debug_config_write,
2010 pcep_cli_debug_config_write);
2011 hook_register(nb_client_debug_set_all, pcep_cli_debug_set_all);
2012
2013 memset(&pce_connections_g, 0, sizeof(pce_connections_g));
2014
2015 install_node(&pcep_node);
2016 install_node(&pcep_pcc_node);
2017 install_node(&pcep_pce_node);
2018 install_node(&pcep_pce_config_node);
2019
2020 install_default(PCEP_PCE_CONFIG_NODE);
2021 install_default(PCEP_PCE_NODE);
2022 install_default(PCEP_PCC_NODE);
2023 install_default(PCEP_NODE);
2024
2025 install_element(SR_TRAFFIC_ENG_NODE, &pcep_cli_pcep_cmd);
2026
2027 /* PCEP configuration group related configuration commands */
2028 install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
2029 install_element(PCEP_NODE, &pcep_cli_pcep_no_pce_config_cmd);
2030 install_element(PCEP_PCE_CONFIG_NODE,
2031 &pcep_cli_peer_source_address_cmd);
2032 install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_timers_cmd);
2033 install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_sr_draft07_cmd);
2034 install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_pce_initiated_cmd);
2035 install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
2036
2037 /* PCE peer related configuration commands */
2038 install_element(PCEP_NODE, &pcep_cli_pce_cmd);
2039 install_element(PCEP_NODE, &pcep_cli_no_pce_cmd);
2040 install_element(PCEP_PCE_NODE, &pcep_cli_peer_address_cmd);
2041 install_element(PCEP_PCE_NODE, &pcep_cli_peer_source_address_cmd);
2042 install_element(PCEP_PCE_NODE, &pcep_cli_peer_pcep_pce_config_ref_cmd);
2043 install_element(PCEP_PCE_NODE, &pcep_cli_peer_timers_cmd);
2044 install_element(PCEP_PCE_NODE, &pcep_cli_peer_sr_draft07_cmd);
2045 install_element(PCEP_PCE_NODE, &pcep_cli_peer_pce_initiated_cmd);
2046 install_element(PCEP_PCE_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
2047
2048 /* PCC related configuration commands */
2049 install_element(ENABLE_NODE, &pcep_cli_show_srte_pcc_cmd);
2050 install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
2051 install_element(PCEP_NODE, &pcep_cli_no_pcc_cmd);
2052 install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd);
2053 install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_msd_cmd);
2054
2055 /* Top commands */
2056 install_element(CONFIG_NODE, &pcep_cli_debug_cmd);
2057 install_element(ENABLE_NODE, &pcep_cli_debug_cmd);
2058 install_element(ENABLE_NODE, &show_debugging_pathd_pcep_cmd);
2059 install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_counters_cmd);
2060 install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_config_cmd);
2061 install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_cmd);
2062 install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_session_cmd);
2063 install_element(ENABLE_NODE, &pcep_cli_clear_srte_pcep_session_cmd);
2064 }