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