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