]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_cli.c
45f4ac7ab8da50d856ad1276fb71f1b9b2e64a44
[mirror_frr.git] / pathd / path_cli.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020 NetDEF, Inc.
4 */
5
6 #include <zebra.h>
7
8 #include <float.h>
9 #include <math.h>
10 #include <zebra.h>
11
12 #include "memory.h"
13 #include "log.h"
14 #include "command.h"
15 #include "mpls.h"
16 #include "northbound_cli.h"
17 #include "termtable.h"
18
19 #include "pathd/pathd.h"
20 #include "pathd/path_nb.h"
21 #include "pathd/path_cli_clippy.c"
22 #include "pathd/path_ted.h"
23
24 #define XPATH_MAXATTRSIZE 64
25 #define XPATH_MAXKEYSIZE 42
26 #define XPATH_POLICY_BASELEN 100
27 #define XPATH_POLICY_MAXLEN (XPATH_POLICY_BASELEN + XPATH_MAXATTRSIZE)
28 #define XPATH_CANDIDATE_BASELEN (XPATH_POLICY_BASELEN + XPATH_MAXKEYSIZE)
29 #define XPATH_CANDIDATE_MAXLEN (XPATH_CANDIDATE_BASELEN + XPATH_MAXATTRSIZE)
30
31
32 static int config_write_segment_routing(struct vty *vty);
33 static int segment_list_has_src_dst(
34 struct vty *vty, char *xpath, long index, const char *index_str,
35 struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
36 struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6,
37 const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str,
38 const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str);
39 static int segment_list_has_prefix(
40 struct vty *vty, char *xpath, long index, const char *index_str,
41 const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str,
42 const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str,
43 const char *has_algo, long algo, const char *algo_str,
44 const char *has_iface_id, long iface_id, const char *iface_id_str);
45
46 DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client");
47
48 DEFINE_HOOK(pathd_srte_config_write, (struct vty *vty), (vty));
49
50 /* Vty node structures. */
51 static struct cmd_node segment_routing_node = {
52 .name = "segment-routing",
53 .node = SEGMENT_ROUTING_NODE,
54 .parent_node = CONFIG_NODE,
55 .prompt = "%s(config-sr)# ",
56 .config_write = config_write_segment_routing,
57 };
58
59 static struct cmd_node sr_traffic_eng_node = {
60 .name = "sr traffic-eng",
61 .node = SR_TRAFFIC_ENG_NODE,
62 .parent_node = SEGMENT_ROUTING_NODE,
63 .prompt = "%s(config-sr-te)# ",
64 };
65
66 static struct cmd_node srte_segment_list_node = {
67 .name = "srte segment-list",
68 .node = SR_SEGMENT_LIST_NODE,
69 .parent_node = SR_TRAFFIC_ENG_NODE,
70 .prompt = "%s(config-sr-te-segment-list)# ",
71 };
72
73 static struct cmd_node srte_policy_node = {
74 .name = "srte policy",
75 .node = SR_POLICY_NODE,
76 .parent_node = SR_TRAFFIC_ENG_NODE,
77 .prompt = "%s(config-sr-te-policy)# ",
78 };
79
80 static struct cmd_node srte_candidate_dyn_node = {
81 .name = "srte candidate-dyn",
82 .node = SR_CANDIDATE_DYN_NODE,
83 .parent_node = SR_POLICY_NODE,
84 .prompt = "%s(config-sr-te-candidate)# ",
85 };
86
87
88 /*
89 * Show SR-TE info
90 */
91 DEFPY(show_srte_policy,
92 show_srte_policy_cmd,
93 "show sr-te policy",
94 SHOW_STR
95 "SR-TE info\n"
96 "SR-TE Policy\n")
97 {
98 struct ttable *tt;
99 struct srte_policy *policy;
100 char *table;
101
102 if (RB_EMPTY(srte_policy_head, &srte_policies)) {
103 vty_out(vty, "No SR Policies to display.\n\n");
104 return CMD_SUCCESS;
105 }
106
107 /* Prepare table. */
108 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
109 ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status");
110 tt->style.cell.rpad = 2;
111 tt->style.corner = '+';
112 ttable_restyle(tt);
113 ttable_rowseps(tt, 0, BOTTOM, true, '-');
114
115 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
116 char endpoint[ENDPOINT_STR_LENGTH];
117 char binding_sid[16] = "-";
118
119 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
120 if (policy->binding_sid != MPLS_LABEL_NONE)
121 snprintf(binding_sid, sizeof(binding_sid), "%u",
122 policy->binding_sid);
123
124 ttable_add_row(tt, "%s|%u|%s|%s|%s", endpoint, policy->color,
125 policy->name, binding_sid,
126 policy->status == SRTE_POLICY_STATUS_UP
127 ? "Active"
128 : "Inactive");
129 }
130
131 /* Dump the generated table. */
132 table = ttable_dump(tt, "\n");
133 vty_out(vty, "%s\n", table);
134 XFREE(MTYPE_TMP, table);
135
136 ttable_del(tt);
137
138 return CMD_SUCCESS;
139 }
140
141
142 /*
143 * Show detailed SR-TE info
144 */
145 DEFPY(show_srte_policy_detail,
146 show_srte_policy_detail_cmd,
147 "show sr-te policy detail",
148 SHOW_STR
149 "SR-TE info\n"
150 "SR-TE Policy\n"
151 "Show a detailed summary\n")
152 {
153 struct srte_policy *policy;
154
155 if (RB_EMPTY(srte_policy_head, &srte_policies)) {
156 vty_out(vty, "No SR Policies to display.\n\n");
157 return CMD_SUCCESS;
158 }
159
160 vty_out(vty, "\n");
161 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
162 struct srte_candidate *candidate;
163 char endpoint[ENDPOINT_STR_LENGTH];
164 char binding_sid[16] = "-";
165 char *segment_list_info;
166 static char undefined_info[] = "(undefined)";
167 static char created_by_pce_info[] = "(created by PCE)";
168
169
170 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
171 if (policy->binding_sid != MPLS_LABEL_NONE)
172 snprintf(binding_sid, sizeof(binding_sid), "%u",
173 policy->binding_sid);
174 vty_out(vty,
175 "Endpoint: %s Color: %u Name: %s BSID: %s Status: %s\n",
176 endpoint, policy->color, policy->name, binding_sid,
177 policy->status == SRTE_POLICY_STATUS_UP ? "Active"
178 : "Inactive");
179
180 RB_FOREACH (candidate, srte_candidate_head,
181 &policy->candidate_paths) {
182 struct srte_segment_list *segment_list;
183
184 segment_list = candidate->lsp->segment_list;
185 if (segment_list == NULL)
186 segment_list_info = undefined_info;
187 else if (segment_list->protocol_origin
188 == SRTE_ORIGIN_PCEP)
189 segment_list_info = created_by_pce_info;
190 else
191 segment_list_info =
192 candidate->lsp->segment_list->name;
193
194 vty_out(vty,
195 " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n",
196 CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)
197 ? "*"
198 : " ",
199 candidate->preference, candidate->name,
200 candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT
201 ? "explicit"
202 : "dynamic",
203 segment_list_info,
204 srte_origin2str(
205 candidate->lsp->protocol_origin));
206 }
207
208 vty_out(vty, "\n");
209 }
210
211 return CMD_SUCCESS;
212 }
213
214 DEFPY_NOSH(
215 segment_routing_list,
216 segment_routing_cmd,
217 "segment-routing",
218 "Configure segment routing\n")
219 {
220 VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE);
221 return CMD_SUCCESS;
222 }
223
224 DEFPY_NOSH(
225 sr_traffic_eng_list,
226 sr_traffic_eng_cmd,
227 "traffic-eng",
228 "Configure SR traffic engineering\n")
229 {
230 VTY_PUSH_CONTEXT_NULL(SR_TRAFFIC_ENG_NODE);
231 return CMD_SUCCESS;
232 }
233
234 /*
235 * XPath: /frr-pathd:pathd/srte/segment-list
236 */
237 DEFPY_NOSH(
238 srte_segment_list,
239 srte_segment_list_cmd,
240 "segment-list WORD$name",
241 "Segment List\n"
242 "Segment List Name\n")
243 {
244 char xpath[XPATH_MAXLEN];
245 int ret;
246
247 snprintf(xpath, sizeof(xpath),
248 "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
249 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
250
251 snprintf(xpath, sizeof(xpath),
252 "/frr-pathd:pathd/srte/segment-list[name='%s']/protocol-origin",
253 name);
254 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "local");
255
256 snprintf(xpath, sizeof(xpath),
257 "/frr-pathd:pathd/srte/segment-list[name='%s']/originator", name);
258 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "config");
259
260 ret = nb_cli_apply_changes(vty, NULL);
261 if (ret == CMD_SUCCESS) {
262 snprintf(xpath, sizeof(xpath),
263 "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
264 VTY_PUSH_XPATH(SR_SEGMENT_LIST_NODE, xpath);
265 }
266
267 return ret;
268 }
269
270 DEFPY(srte_no_segment_list,
271 srte_no_segment_list_cmd,
272 "no segment-list WORD$name",
273 NO_STR
274 "Segment List\n"
275 "Segment List Name\n")
276 {
277 char xpath[XPATH_MAXLEN];
278
279 snprintf(xpath, sizeof(xpath),
280 "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
281 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
282
283 return nb_cli_apply_changes(vty, NULL);
284 }
285
286 void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode,
287 bool show_defaults)
288 {
289 vty_out(vty, " segment-list %s\n",
290 yang_dnode_get_string(dnode, "./name"));
291 }
292
293 void cli_show_srte_segment_list_end(struct vty *vty,
294 const struct lyd_node *dnode)
295 {
296 vty_out(vty, " exit\n");
297 }
298
299 static int segment_list_has_src_dst(
300 struct vty *vty, char *xpath, long index, const char *index_str,
301 struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
302 struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6,
303 const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str,
304 const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str)
305 {
306 const char *node_src_id;
307 uint32_t ted_sid = MPLS_LABEL_NONE;
308
309 struct ipaddr ip_src = {};
310 struct ipaddr ip_dst = {};
311 if (adj_src_ipv4_str != NULL) {
312 ip_src.ipa_type = IPADDR_V4;
313 ip_src.ip._v4_addr = adj_src_ipv4;
314 ip_dst.ipa_type = IPADDR_V4;
315 ip_dst.ip._v4_addr = adj_dst_ipv4;
316 } else if (adj_src_ipv6_str != NULL) {
317 ip_src.ipa_type = IPADDR_V6;
318 ip_src.ip._v6_addr = adj_src_ipv6;
319 ip_dst.ipa_type = IPADDR_V6;
320 ip_dst.ip._v6_addr = adj_dst_ipv6;
321 } else {
322 return CMD_ERR_NO_MATCH;
323 }
324 ted_sid = path_ted_query_type_f(&ip_src, &ip_dst);
325 if (ted_sid == MPLS_LABEL_NONE) {
326 zlog_warn(
327 "%s: [rcv ted] CLI NOT FOUND Continue query_type_f SRC (%pIA) DST (%pIA)!",
328 __func__, &ip_src, &ip_dst);
329 }
330 /* type */
331 snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type",
332 index_str);
333 if (adj_src_ipv4_str != NULL) {
334 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
335 "ipv4_adjacency");
336 node_src_id = adj_src_ipv4_str;
337 } else if (adj_src_ipv6_str != NULL) {
338 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
339 "ipv6_adjacency");
340 node_src_id = adj_src_ipv6_str;
341 } else {
342 /*
343 * This is just to make the compiler happy about
344 * node_src_id not being initialized. This
345 * should never happen unless we change the cli
346 * function.
347 */
348 assert(!"We must have a adj_src_ipv4_str or a adj_src_ipv6_str");
349 }
350
351 /* addresses */
352 snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
353 index_str);
354 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_src_id);
355 snprintf(xpath, XPATH_MAXLEN,
356 "./segment[index='%s']/nai/remote-address", index_str);
357 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
358 adj_dst_ipv4_str ? adj_dst_ipv4_str
359 : adj_dst_ipv6_str);
360 return CMD_SUCCESS;
361 }
362 int segment_list_has_prefix(
363 struct vty *vty, char *xpath, long index, const char *index_str,
364 const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str,
365 const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str,
366 const char *has_algo, long algo, const char *algo_str,
367 const char *has_iface_id, long iface_id, const char *iface_id_str)
368 {
369 char buf_prefix[INET6_ADDRSTRLEN];
370
371 uint32_t ted_sid = MPLS_LABEL_NONE;
372 struct prefix prefix_cli = {};
373 struct ipaddr pre_ipaddr = {};
374 /* prefix with algorithm or local interface id */
375 /* Type */
376 snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type",
377 index_str);
378 if (has_iface_id != NULL) {
379 if (prefix_ipv4_str != NULL) {
380 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
381 "ipv4_local_iface");
382 } else if (prefix_ipv6_str != NULL) {
383 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
384 "ipv6_local_iface");
385 } else {
386 return CMD_ERR_NO_MATCH;
387 }
388 } else {
389 if (prefix_ipv4_str != NULL) {
390 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
391 "ipv4_algo");
392 } else if (prefix_ipv6_str != NULL) {
393 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
394 "ipv6_algo");
395 } else {
396 return CMD_ERR_NO_MATCH;
397 }
398 }
399 /* Prefix */
400 if (prefix_ipv4_str != NULL) {
401 if (!str2prefix(prefix_ipv4_str, &prefix_cli)) {
402 vty_out(vty, "%% Malformed prefix\n");
403 return CMD_WARNING_CONFIG_FAILED;
404 }
405 inet_ntop(AF_INET, &prefix_cli.u.prefix4, buf_prefix,
406 sizeof(buf_prefix));
407 pre_ipaddr.ipa_type = IPADDR_V4;
408 pre_ipaddr.ip._v4_addr = prefix_cli.u.prefix4;
409 } else if (prefix_ipv6_str != NULL) {
410 if (!str2prefix(prefix_ipv6_str, &prefix_cli)) {
411 vty_out(vty, "%% Malformed prefix\n");
412 return CMD_WARNING_CONFIG_FAILED;
413 }
414 inet_ntop(AF_INET6, &prefix_cli.u.prefix6, buf_prefix,
415 sizeof(buf_prefix));
416 pre_ipaddr.ipa_type = IPADDR_V6;
417 pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6;
418 }
419 snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
420 index_str);
421 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, buf_prefix);
422 snprintf(xpath, XPATH_MAXLEN,
423 "./segment[index='%s']/nai/local-prefix-len", index_str);
424 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
425 prefix_ipv4_str
426 ? strchr(prefix_ipv4_str, '/') + 1
427 : strchr(prefix_ipv6_str, '/') + 1);
428 /* Alg / Iface */
429 if (has_algo != NULL) {
430 snprintf(xpath, XPATH_MAXLEN,
431 "./segment[index='%s']/nai/algorithm", index_str);
432 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, algo_str);
433 } else {
434 if (has_iface_id != NULL) {
435 snprintf(xpath, XPATH_MAXLEN,
436 "./segment[index='%s']/nai/local-interface",
437 index_str);
438 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
439 iface_id_str);
440 }
441 }
442 if (has_algo != NULL) {
443 ted_sid = path_ted_query_type_c(&prefix_cli, algo);
444 if (ted_sid == MPLS_LABEL_NONE) {
445 zlog_err(
446 "%s: [rcv ted] CLI NOT FOUND Continue query_type_c PREFIX (%pIA/%d) ALGO (%ld) sid:(%d)!",
447 __func__, &pre_ipaddr, prefix_cli.prefixlen,
448 algo, ted_sid);
449 }
450 }
451 if (has_iface_id != NULL) {
452 ted_sid = path_ted_query_type_e(&prefix_cli, iface_id);
453 if (ted_sid == MPLS_LABEL_NONE) {
454 zlog_err(
455 "%s: [rcv ted] CLI NOT FOUND Continue query_type_e PREFIX (%pIA/%d) IFACE (%ld) sid:(%d)!",
456 __func__, &pre_ipaddr, prefix_cli.prefixlen,
457 iface_id, ted_sid);
458 }
459 }
460 return CMD_SUCCESS;
461 }
462 /*
463 * XPath: /frr-pathd:pathd/srte/segment-list/segment
464 */
465 /* clang-format off */
466 DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd,
467 "index (0-4294967295)$index <[mpls$has_mpls_label label (16-1048575)$label] "
468 "|"
469 "[nai$has_nai <"
470 "prefix <A.B.C.D/M$prefix_ipv4|X:X::X:X/M$prefix_ipv6>"
471 "<algorithm$has_algo (0-1)$algo| iface$has_iface_id (0-4294967295)$iface_id>"
472 "| adjacency$has_adj "
473 "<A.B.C.D$adj_src_ipv4 A.B.C.D$adj_dst_ipv4|X:X::X:X$adj_src_ipv6 X:X::X:X$adj_dst_ipv6>"
474 ">]"
475 ">",
476 "Index\n"
477 "Index Value\n"
478 "MPLS or IP Label\n"
479 "Label\n"
480 "Label Value\n"
481 "Segment NAI\n"
482 "NAI prefix identifier\n"
483 "NAI IPv4 prefix identifier\n"
484 "NAI IPv6 prefix identifier\n"
485 "IGP Algorithm\n"
486 "Algorithm Value SPF or Strict-SPF\n"
487 "Interface Id\n"
488 "Interface Value\n"
489 "ADJ identifier\n"
490 "ADJ IPv4 src identifier\n"
491 "ADJ IPv4 dst identifier\n"
492 "ADJ IPv6 src identifier\n"
493 "ADJ IPv6 dst identifier\n")
494 /* clang-format on */
495 {
496 char xpath[XPATH_MAXLEN];
497 int status = CMD_SUCCESS;
498
499
500 snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str);
501 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
502
503 if (has_mpls_label != NULL) {
504 snprintf(xpath, sizeof(xpath),
505 "./segment[index='%s']/sid-value", index_str);
506 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str);
507 return nb_cli_apply_changes(vty, NULL);
508 }
509
510 if (has_adj != NULL) {
511 status = segment_list_has_src_dst(vty, xpath, index, index_str,
512 adj_src_ipv4, adj_dst_ipv4,
513 adj_src_ipv6, adj_dst_ipv6,
514 adj_src_ipv4_str, adj_dst_ipv4_str,
515 adj_src_ipv6_str, adj_dst_ipv6_str);
516 if (status != CMD_SUCCESS)
517 return status;
518 } else {
519 status = segment_list_has_prefix(
520 vty, xpath, index, index_str, prefix_ipv4,
521 prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo,
522 algo, algo_str, has_iface_id, iface_id, iface_id_str);
523 if (status != CMD_SUCCESS)
524 return status;
525 }
526
527 return nb_cli_apply_changes(vty, NULL);
528 }
529
530 DEFPY(srte_segment_list_no_segment,
531 srte_segment_list_no_segment_cmd,
532 "no index (0-4294967295)$index",
533 NO_STR
534 "Index\n"
535 "Index Value\n")
536 {
537 char xpath[XPATH_MAXLEN];
538
539 snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str);
540 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
541
542 return nb_cli_apply_changes(vty, NULL);
543 }
544
545 void cli_show_srte_segment_list_segment(struct vty *vty,
546 const struct lyd_node *dnode,
547 bool show_defaults)
548 {
549 vty_out(vty, " index %s", yang_dnode_get_string(dnode, "./index"));
550 if (yang_dnode_exists(dnode, "./sid-value")) {
551 vty_out(vty, " mpls label %s",
552 yang_dnode_get_string(dnode, "./sid-value"));
553 }
554 if (yang_dnode_exists(dnode, "./nai")) {
555 struct ipaddr addr;
556 struct ipaddr addr_rmt;
557
558 switch (yang_dnode_get_enum(dnode, "./nai/type")) {
559 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
560 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
561 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
562 yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
563 vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4);
564 break;
565 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
566 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
567 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
568 yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
569 vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6);
570 break;
571 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
572 yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
573 yang_dnode_get_ip(&addr_rmt, dnode,
574 "./nai/remote-address");
575 vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4);
576 vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4);
577 break;
578 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
579 yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
580 yang_dnode_get_ip(&addr_rmt, dnode,
581 "./nai/remote-address");
582 vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6);
583 vty_out(vty, " %pI6", &addr_rmt.ipaddr_v6);
584 break;
585 default:
586 break;
587 }
588 if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) {
589 vty_out(vty, "/%s",
590 yang_dnode_get_string(
591 dnode, "./nai/local-prefix-len"));
592 }
593 if (yang_dnode_exists(dnode, "./nai/local-interface")) {
594 vty_out(vty, " iface %s",
595 yang_dnode_get_string(dnode,
596 "./nai/local-interface"));
597 }
598 if (yang_dnode_exists(dnode, "./nai/algorithm")) {
599 vty_out(vty, " algorithm %s",
600 yang_dnode_get_string(dnode,
601 "./nai/algorithm"));
602 }
603 }
604 vty_out(vty, "\n");
605 }
606
607 /*
608 * XPath: /frr-pathd:pathd/policy
609 */
610 DEFPY_NOSH(
611 srte_policy,
612 srte_policy_cmd,
613 "policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint",
614 "Segment Routing Policy\n"
615 "SR Policy color\n"
616 "SR Policy color value\n"
617 "SR Policy endpoint\n"
618 "SR Policy endpoint IPv4 address\n"
619 "SR Policy endpoint IPv6 address\n")
620 {
621 char xpath[XPATH_POLICY_BASELEN];
622 int ret;
623
624 snprintf(xpath, sizeof(xpath),
625 "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']",
626 num_str, endpoint_str);
627 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
628
629 ret = nb_cli_apply_changes(vty, NULL);
630 if (ret == CMD_SUCCESS)
631 VTY_PUSH_XPATH(SR_POLICY_NODE, xpath);
632
633 return ret;
634 }
635
636 DEFPY(srte_no_policy,
637 srte_no_policy_cmd,
638 "no policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint",
639 NO_STR
640 "Segment Routing Policy\n"
641 "SR Policy color\n"
642 "SR Policy color value\n"
643 "SR Policy endpoint\n"
644 "SR Policy endpoint IPv4 address\n"
645 "SR Policy endpoint IPv6 address\n")
646 {
647 char xpath[XPATH_POLICY_BASELEN];
648
649 snprintf(xpath, sizeof(xpath),
650 "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']",
651 num_str, endpoint_str);
652 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
653
654 return nb_cli_apply_changes(vty, NULL);
655 }
656
657 void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode,
658 bool show_defaults)
659 {
660 vty_out(vty, " policy color %s endpoint %s\n",
661 yang_dnode_get_string(dnode, "./color"),
662 yang_dnode_get_string(dnode, "./endpoint"));
663 }
664
665 void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode)
666 {
667 vty_out(vty, " exit\n");
668 }
669
670 /*
671 * XPath: /frr-pathd:pathd/srte/policy/name
672 */
673 DEFPY(srte_policy_name,
674 srte_policy_name_cmd,
675 "name WORD$name",
676 "Segment Routing Policy name\n"
677 "SR Policy name value\n")
678 {
679 nb_cli_enqueue_change(vty, "./name", NB_OP_CREATE, name);
680
681 return nb_cli_apply_changes(vty, NULL);
682 }
683
684 DEFPY(srte_policy_no_name,
685 srte_policy_no_name_cmd,
686 "no name [WORD]",
687 NO_STR
688 "Segment Routing Policy name\n"
689 "SR Policy name value\n")
690 {
691 nb_cli_enqueue_change(vty, "./name", NB_OP_DESTROY, NULL);
692
693 return nb_cli_apply_changes(vty, NULL);
694 }
695
696
697 void cli_show_srte_policy_name(struct vty *vty, const struct lyd_node *dnode,
698 bool show_defaults)
699 {
700 vty_out(vty, " name %s\n", yang_dnode_get_string(dnode, NULL));
701 }
702
703 /*
704 * XPath: /frr-pathd:pathd/srte/policy/binding-sid
705 */
706 DEFPY(srte_policy_binding_sid,
707 srte_policy_binding_sid_cmd,
708 "binding-sid (16-1048575)$label",
709 "Segment Routing Policy Binding-SID\n"
710 "SR Policy Binding-SID label\n")
711 {
712 nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_CREATE, label_str);
713
714 return nb_cli_apply_changes(vty, NULL);
715 }
716
717 DEFPY(srte_policy_no_binding_sid,
718 srte_policy_no_binding_sid_cmd,
719 "no binding-sid [(16-1048575)]",
720 NO_STR
721 "Segment Routing Policy Binding-SID\n"
722 "SR Policy Binding-SID label\n")
723 {
724 nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_DESTROY, NULL);
725
726 return nb_cli_apply_changes(vty, NULL);
727 }
728
729 void cli_show_srte_policy_binding_sid(struct vty *vty,
730 const struct lyd_node *dnode,
731 bool show_defaults)
732 {
733 vty_out(vty, " binding-sid %s\n", yang_dnode_get_string(dnode, NULL));
734 }
735
736 /*
737 * XPath: /frr-pathd:pathd/srte/policy/candidate-path
738 */
739 DEFPY(srte_policy_candidate_exp,
740 srte_policy_candidate_exp_cmd,
741 "candidate-path preference (0-4294967295)$preference name WORD$name \
742 explicit segment-list WORD$list_name",
743 "Segment Routing Policy Candidate Path\n"
744 "Segment Routing Policy Candidate Path Preference\n"
745 "Administrative Preference\n"
746 "Segment Routing Policy Candidate Path Name\n"
747 "Symbolic Name\n"
748 "Explicit Path\n"
749 "List of SIDs\n"
750 "Name of the Segment List\n")
751 {
752 nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str);
753 nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name);
754 nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local");
755 nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config");
756 nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "explicit");
757 nb_cli_enqueue_change(vty, "./segment-list-name", NB_OP_MODIFY,
758 list_name);
759 return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
760 preference_str);
761 }
762
763 DEFPY_NOSH(
764 srte_policy_candidate_dyn,
765 srte_policy_candidate_dyn_cmd,
766 "candidate-path preference (0-4294967295)$preference name WORD$name dynamic",
767 "Segment Routing Policy Candidate Path\n"
768 "Segment Routing Policy Candidate Path Preference\n"
769 "Administrative Preference\n"
770 "Segment Routing Policy Candidate Path Name\n"
771 "Symbolic Name\n"
772 "Dynamic Path\n")
773 {
774 char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN];
775 int ret;
776
777 snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']",
778 VTY_CURR_XPATH, preference_str);
779
780 nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str);
781 nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name);
782 nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local");
783 nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config");
784 nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "dynamic");
785 ret = nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
786 preference_str);
787
788 if (ret == CMD_SUCCESS)
789 VTY_PUSH_XPATH(SR_CANDIDATE_DYN_NODE, xpath);
790
791 return ret;
792 }
793
794 DEFPY(srte_candidate_bandwidth,
795 srte_candidate_bandwidth_cmd,
796 "bandwidth BANDWIDTH$value [required$required]",
797 "Define a bandwidth constraint\n"
798 "Bandwidth value\n"
799 "Required constraint\n")
800 {
801 nb_cli_enqueue_change(vty, "./constraints/bandwidth/required",
802 NB_OP_MODIFY, required ? "true" : "false");
803 nb_cli_enqueue_change(vty, "./constraints/bandwidth/value",
804 NB_OP_MODIFY, value);
805 return nb_cli_apply_changes(vty, NULL);
806 }
807
808 DEFPY(srte_candidate_no_bandwidth,
809 srte_candidate_no_bandwidth_cmd,
810 "no bandwidth [BANDWIDTH$value] [required$required]",
811 NO_STR
812 "Remove a bandwidth constraint\n"
813 "Bandwidth value\n"
814 "Required constraint\n")
815 {
816 nb_cli_enqueue_change(vty, "./constraints/bandwidth", NB_OP_DESTROY,
817 NULL);
818 return nb_cli_apply_changes(vty, NULL);
819 }
820
821 DEFPY(srte_candidate_affinity_filter, srte_candidate_affinity_filter_cmd,
822 "affinity <exclude-any|include-any|include-all>$type BITPATTERN$value",
823 "Affinity constraint\n"
824 "Exclude any matching link\n"
825 "Include any matching link\n"
826 "Include all matching links\n"
827 "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n")
828 {
829 uint32_t filter;
830 char xpath[XPATH_CANDIDATE_MAXLEN];
831 char decimal_value[11];
832
833 if (sscanf(value, "0x%x", &filter) != 1) {
834 vty_out(vty, "affinity type: fscanf: %s\n",
835 safe_strerror(errno));
836 return CMD_WARNING_CONFIG_FAILED;
837 }
838 snprintf(decimal_value, sizeof(decimal_value), "%u", filter);
839 snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type);
840 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, decimal_value);
841
842 return nb_cli_apply_changes(vty, NULL);
843 }
844
845 DEFPY(srte_candidate_no_affinity_filter, srte_candidate_no_affinity_filter_cmd,
846 "no affinity <exclude-any|include-any|include-all>$type [BITPATTERN$value]",
847 NO_STR
848 "Affinity constraint\n"
849 "Exclude any matching link\n"
850 "Include any matching link\n"
851 "Include all matching links\n"
852 "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n")
853 {
854 char xpath[XPATH_CANDIDATE_MAXLEN];
855
856 snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type);
857 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
858 return nb_cli_apply_changes(vty, NULL);
859 }
860
861 DEFPY(srte_candidate_metric,
862 srte_candidate_metric_cmd,
863 "metric [bound$bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type METRIC$value [required$required]",
864 "Define a metric constraint\n"
865 "If the metric is bounded\n"
866 "IGP metric\n"
867 "TE metric\n"
868 "Hop Counts\n"
869 "Aggregate bandwidth consumption\n"
870 "Load of the most loaded link\n"
871 "Cumulative IGP cost\n"
872 "Cumulative TE cost\n"
873 "P2MP IGP metric\n"
874 "P2MP TE metric\n"
875 "P2MP hop count metric\n"
876 "Segment-ID (SID) Depth.\n"
877 "Path Delay metric\n"
878 "Path Delay Variation metric\n"
879 "Path Loss metric\n"
880 "P2MP Path Delay metric\n"
881 "P2MP Path Delay variation metric\n"
882 "P2MP Path Loss metric\n"
883 "Number of adaptations on a path\n"
884 "Number of layers on a path\n"
885 "Domain Count metric\n"
886 "Border Node Count metric\n"
887 "Metric value\n"
888 "Required constraint\n")
889 {
890 char xpath[XPATH_CANDIDATE_MAXLEN];
891 snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']/value",
892 type);
893 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value);
894 snprintf(xpath, sizeof(xpath),
895 "./constraints/metrics[type='%s']/is-bound", type);
896 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
897 (bound != NULL) ? "true" : "false");
898 snprintf(xpath, sizeof(xpath),
899 "./constraints/metrics[type='%s']/required", type);
900 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
901 required ? "true" : "false");
902 return nb_cli_apply_changes(vty, NULL);
903 }
904
905 DEFPY(srte_candidate_no_metric,
906 srte_candidate_no_metric_cmd,
907 "no metric [bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type [METRIC$value] [required$required]",
908 NO_STR
909 "Remove a metric constraint\n"
910 "If the metric is bounded\n"
911 "IGP metric\n"
912 "TE metric\n"
913 "Hop Counts\n"
914 "Aggregate bandwidth consumption\n"
915 "Load of the most loaded link\n"
916 "Cumulative IGP cost\n"
917 "Cumulative TE cost\n"
918 "P2MP IGP metric\n"
919 "P2MP TE metric\n"
920 "P2MP hop count metric\n"
921 "Segment-ID (SID) Depth.\n"
922 "Path Delay metric\n"
923 "Path Delay Variation metric\n"
924 "Path Loss metric\n"
925 "P2MP Path Delay metric\n"
926 "P2MP Path Delay variation metric\n"
927 "P2MP Path Loss metric\n"
928 "Number of adaptations on a path\n"
929 "Number of layers on a path\n"
930 "Domain Count metric\n"
931 "Border Node Count metric\n"
932 "Metric value\n"
933 "Required constraint\n")
934 {
935 char xpath[XPATH_CANDIDATE_MAXLEN];
936 snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']",
937 type);
938 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
939 return nb_cli_apply_changes(vty, NULL);
940 }
941
942 DEFPY(srte_policy_no_candidate,
943 srte_policy_no_candidate_cmd,
944 "no candidate-path\
945 preference (0-4294967295)$preference\
946 [name WORD\
947 <\
948 explicit segment-list WORD\
949 |dynamic\
950 >]",
951 NO_STR
952 "Segment Routing Policy Candidate Path\n"
953 "Segment Routing Policy Candidate Path Preference\n"
954 "Administrative Preference\n"
955 "Segment Routing Policy Candidate Path Name\n"
956 "Symbolic Name\n"
957 "Explicit Path\n"
958 "List of SIDs\n"
959 "Name of the Segment List\n"
960 "Dynamic Path\n")
961 {
962 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
963
964 return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
965 preference_str);
966 }
967
968 DEFPY(srte_candidate_objfun,
969 srte_candidate_objfun_cmd,
970 "objective-function <mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>$type [required$required]",
971 "Define an objective function constraint\n"
972 "Minimum Cost Path\n"
973 "Minimum Load Path\n"
974 "Maximum residual Bandwidth Path\n"
975 "Minimize aggregate Bandwidth Consumption\n"
976 "Minimize the Load of the most loaded Link\n"
977 "Minimize the Cumulative Cost of a set of paths\n"
978 "Shortest Path Tree\n"
979 "Minimum Cost Tree\n"
980 "Minimum Packet Loss Path\n"
981 "Maximum Under-Utilized Path\n"
982 "Maximum Reserved Under-Utilized Path\n"
983 "Minimize the number of Transit Domains\n"
984 "Minimize the number of Border Nodes\n"
985 "Minimize the number of Common Transit Domains\n"
986 "Minimize the number of Shared Links\n"
987 "Minimize the number of Shared SRLGs\n"
988 "Minimize the number of Shared Nodes\n"
989 "Required constraint\n")
990 {
991 char xpath[XPATH_CANDIDATE_MAXLEN];
992 nb_cli_enqueue_change(vty, "./constraints/objective-function",
993 NB_OP_DESTROY, NULL);
994 snprintf(xpath, sizeof(xpath),
995 "./constraints/objective-function/required");
996 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
997 required ? "true" : "false");
998 nb_cli_enqueue_change(vty, "./constraints/objective-function/type",
999 NB_OP_MODIFY, type);
1000 return nb_cli_apply_changes(vty, NULL);
1001 }
1002
1003 DEFPY(srte_candidate_no_objfun,
1004 srte_candidate_no_objfun_cmd,
1005 "no objective-function [<mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>] [required$required]",
1006 NO_STR
1007 "Remove an objective function constraint\n"
1008 "Minimum Cost Path\n"
1009 "Minimum Load Path\n"
1010 "Maximum residual Bandwidth Path\n"
1011 "Minimize aggregate Bandwidth Consumption\n"
1012 "Minimize the Load of the most loaded Link\n"
1013 "Minimize the Cumulative Cost of a set of paths\n"
1014 "Shortest Path Tree\n"
1015 "Minimum Cost Tree\n"
1016 "Minimum Packet Loss Path\n"
1017 "Maximum Under-Utilized Path\n"
1018 "Maximum Reserved Under-Utilized Path\n"
1019 "Minimize the number of Transit Domains\n"
1020 "Minimize the number of Border Nodes\n"
1021 "Minimize the number of Common Transit Domains\n"
1022 "Minimize the number of Shared Links\n"
1023 "Minimize the number of Shared SRLGs\n"
1024 "Minimize the number of Shared Nodes\n"
1025 "Required constraint\n")
1026 {
1027 nb_cli_enqueue_change(vty, "./constraints/objective-function",
1028 NB_OP_DESTROY, NULL);
1029 return nb_cli_apply_changes(vty, NULL);
1030 }
1031
1032 static const char *objfun_type_name(enum objfun_type type)
1033 {
1034 switch (type) {
1035 case OBJFUN_MCP:
1036 return "mcp";
1037 case OBJFUN_MLP:
1038 return "mlp";
1039 case OBJFUN_MBP:
1040 return "mbp";
1041 case OBJFUN_MBC:
1042 return "mbc";
1043 case OBJFUN_MLL:
1044 return "mll";
1045 case OBJFUN_MCC:
1046 return "mcc";
1047 case OBJFUN_SPT:
1048 return "spt";
1049 case OBJFUN_MCT:
1050 return "mct";
1051 case OBJFUN_MPLP:
1052 return "mplp";
1053 case OBJFUN_MUP:
1054 return "mup";
1055 case OBJFUN_MRUP:
1056 return "mrup";
1057 case OBJFUN_MTD:
1058 return "mtd";
1059 case OBJFUN_MBN:
1060 return "mbn";
1061 case OBJFUN_MCTD:
1062 return "mctd";
1063 case OBJFUN_MSL:
1064 return "msl";
1065 case OBJFUN_MSS:
1066 return "mss";
1067 case OBJFUN_MSN:
1068 return "msn";
1069 case OBJFUN_UNDEFINED:
1070 return NULL;
1071 }
1072
1073 assert(!"Reached end of function we should never hit");
1074 }
1075
1076 DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
1077 "show debugging [pathd]",
1078 SHOW_STR
1079 "State of each debugging option\n"
1080 "pathd module debugging\n")
1081 {
1082
1083 vty_out(vty, "Path debugging status:\n");
1084
1085 cmd_show_lib_debugs(vty);
1086 /* nothing to do here */
1087 path_ted_show_debugging(vty);
1088 path_policy_show_debugging(vty);
1089 return CMD_SUCCESS;
1090 }
1091
1092 DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
1093 NO_STR DEBUG_STR
1094 "path debugging\n"
1095 "policy debugging\n")
1096 {
1097 uint32_t mode = DEBUG_NODE2MODE(vty->node);
1098 bool no_debug = no;
1099
1100 DEBUG_MODE_SET(&path_policy_debug, mode, !no);
1101 DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug);
1102 return CMD_SUCCESS;
1103 }
1104
1105 static const char *metric_type_name(enum srte_candidate_metric_type type)
1106 {
1107 switch (type) {
1108 case SRTE_CANDIDATE_METRIC_TYPE_IGP:
1109 return "igp";
1110 case SRTE_CANDIDATE_METRIC_TYPE_TE:
1111 return "te";
1112 case SRTE_CANDIDATE_METRIC_TYPE_HC:
1113 return "hc";
1114 case SRTE_CANDIDATE_METRIC_TYPE_ABC:
1115 return "abc";
1116 case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
1117 return "lmll";
1118 case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
1119 return "cigp";
1120 case SRTE_CANDIDATE_METRIC_TYPE_CTE:
1121 return "cte";
1122 case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
1123 return "pigp";
1124 case SRTE_CANDIDATE_METRIC_TYPE_PTE:
1125 return "pte";
1126 case SRTE_CANDIDATE_METRIC_TYPE_PHC:
1127 return "phc";
1128 case SRTE_CANDIDATE_METRIC_TYPE_MSD:
1129 return "msd";
1130 case SRTE_CANDIDATE_METRIC_TYPE_PD:
1131 return "pd";
1132 case SRTE_CANDIDATE_METRIC_TYPE_PDV:
1133 return "pdv";
1134 case SRTE_CANDIDATE_METRIC_TYPE_PL:
1135 return "pl";
1136 case SRTE_CANDIDATE_METRIC_TYPE_PPD:
1137 return "ppd";
1138 case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
1139 return "ppdv";
1140 case SRTE_CANDIDATE_METRIC_TYPE_PPL:
1141 return "ppl";
1142 case SRTE_CANDIDATE_METRIC_TYPE_NAP:
1143 return "nap";
1144 case SRTE_CANDIDATE_METRIC_TYPE_NLP:
1145 return "nlp";
1146 case SRTE_CANDIDATE_METRIC_TYPE_DC:
1147 return "dc";
1148 case SRTE_CANDIDATE_METRIC_TYPE_BNC:
1149 return "bnc";
1150 default:
1151 return NULL;
1152 }
1153 }
1154
1155 static void config_write_float(struct vty *vty, float value)
1156 {
1157 if (fabs(truncf(value) - value) < FLT_EPSILON) {
1158 vty_out(vty, " %d", (int)value);
1159 return;
1160 } else {
1161 vty_out(vty, " %f", value);
1162 }
1163 }
1164
1165 static void config_write_metric(struct vty *vty,
1166 enum srte_candidate_metric_type type,
1167 float value, bool required, bool is_bound)
1168 {
1169 const char *name = metric_type_name(type);
1170 if (name == NULL)
1171 return;
1172 vty_out(vty, " metric %s%s", is_bound ? "bound " : "",
1173 metric_type_name(type));
1174 config_write_float(vty, value);
1175 vty_out(vty, required ? " required" : "");
1176 vty_out(vty, "\n");
1177 }
1178
1179 static int config_write_metric_cb(const struct lyd_node *dnode, void *arg)
1180 {
1181 struct vty *vty = arg;
1182 enum srte_candidate_metric_type type;
1183 bool required, is_bound = false;
1184 float value;
1185
1186 type = yang_dnode_get_enum(dnode, "./type");
1187 value = (float)yang_dnode_get_dec64(dnode, "./value");
1188 required = yang_dnode_get_bool(dnode, "./required");
1189 if (yang_dnode_exists(dnode, "./is-bound"))
1190 is_bound = yang_dnode_get_bool(dnode, "./is-bound");
1191
1192 config_write_metric(vty, type, value, required, is_bound);
1193 return YANG_ITER_CONTINUE;
1194 }
1195
1196 void cli_show_srte_policy_candidate_path(struct vty *vty,
1197 const struct lyd_node *dnode,
1198 bool show_defaults)
1199 {
1200 float bandwidth;
1201 uint32_t affinity;
1202 bool required;
1203 enum objfun_type objfun_type;
1204 const char *type = yang_dnode_get_string(dnode, "./type");
1205
1206 vty_out(vty, " candidate-path preference %s name %s %s",
1207 yang_dnode_get_string(dnode, "./preference"),
1208 yang_dnode_get_string(dnode, "./name"), type);
1209 if (strmatch(type, "explicit"))
1210 vty_out(vty, " segment-list %s",
1211 yang_dnode_get_string(dnode, "./segment-list-name"));
1212 vty_out(vty, "\n");
1213
1214 if (strmatch(type, "dynamic")) {
1215 if (yang_dnode_exists(dnode, "./constraints/bandwidth")) {
1216 bandwidth = (float)yang_dnode_get_dec64(
1217 dnode, "./constraints/bandwidth/value");
1218 required = yang_dnode_get_bool(
1219 dnode, "./constraints/bandwidth/required");
1220 vty_out(vty, " bandwidth");
1221 config_write_float(vty, bandwidth);
1222 if (required)
1223 vty_out(vty, " required");
1224 vty_out(vty, "\n");
1225 }
1226 if (yang_dnode_exists(dnode,
1227 "./constraints/affinity/exclude-any")) {
1228 affinity = yang_dnode_get_uint32(
1229 dnode, "./constraints/affinity/exclude-any");
1230 vty_out(vty, " affinity exclude-any 0x%08x\n",
1231 affinity);
1232 }
1233 if (yang_dnode_exists(dnode,
1234 "./constraints/affinity/include-any")) {
1235 affinity = yang_dnode_get_uint32(
1236 dnode, "./constraints/affinity/include-any");
1237 vty_out(vty, " affinity include-any 0x%08x\n",
1238 affinity);
1239 }
1240 if (yang_dnode_exists(dnode,
1241 "./constraints/affinity/include-all")) {
1242 affinity = yang_dnode_get_uint32(
1243 dnode, "./constraints/affinity/include-all");
1244 vty_out(vty, " affinity include-all 0x%08x\n",
1245 affinity);
1246 }
1247 yang_dnode_iterate(config_write_metric_cb, vty, dnode,
1248 "./constraints/metrics");
1249 if (yang_dnode_exists(dnode,
1250 "./constraints/objective-function")) {
1251 objfun_type = yang_dnode_get_enum(dnode,
1252 "./constraints/objective-function/type");
1253 required = yang_dnode_get_bool(dnode,
1254 "./constraints/objective-function/required");
1255 vty_out(vty, " objective-function %s%s\n",
1256 objfun_type_name(objfun_type),
1257 required ? " required" : "");
1258 }
1259 }
1260 }
1261
1262 void cli_show_srte_policy_candidate_path_end(struct vty *vty,
1263 const struct lyd_node *dnode)
1264 {
1265 const char *type = yang_dnode_get_string(dnode, "./type");
1266
1267 if (strmatch(type, "dynamic"))
1268 vty_out(vty, " exit\n");
1269 }
1270
1271 static int config_write_dnode(const struct lyd_node *dnode, void *arg)
1272 {
1273 struct vty *vty = arg;
1274
1275 nb_cli_show_dnode_cmds(vty, dnode, false);
1276
1277 return YANG_ITER_CONTINUE;
1278 }
1279
1280 int config_write_segment_routing(struct vty *vty)
1281 {
1282 vty_out(vty, "segment-routing\n");
1283 vty_out(vty, " traffic-eng\n");
1284
1285 path_ted_config_write(vty);
1286
1287 yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
1288 "/frr-pathd:pathd/srte/segment-list");
1289 yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
1290 "/frr-pathd:pathd/srte/policy");
1291
1292 hook_call(pathd_srte_config_write, vty);
1293
1294 vty_out(vty, " exit\n");
1295 vty_out(vty, "exit\n");
1296
1297 return 1;
1298 }
1299
1300 static int path_policy_cli_debug_config_write(struct vty *vty)
1301 {
1302 if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) {
1303 if (DEBUG_FLAGS_CHECK(&path_policy_debug,
1304 PATH_POLICY_DEBUG_BASIC))
1305 vty_out(vty, "debug pathd policy\n");
1306 return 1;
1307 }
1308 return 0;
1309 }
1310
1311 static int path_policy_cli_debug_set_all(uint32_t flags, bool set)
1312 {
1313 DEBUG_FLAGS_SET(&path_policy_debug, flags, set);
1314
1315 /* If all modes have been turned off, don't preserve options. */
1316 if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL))
1317 DEBUG_CLEAR(&path_policy_debug);
1318
1319 return 0;
1320 }
1321
1322 void path_cli_init(void)
1323 {
1324 hook_register(nb_client_debug_config_write,
1325 path_policy_cli_debug_config_write);
1326 hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all);
1327
1328 install_node(&segment_routing_node);
1329 install_node(&sr_traffic_eng_node);
1330 install_node(&srte_segment_list_node);
1331 install_node(&srte_policy_node);
1332 install_node(&srte_candidate_dyn_node);
1333 install_default(SEGMENT_ROUTING_NODE);
1334 install_default(SR_TRAFFIC_ENG_NODE);
1335 install_default(SR_SEGMENT_LIST_NODE);
1336 install_default(SR_POLICY_NODE);
1337 install_default(SR_CANDIDATE_DYN_NODE);
1338
1339 install_element(ENABLE_NODE, &show_debugging_pathd_cmd);
1340 install_element(ENABLE_NODE, &show_srte_policy_cmd);
1341 install_element(ENABLE_NODE, &show_srte_policy_detail_cmd);
1342
1343 install_element(ENABLE_NODE, &debug_path_policy_cmd);
1344 install_element(CONFIG_NODE, &debug_path_policy_cmd);
1345
1346 install_element(CONFIG_NODE, &segment_routing_cmd);
1347 install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
1348 install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
1349 install_element(SR_TRAFFIC_ENG_NODE, &srte_no_segment_list_cmd);
1350 install_element(SR_SEGMENT_LIST_NODE,
1351 &srte_segment_list_segment_cmd);
1352 install_element(SR_SEGMENT_LIST_NODE,
1353 &srte_segment_list_no_segment_cmd);
1354 install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
1355 install_element(SR_TRAFFIC_ENG_NODE, &srte_no_policy_cmd);
1356 install_element(SR_POLICY_NODE, &srte_policy_name_cmd);
1357 install_element(SR_POLICY_NODE, &srte_policy_no_name_cmd);
1358 install_element(SR_POLICY_NODE, &srte_policy_binding_sid_cmd);
1359 install_element(SR_POLICY_NODE, &srte_policy_no_binding_sid_cmd);
1360 install_element(SR_POLICY_NODE, &srte_policy_candidate_exp_cmd);
1361 install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_cmd);
1362 install_element(SR_POLICY_NODE, &srte_policy_no_candidate_cmd);
1363 install_element(SR_CANDIDATE_DYN_NODE,
1364 &srte_candidate_bandwidth_cmd);
1365 install_element(SR_CANDIDATE_DYN_NODE,
1366 &srte_candidate_no_bandwidth_cmd);
1367 install_element(SR_CANDIDATE_DYN_NODE,
1368 &srte_candidate_affinity_filter_cmd);
1369 install_element(SR_CANDIDATE_DYN_NODE,
1370 &srte_candidate_no_affinity_filter_cmd);
1371 install_element(SR_CANDIDATE_DYN_NODE,
1372 &srte_candidate_metric_cmd);
1373 install_element(SR_CANDIDATE_DYN_NODE,
1374 &srte_candidate_no_metric_cmd);
1375 install_element(SR_CANDIDATE_DYN_NODE,
1376 &srte_candidate_objfun_cmd);
1377 install_element(SR_CANDIDATE_DYN_NODE,
1378 &srte_candidate_no_objfun_cmd);
1379 }