]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_vty.c
bgpd: Refactor subgroup_announce_table() to reuse an existing helpers
[mirror_frr.git] / staticd / static_vty.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * STATICd - vty code
4 * Copyright (C) 2018 Cumulus Networks, Inc.
5 * Donald Sharp
6 */
7 #include <zebra.h>
8
9 #include "command.h"
10 #include "vty.h"
11 #include "vrf.h"
12 #include "prefix.h"
13 #include "nexthop.h"
14 #include "table.h"
15 #include "srcdest_table.h"
16 #include "mgmt_be_client.h"
17 #include "mpls.h"
18 #include "northbound.h"
19 #include "libfrr.h"
20 #include "routing_nb.h"
21 #include "northbound_cli.h"
22
23 #include "static_vrf.h"
24 #include "static_vty.h"
25 #include "static_routes.h"
26 #include "static_debug.h"
27 #include "staticd/static_vty_clippy.c"
28 #include "static_nb.h"
29
30 #define STATICD_STR "Static route daemon\n"
31
32 /** All possible route parameters available in CLI. */
33 struct static_route_args {
34 /** "no" command? */
35 bool delete;
36 /** Is VRF obtained from XPath? */
37 bool xpath_vrf;
38
39 bool onlink;
40 afi_t afi;
41 safi_t safi;
42
43 const char *vrf;
44 const char *nexthop_vrf;
45 const char *prefix;
46 const char *prefix_mask;
47 const char *source;
48 const char *gateway;
49 const char *interface_name;
50 const char *flag;
51 const char *tag;
52 const char *distance;
53 const char *label;
54 const char *table;
55 const char *color;
56
57 bool bfd;
58 bool bfd_multi_hop;
59 const char *bfd_source;
60 const char *bfd_profile;
61 };
62
63 static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
64 {
65 int ret;
66 struct prefix p, src;
67 struct in_addr mask;
68 enum static_nh_type type;
69 const char *bh_type;
70 char xpath_prefix[XPATH_MAXLEN];
71 char xpath_nexthop[XPATH_MAXLEN];
72 char xpath_mpls[XPATH_MAXLEN];
73 char xpath_label[XPATH_MAXLEN];
74 char ab_xpath[XPATH_MAXLEN];
75 char buf_prefix[PREFIX_STRLEN];
76 char buf_src_prefix[PREFIX_STRLEN] = {};
77 char buf_nh_type[PREFIX_STRLEN] = {};
78 char buf_tag[PREFIX_STRLEN];
79 uint8_t label_stack_id = 0;
80 const char *buf_gate_str;
81 uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
82 route_tag_t tag = 0;
83 uint32_t table_id = 0;
84 const struct lyd_node *dnode;
85 const struct lyd_node *vrf_dnode;
86
87 if (args->xpath_vrf) {
88 vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
89 VTY_CURR_XPATH);
90 if (vrf_dnode == NULL) {
91 vty_out(vty,
92 "%% Failed to get vrf dnode in candidate db\n");
93 return CMD_WARNING_CONFIG_FAILED;
94 }
95
96 args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
97 } else {
98 if (args->vrf == NULL)
99 args->vrf = VRF_DEFAULT_NAME;
100 }
101 if (args->nexthop_vrf == NULL)
102 args->nexthop_vrf = args->vrf;
103
104 if (args->interface_name &&
105 !strcasecmp(args->interface_name, "Null0")) {
106 args->flag = "Null0";
107 args->interface_name = NULL;
108 }
109
110 assert(!!str2prefix(args->prefix, &p));
111
112 switch (args->afi) {
113 case AFI_IP:
114 /* Cisco like mask notation. */
115 if (args->prefix_mask) {
116 assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
117 1);
118 p.prefixlen = ip_masklen(mask);
119 }
120 break;
121 case AFI_IP6:
122 /* srcdest routing */
123 if (args->source)
124 assert(!!str2prefix(args->source, &src));
125 break;
126 case AFI_L2VPN:
127 case AFI_UNSPEC:
128 case AFI_MAX:
129 break;
130 }
131
132 /* Apply mask for given prefix. */
133 apply_mask(&p);
134 prefix2str(&p, buf_prefix, sizeof(buf_prefix));
135
136 if (args->bfd && args->gateway == NULL) {
137 vty_out(vty, "%% Route monitoring requires a gateway\n");
138 return CMD_WARNING_CONFIG_FAILED;
139 }
140
141 if (args->source)
142 prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
143 if (args->gateway)
144 buf_gate_str = args->gateway;
145 else
146 buf_gate_str = "";
147
148 if (args->gateway == NULL && args->interface_name == NULL)
149 type = STATIC_BLACKHOLE;
150 else if (args->gateway && args->interface_name) {
151 if (args->afi == AFI_IP)
152 type = STATIC_IPV4_GATEWAY_IFNAME;
153 else
154 type = STATIC_IPV6_GATEWAY_IFNAME;
155 } else if (args->interface_name)
156 type = STATIC_IFNAME;
157 else {
158 if (args->afi == AFI_IP)
159 type = STATIC_IPV4_GATEWAY;
160 else
161 type = STATIC_IPV6_GATEWAY;
162 }
163
164 /* Administrative distance. */
165 if (args->distance)
166 distance = strtol(args->distance, NULL, 10);
167
168 /* tag */
169 if (args->tag)
170 tag = strtoul(args->tag, NULL, 10);
171
172 /* TableID */
173 if (args->table)
174 table_id = strtol(args->table, NULL, 10);
175
176 static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
177 if (!args->delete) {
178 if (args->source)
179 snprintf(ab_xpath, sizeof(ab_xpath),
180 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
181 "frr-staticd:staticd", "staticd", args->vrf,
182 buf_prefix,
183 yang_afi_safi_value2identity(args->afi,
184 args->safi),
185 buf_src_prefix, table_id, buf_nh_type,
186 args->nexthop_vrf, buf_gate_str,
187 args->interface_name);
188 else
189 snprintf(ab_xpath, sizeof(ab_xpath),
190 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
191 "frr-staticd:staticd", "staticd", args->vrf,
192 buf_prefix,
193 yang_afi_safi_value2identity(args->afi,
194 args->safi),
195 table_id, buf_nh_type, args->nexthop_vrf,
196 buf_gate_str, args->interface_name);
197
198 /*
199 * If there's already the same nexthop but with a different
200 * distance, then remove it for the replacement.
201 */
202 dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
203 if (dnode) {
204 dnode = yang_get_subtree_with_no_sibling(dnode);
205 assert(dnode);
206 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
207
208 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY,
209 NULL);
210 }
211
212 /* route + path procesing */
213 if (args->source)
214 snprintf(xpath_prefix, sizeof(xpath_prefix),
215 FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
216 "frr-staticd:staticd", "staticd", args->vrf,
217 buf_prefix,
218 yang_afi_safi_value2identity(args->afi,
219 args->safi),
220 buf_src_prefix, table_id, distance);
221 else
222 snprintf(xpath_prefix, sizeof(xpath_prefix),
223 FRR_STATIC_ROUTE_INFO_KEY_XPATH,
224 "frr-staticd:staticd", "staticd", args->vrf,
225 buf_prefix,
226 yang_afi_safi_value2identity(args->afi,
227 args->safi),
228 table_id, distance);
229
230 nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
231
232 /* Tag processing */
233 snprintf(buf_tag, sizeof(buf_tag), "%u", tag);
234 strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
235 strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TAG_XPATH,
236 sizeof(ab_xpath));
237 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
238
239 /* nexthop processing */
240
241 snprintf(ab_xpath, sizeof(ab_xpath),
242 FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
243 args->nexthop_vrf, buf_gate_str, args->interface_name);
244 strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
245 strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
246 nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
247
248 if (type == STATIC_BLACKHOLE) {
249 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
250 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_BH_XPATH,
251 sizeof(ab_xpath));
252
253 /* Route flags */
254 if (args->flag) {
255 switch (args->flag[0]) {
256 case 'r':
257 bh_type = "reject";
258 break;
259 case 'b':
260 bh_type = "unspec";
261 break;
262 case 'N':
263 bh_type = "null";
264 break;
265 default:
266 bh_type = NULL;
267 break;
268 }
269 nb_cli_enqueue_change(vty, ab_xpath,
270 NB_OP_MODIFY, bh_type);
271 } else {
272 nb_cli_enqueue_change(vty, ab_xpath,
273 NB_OP_MODIFY, "null");
274 }
275 }
276 if (type == STATIC_IPV4_GATEWAY_IFNAME
277 || type == STATIC_IPV6_GATEWAY_IFNAME) {
278 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
279 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
280 sizeof(ab_xpath));
281
282 if (args->onlink)
283 nb_cli_enqueue_change(vty, ab_xpath,
284 NB_OP_MODIFY, "true");
285 else
286 nb_cli_enqueue_change(vty, ab_xpath,
287 NB_OP_MODIFY, "false");
288 }
289 if (type == STATIC_IPV4_GATEWAY ||
290 type == STATIC_IPV6_GATEWAY ||
291 type == STATIC_IPV4_GATEWAY_IFNAME ||
292 type == STATIC_IPV6_GATEWAY_IFNAME) {
293 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
294 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
295 sizeof(ab_xpath));
296 if (args->color)
297 nb_cli_enqueue_change(vty, ab_xpath,
298 NB_OP_MODIFY,
299 args->color);
300 }
301 if (args->label) {
302 /* copy of label string (start) */
303 char *ostr;
304 /* pointer to next segment */
305 char *nump;
306
307 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
308 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
309 sizeof(xpath_mpls));
310
311 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
312 NULL);
313
314 ostr = XSTRDUP(MTYPE_TMP, args->label);
315 while ((nump = strsep(&ostr, "/")) != NULL) {
316 snprintf(ab_xpath, sizeof(ab_xpath),
317 FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
318 label_stack_id);
319 strlcpy(xpath_label, xpath_mpls,
320 sizeof(xpath_label));
321 strlcat(xpath_label, ab_xpath,
322 sizeof(xpath_label));
323 nb_cli_enqueue_change(vty, xpath_label,
324 NB_OP_MODIFY, nump);
325 label_stack_id++;
326 }
327 XFREE(MTYPE_TMP, ostr);
328 } else {
329 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
330 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
331 sizeof(xpath_mpls));
332 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
333 NULL);
334 }
335
336 if (args->bfd) {
337 char xpath_bfd[XPATH_MAXLEN];
338
339 if (args->bfd_source) {
340 strlcpy(xpath_bfd, xpath_nexthop,
341 sizeof(xpath_bfd));
342 strlcat(xpath_bfd,
343 "/frr-staticd:bfd-monitoring/source",
344 sizeof(xpath_bfd));
345 nb_cli_enqueue_change(vty, xpath_bfd,
346 NB_OP_MODIFY,
347 args->bfd_source);
348 }
349
350 strlcpy(xpath_bfd, xpath_nexthop, sizeof(xpath_bfd));
351 strlcat(xpath_bfd,
352 "/frr-staticd:bfd-monitoring/multi-hop",
353 sizeof(xpath_bfd));
354 nb_cli_enqueue_change(vty, xpath_bfd, NB_OP_MODIFY,
355 args->bfd_multi_hop ? "true"
356 : "false");
357
358 if (args->bfd_profile) {
359 strlcpy(xpath_bfd, xpath_nexthop,
360 sizeof(xpath_bfd));
361 strlcat(xpath_bfd,
362 "/frr-staticd:bfd-monitoring/profile",
363 sizeof(xpath_bfd));
364 nb_cli_enqueue_change(vty, xpath_bfd,
365 NB_OP_MODIFY,
366 args->bfd_profile);
367 }
368 }
369
370 ret = nb_cli_apply_changes(vty, "%s", xpath_prefix);
371 } else {
372 if (args->source) {
373 if (args->distance)
374 snprintf(ab_xpath, sizeof(ab_xpath),
375 FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH,
376 "frr-staticd:staticd", "staticd",
377 args->vrf, buf_prefix,
378 yang_afi_safi_value2identity(
379 args->afi, args->safi),
380 buf_src_prefix, table_id, distance,
381 buf_nh_type, args->nexthop_vrf,
382 buf_gate_str, args->interface_name);
383 else
384 snprintf(
385 ab_xpath, sizeof(ab_xpath),
386 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
387 "frr-staticd:staticd", "staticd",
388 args->vrf, buf_prefix,
389 yang_afi_safi_value2identity(
390 args->afi, args->safi),
391 buf_src_prefix, table_id, buf_nh_type,
392 args->nexthop_vrf, buf_gate_str,
393 args->interface_name);
394 } else {
395 if (args->distance)
396 snprintf(ab_xpath, sizeof(ab_xpath),
397 FRR_DEL_S_ROUTE_NH_KEY_XPATH,
398 "frr-staticd:staticd", "staticd",
399 args->vrf, buf_prefix,
400 yang_afi_safi_value2identity(
401 args->afi, args->safi),
402 table_id, distance, buf_nh_type,
403 args->nexthop_vrf, buf_gate_str,
404 args->interface_name);
405 else
406 snprintf(
407 ab_xpath, sizeof(ab_xpath),
408 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
409 "frr-staticd:staticd", "staticd",
410 args->vrf, buf_prefix,
411 yang_afi_safi_value2identity(
412 args->afi, args->safi),
413 table_id, buf_nh_type,
414 args->nexthop_vrf, buf_gate_str,
415 args->interface_name);
416 }
417
418 dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
419 if (!dnode) {
420 vty_out(vty,
421 "%% Refusing to remove a non-existent route\n");
422 return CMD_SUCCESS;
423 }
424
425 dnode = yang_get_subtree_with_no_sibling(dnode);
426 assert(dnode);
427 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
428
429 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
430 ret = nb_cli_apply_changes(vty, "%s", ab_xpath);
431 }
432
433 return ret;
434 }
435
436 /* Static unicast routes for multicast RPF lookup. */
437 DEFPY_YANG (ip_mroute_dist,
438 ip_mroute_dist_cmd,
439 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [{"
440 "(1-255)$distance"
441 "|bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}]"
442 "}]",
443 NO_STR
444 IP_STR
445 "Configure static unicast route into MRIB for multicast RPF lookup\n"
446 "IP destination prefix (e.g. 10.0.0.0/8)\n"
447 "Nexthop address\n"
448 "Nexthop interface name\n"
449 "Distance\n"
450 BFD_INTEGRATION_STR
451 BFD_INTEGRATION_MULTI_HOP_STR
452 BFD_INTEGRATION_SOURCE_STR
453 BFD_INTEGRATION_SOURCEV4_STR
454 BFD_PROFILE_STR
455 BFD_PROFILE_NAME_STR)
456 {
457 struct static_route_args args = {
458 .delete = !!no,
459 .afi = AFI_IP,
460 .safi = SAFI_MULTICAST,
461 .prefix = prefix_str,
462 .gateway = gate_str,
463 .interface_name = ifname,
464 .distance = distance_str,
465 .bfd = !!bfd,
466 .bfd_multi_hop = !!bfd_multi_hop,
467 .bfd_source = bfd_source_str,
468 .bfd_profile = bfd_profile,
469 };
470
471 return static_route_nb_run(vty, &args);
472 }
473
474 /* Static route configuration. */
475 DEFPY_YANG(ip_route_blackhole,
476 ip_route_blackhole_cmd,
477 "[no] ip route\
478 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
479 <reject|blackhole>$flag \
480 [{ \
481 tag (1-4294967295) \
482 |(1-255)$distance \
483 |vrf NAME \
484 |label WORD \
485 |table (1-4294967295) \
486 }]",
487 NO_STR IP_STR
488 "Establish static routes\n"
489 "IP destination prefix (e.g. 10.0.0.0/8)\n"
490 "IP destination prefix\n"
491 "IP destination prefix mask\n"
492 "Emit an ICMP unreachable when matched\n"
493 "Silently discard pkts when matched\n"
494 "Set tag for this route\n"
495 "Tag value\n"
496 "Distance value for this route\n"
497 VRF_CMD_HELP_STR
498 MPLS_LABEL_HELPSTR
499 "Table to configure\n"
500 "The table number to configure\n")
501 {
502 struct static_route_args args = {
503 .delete = !!no,
504 .afi = AFI_IP,
505 .safi = SAFI_UNICAST,
506 .prefix = prefix,
507 .prefix_mask = mask_str,
508 .flag = flag,
509 .tag = tag_str,
510 .distance = distance_str,
511 .label = label,
512 .table = table_str,
513 .vrf = vrf,
514 };
515
516 return static_route_nb_run(vty, &args);
517 }
518
519 DEFPY_YANG(ip_route_blackhole_vrf,
520 ip_route_blackhole_vrf_cmd,
521 "[no] ip route\
522 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
523 <reject|blackhole>$flag \
524 [{ \
525 tag (1-4294967295) \
526 |(1-255)$distance \
527 |label WORD \
528 |table (1-4294967295) \
529 }]",
530 NO_STR IP_STR
531 "Establish static routes\n"
532 "IP destination prefix (e.g. 10.0.0.0/8)\n"
533 "IP destination prefix\n"
534 "IP destination prefix mask\n"
535 "Emit an ICMP unreachable when matched\n"
536 "Silently discard pkts when matched\n"
537 "Set tag for this route\n"
538 "Tag value\n"
539 "Distance value for this route\n"
540 MPLS_LABEL_HELPSTR
541 "Table to configure\n"
542 "The table number to configure\n")
543 {
544 struct static_route_args args = {
545 .delete = !!no,
546 .afi = AFI_IP,
547 .safi = SAFI_UNICAST,
548 .prefix = prefix,
549 .prefix_mask = mask_str,
550 .flag = flag,
551 .tag = tag_str,
552 .distance = distance_str,
553 .label = label,
554 .table = table_str,
555 .xpath_vrf = true,
556 };
557
558 /*
559 * Coverity is complaining that prefix could
560 * be dereferenced, but we know that prefix will
561 * valid. Add an assert to make it happy
562 */
563 assert(args.prefix);
564
565 return static_route_nb_run(vty, &args);
566 }
567
568 DEFPY_YANG(ip_route_address_interface,
569 ip_route_address_interface_cmd,
570 "[no] ip route\
571 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
572 A.B.C.D$gate \
573 <INTERFACE|Null0>$ifname \
574 [{ \
575 tag (1-4294967295) \
576 |(1-255)$distance \
577 |vrf NAME \
578 |label WORD \
579 |table (1-4294967295) \
580 |nexthop-vrf NAME \
581 |onlink$onlink \
582 |color (1-4294967295) \
583 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
584 }]",
585 NO_STR IP_STR
586 "Establish static routes\n"
587 "IP destination prefix (e.g. 10.0.0.0/8)\n"
588 "IP destination prefix\n"
589 "IP destination prefix mask\n"
590 "IP gateway address\n"
591 "IP gateway interface name\n"
592 "Null interface\n"
593 "Set tag for this route\n"
594 "Tag value\n"
595 "Distance value for this route\n"
596 VRF_CMD_HELP_STR
597 MPLS_LABEL_HELPSTR
598 "Table to configure\n"
599 "The table number to configure\n"
600 VRF_CMD_HELP_STR
601 "Treat the nexthop as directly attached to the interface\n"
602 "SR-TE color\n"
603 "The SR-TE color to configure\n"
604 BFD_INTEGRATION_STR
605 BFD_INTEGRATION_MULTI_HOP_STR
606 BFD_INTEGRATION_SOURCE_STR
607 BFD_INTEGRATION_SOURCEV4_STR
608 BFD_PROFILE_STR
609 BFD_PROFILE_NAME_STR)
610 {
611 struct static_route_args args = {
612 .delete = !!no,
613 .afi = AFI_IP,
614 .safi = SAFI_UNICAST,
615 .prefix = prefix,
616 .prefix_mask = mask_str,
617 .gateway = gate_str,
618 .interface_name = ifname,
619 .tag = tag_str,
620 .distance = distance_str,
621 .label = label,
622 .table = table_str,
623 .color = color_str,
624 .onlink = !!onlink,
625 .vrf = vrf,
626 .nexthop_vrf = nexthop_vrf,
627 .bfd = !!bfd,
628 .bfd_multi_hop = !!bfd_multi_hop,
629 .bfd_source = bfd_source_str,
630 .bfd_profile = bfd_profile,
631 };
632
633 return static_route_nb_run(vty, &args);
634 }
635
636 DEFPY_YANG(ip_route_address_interface_vrf,
637 ip_route_address_interface_vrf_cmd,
638 "[no] ip route\
639 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
640 A.B.C.D$gate \
641 <INTERFACE|Null0>$ifname \
642 [{ \
643 tag (1-4294967295) \
644 |(1-255)$distance \
645 |label WORD \
646 |table (1-4294967295) \
647 |nexthop-vrf NAME \
648 |onlink$onlink \
649 |color (1-4294967295) \
650 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
651 }]",
652 NO_STR IP_STR
653 "Establish static routes\n"
654 "IP destination prefix (e.g. 10.0.0.0/8)\n"
655 "IP destination prefix\n"
656 "IP destination prefix mask\n"
657 "IP gateway address\n"
658 "IP gateway interface name\n"
659 "Null interface\n"
660 "Set tag for this route\n"
661 "Tag value\n"
662 "Distance value for this route\n"
663 MPLS_LABEL_HELPSTR
664 "Table to configure\n"
665 "The table number to configure\n"
666 VRF_CMD_HELP_STR
667 "Treat the nexthop as directly attached to the interface\n"
668 "SR-TE color\n"
669 "The SR-TE color to configure\n"
670 BFD_INTEGRATION_STR
671 BFD_INTEGRATION_MULTI_HOP_STR
672 BFD_INTEGRATION_SOURCE_STR
673 BFD_INTEGRATION_SOURCEV4_STR
674 BFD_PROFILE_STR
675 BFD_PROFILE_NAME_STR)
676 {
677 struct static_route_args args = {
678 .delete = !!no,
679 .afi = AFI_IP,
680 .safi = SAFI_UNICAST,
681 .prefix = prefix,
682 .prefix_mask = mask_str,
683 .gateway = gate_str,
684 .interface_name = ifname,
685 .tag = tag_str,
686 .distance = distance_str,
687 .label = label,
688 .table = table_str,
689 .color = color_str,
690 .onlink = !!onlink,
691 .xpath_vrf = true,
692 .nexthop_vrf = nexthop_vrf,
693 .bfd = !!bfd,
694 .bfd_multi_hop = !!bfd_multi_hop,
695 .bfd_source = bfd_source_str,
696 .bfd_profile = bfd_profile,
697 };
698
699 return static_route_nb_run(vty, &args);
700 }
701
702 DEFPY_YANG(ip_route,
703 ip_route_cmd,
704 "[no] ip route\
705 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
706 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
707 [{ \
708 tag (1-4294967295) \
709 |(1-255)$distance \
710 |vrf NAME \
711 |label WORD \
712 |table (1-4294967295) \
713 |nexthop-vrf NAME \
714 |color (1-4294967295) \
715 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
716 }]",
717 NO_STR IP_STR
718 "Establish static routes\n"
719 "IP destination prefix (e.g. 10.0.0.0/8)\n"
720 "IP destination prefix\n"
721 "IP destination prefix mask\n"
722 "IP gateway address\n"
723 "IP gateway interface name\n"
724 "Null interface\n"
725 "Set tag for this route\n"
726 "Tag value\n"
727 "Distance value for this route\n"
728 VRF_CMD_HELP_STR
729 MPLS_LABEL_HELPSTR
730 "Table to configure\n"
731 "The table number to configure\n"
732 VRF_CMD_HELP_STR
733 "SR-TE color\n"
734 "The SR-TE color to configure\n"
735 BFD_INTEGRATION_STR
736 BFD_INTEGRATION_MULTI_HOP_STR
737 BFD_INTEGRATION_SOURCE_STR
738 BFD_INTEGRATION_SOURCEV4_STR
739 BFD_PROFILE_STR
740 BFD_PROFILE_NAME_STR)
741 {
742 struct static_route_args args = {
743 .delete = !!no,
744 .afi = AFI_IP,
745 .safi = SAFI_UNICAST,
746 .prefix = prefix,
747 .prefix_mask = mask_str,
748 .gateway = gate_str,
749 .interface_name = ifname,
750 .tag = tag_str,
751 .distance = distance_str,
752 .label = label,
753 .table = table_str,
754 .color = color_str,
755 .vrf = vrf,
756 .nexthop_vrf = nexthop_vrf,
757 .bfd = !!bfd,
758 .bfd_multi_hop = !!bfd_multi_hop,
759 .bfd_source = bfd_source_str,
760 .bfd_profile = bfd_profile,
761 };
762
763 return static_route_nb_run(vty, &args);
764 }
765
766 DEFPY_YANG(ip_route_vrf,
767 ip_route_vrf_cmd,
768 "[no] ip route\
769 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
770 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
771 [{ \
772 tag (1-4294967295) \
773 |(1-255)$distance \
774 |label WORD \
775 |table (1-4294967295) \
776 |nexthop-vrf NAME \
777 |color (1-4294967295) \
778 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
779 }]",
780 NO_STR IP_STR
781 "Establish static routes\n"
782 "IP destination prefix (e.g. 10.0.0.0/8)\n"
783 "IP destination prefix\n"
784 "IP destination prefix mask\n"
785 "IP gateway address\n"
786 "IP gateway interface name\n"
787 "Null interface\n"
788 "Set tag for this route\n"
789 "Tag value\n"
790 "Distance value for this route\n"
791 MPLS_LABEL_HELPSTR
792 "Table to configure\n"
793 "The table number to configure\n"
794 VRF_CMD_HELP_STR
795 "SR-TE color\n"
796 "The SR-TE color to configure\n"
797 BFD_INTEGRATION_STR
798 BFD_INTEGRATION_MULTI_HOP_STR
799 BFD_INTEGRATION_SOURCE_STR
800 BFD_INTEGRATION_SOURCEV4_STR
801 BFD_PROFILE_STR
802 BFD_PROFILE_NAME_STR)
803 {
804 struct static_route_args args = {
805 .delete = !!no,
806 .afi = AFI_IP,
807 .safi = SAFI_UNICAST,
808 .prefix = prefix,
809 .prefix_mask = mask_str,
810 .gateway = gate_str,
811 .interface_name = ifname,
812 .tag = tag_str,
813 .distance = distance_str,
814 .label = label,
815 .table = table_str,
816 .color = color_str,
817 .xpath_vrf = true,
818 .nexthop_vrf = nexthop_vrf,
819 .bfd = !!bfd,
820 .bfd_multi_hop = !!bfd_multi_hop,
821 .bfd_source = bfd_source_str,
822 .bfd_profile = bfd_profile,
823 };
824
825 return static_route_nb_run(vty, &args);
826 }
827
828 DEFPY_YANG(ipv6_route_blackhole,
829 ipv6_route_blackhole_cmd,
830 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
831 <reject|blackhole>$flag \
832 [{ \
833 tag (1-4294967295) \
834 |(1-255)$distance \
835 |vrf NAME \
836 |label WORD \
837 |table (1-4294967295) \
838 }]",
839 NO_STR
840 IPV6_STR
841 "Establish static routes\n"
842 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
843 "IPv6 source-dest route\n"
844 "IPv6 source prefix\n"
845 "Emit an ICMP unreachable when matched\n"
846 "Silently discard pkts when matched\n"
847 "Set tag for this route\n"
848 "Tag value\n"
849 "Distance value for this prefix\n"
850 VRF_CMD_HELP_STR
851 MPLS_LABEL_HELPSTR
852 "Table to configure\n"
853 "The table number to configure\n")
854 {
855 struct static_route_args args = {
856 .delete = !!no,
857 .afi = AFI_IP6,
858 .safi = SAFI_UNICAST,
859 .prefix = prefix_str,
860 .source = from_str,
861 .flag = flag,
862 .tag = tag_str,
863 .distance = distance_str,
864 .label = label,
865 .table = table_str,
866 .vrf = vrf,
867 };
868
869 return static_route_nb_run(vty, &args);
870 }
871
872 DEFPY_YANG(ipv6_route_blackhole_vrf,
873 ipv6_route_blackhole_vrf_cmd,
874 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
875 <reject|blackhole>$flag \
876 [{ \
877 tag (1-4294967295) \
878 |(1-255)$distance \
879 |label WORD \
880 |table (1-4294967295) \
881 }]",
882 NO_STR
883 IPV6_STR
884 "Establish static routes\n"
885 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
886 "IPv6 source-dest route\n"
887 "IPv6 source prefix\n"
888 "Emit an ICMP unreachable when matched\n"
889 "Silently discard pkts when matched\n"
890 "Set tag for this route\n"
891 "Tag value\n"
892 "Distance value for this prefix\n"
893 MPLS_LABEL_HELPSTR
894 "Table to configure\n"
895 "The table number to configure\n")
896 {
897 struct static_route_args args = {
898 .delete = !!no,
899 .afi = AFI_IP6,
900 .safi = SAFI_UNICAST,
901 .prefix = prefix_str,
902 .source = from_str,
903 .flag = flag,
904 .tag = tag_str,
905 .distance = distance_str,
906 .label = label,
907 .table = table_str,
908 .xpath_vrf = true,
909 };
910
911 /*
912 * Coverity is complaining that prefix could
913 * be dereferenced, but we know that prefix will
914 * valid. Add an assert to make it happy
915 */
916 assert(args.prefix);
917
918 return static_route_nb_run(vty, &args);
919 }
920
921 DEFPY_YANG(ipv6_route_address_interface,
922 ipv6_route_address_interface_cmd,
923 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
924 X:X::X:X$gate \
925 <INTERFACE|Null0>$ifname \
926 [{ \
927 tag (1-4294967295) \
928 |(1-255)$distance \
929 |vrf NAME \
930 |label WORD \
931 |table (1-4294967295) \
932 |nexthop-vrf NAME \
933 |onlink$onlink \
934 |color (1-4294967295) \
935 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
936 }]",
937 NO_STR
938 IPV6_STR
939 "Establish static routes\n"
940 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
941 "IPv6 source-dest route\n"
942 "IPv6 source prefix\n"
943 "IPv6 gateway address\n"
944 "IPv6 gateway interface name\n"
945 "Null interface\n"
946 "Set tag for this route\n"
947 "Tag value\n"
948 "Distance value for this prefix\n"
949 VRF_CMD_HELP_STR
950 MPLS_LABEL_HELPSTR
951 "Table to configure\n"
952 "The table number to configure\n"
953 VRF_CMD_HELP_STR
954 "Treat the nexthop as directly attached to the interface\n"
955 "SR-TE color\n"
956 "The SR-TE color to configure\n"
957 BFD_INTEGRATION_STR
958 BFD_INTEGRATION_MULTI_HOP_STR
959 BFD_INTEGRATION_SOURCE_STR
960 BFD_INTEGRATION_SOURCEV4_STR
961 BFD_PROFILE_STR
962 BFD_PROFILE_NAME_STR)
963 {
964 struct static_route_args args = {
965 .delete = !!no,
966 .afi = AFI_IP6,
967 .safi = SAFI_UNICAST,
968 .prefix = prefix_str,
969 .source = from_str,
970 .gateway = gate_str,
971 .interface_name = ifname,
972 .tag = tag_str,
973 .distance = distance_str,
974 .label = label,
975 .table = table_str,
976 .color = color_str,
977 .onlink = !!onlink,
978 .vrf = vrf,
979 .nexthop_vrf = nexthop_vrf,
980 .bfd = !!bfd,
981 .bfd_multi_hop = !!bfd_multi_hop,
982 .bfd_source = bfd_source_str,
983 .bfd_profile = bfd_profile,
984 };
985
986 return static_route_nb_run(vty, &args);
987 }
988
989 DEFPY_YANG(ipv6_route_address_interface_vrf,
990 ipv6_route_address_interface_vrf_cmd,
991 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
992 X:X::X:X$gate \
993 <INTERFACE|Null0>$ifname \
994 [{ \
995 tag (1-4294967295) \
996 |(1-255)$distance \
997 |label WORD \
998 |table (1-4294967295) \
999 |nexthop-vrf NAME \
1000 |onlink$onlink \
1001 |color (1-4294967295) \
1002 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1003 }]",
1004 NO_STR
1005 IPV6_STR
1006 "Establish static routes\n"
1007 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1008 "IPv6 source-dest route\n"
1009 "IPv6 source prefix\n"
1010 "IPv6 gateway address\n"
1011 "IPv6 gateway interface name\n"
1012 "Null interface\n"
1013 "Set tag for this route\n"
1014 "Tag value\n"
1015 "Distance value for this prefix\n"
1016 MPLS_LABEL_HELPSTR
1017 "Table to configure\n"
1018 "The table number to configure\n"
1019 VRF_CMD_HELP_STR
1020 "Treat the nexthop as directly attached to the interface\n"
1021 "SR-TE color\n"
1022 "The SR-TE color to configure\n"
1023 BFD_INTEGRATION_STR
1024 BFD_INTEGRATION_MULTI_HOP_STR
1025 BFD_INTEGRATION_SOURCE_STR
1026 BFD_INTEGRATION_SOURCEV4_STR
1027 BFD_PROFILE_STR
1028 BFD_PROFILE_NAME_STR)
1029 {
1030 struct static_route_args args = {
1031 .delete = !!no,
1032 .afi = AFI_IP6,
1033 .safi = SAFI_UNICAST,
1034 .prefix = prefix_str,
1035 .source = from_str,
1036 .gateway = gate_str,
1037 .interface_name = ifname,
1038 .tag = tag_str,
1039 .distance = distance_str,
1040 .label = label,
1041 .table = table_str,
1042 .color = color_str,
1043 .onlink = !!onlink,
1044 .xpath_vrf = true,
1045 .nexthop_vrf = nexthop_vrf,
1046 .bfd = !!bfd,
1047 .bfd_multi_hop = !!bfd_multi_hop,
1048 .bfd_source = bfd_source_str,
1049 .bfd_profile = bfd_profile,
1050 };
1051
1052 return static_route_nb_run(vty, &args);
1053 }
1054
1055 DEFPY_YANG(ipv6_route,
1056 ipv6_route_cmd,
1057 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1058 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1059 [{ \
1060 tag (1-4294967295) \
1061 |(1-255)$distance \
1062 |vrf NAME \
1063 |label WORD \
1064 |table (1-4294967295) \
1065 |nexthop-vrf NAME \
1066 |color (1-4294967295) \
1067 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1068 }]",
1069 NO_STR
1070 IPV6_STR
1071 "Establish static routes\n"
1072 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1073 "IPv6 source-dest route\n"
1074 "IPv6 source prefix\n"
1075 "IPv6 gateway address\n"
1076 "IPv6 gateway interface name\n"
1077 "Null interface\n"
1078 "Set tag for this route\n"
1079 "Tag value\n"
1080 "Distance value for this prefix\n"
1081 VRF_CMD_HELP_STR
1082 MPLS_LABEL_HELPSTR
1083 "Table to configure\n"
1084 "The table number to configure\n"
1085 VRF_CMD_HELP_STR
1086 "SR-TE color\n"
1087 "The SR-TE color to configure\n"
1088 BFD_INTEGRATION_STR
1089 BFD_INTEGRATION_MULTI_HOP_STR
1090 BFD_INTEGRATION_SOURCE_STR
1091 BFD_INTEGRATION_SOURCEV4_STR
1092 BFD_PROFILE_STR
1093 BFD_PROFILE_NAME_STR)
1094 {
1095 struct static_route_args args = {
1096 .delete = !!no,
1097 .afi = AFI_IP6,
1098 .safi = SAFI_UNICAST,
1099 .prefix = prefix_str,
1100 .source = from_str,
1101 .gateway = gate_str,
1102 .interface_name = ifname,
1103 .tag = tag_str,
1104 .distance = distance_str,
1105 .label = label,
1106 .table = table_str,
1107 .color = color_str,
1108 .vrf = vrf,
1109 .nexthop_vrf = nexthop_vrf,
1110 .bfd = !!bfd,
1111 .bfd_multi_hop = !!bfd_multi_hop,
1112 .bfd_source = bfd_source_str,
1113 .bfd_profile = bfd_profile,
1114 };
1115
1116 return static_route_nb_run(vty, &args);
1117 }
1118
1119 DEFPY_YANG(ipv6_route_vrf,
1120 ipv6_route_vrf_cmd,
1121 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1122 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1123 [{ \
1124 tag (1-4294967295) \
1125 |(1-255)$distance \
1126 |label WORD \
1127 |table (1-4294967295) \
1128 |nexthop-vrf NAME \
1129 |color (1-4294967295) \
1130 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1131 }]",
1132 NO_STR
1133 IPV6_STR
1134 "Establish static routes\n"
1135 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1136 "IPv6 source-dest route\n"
1137 "IPv6 source prefix\n"
1138 "IPv6 gateway address\n"
1139 "IPv6 gateway interface name\n"
1140 "Null interface\n"
1141 "Set tag for this route\n"
1142 "Tag value\n"
1143 "Distance value for this prefix\n"
1144 MPLS_LABEL_HELPSTR
1145 "Table to configure\n"
1146 "The table number to configure\n"
1147 VRF_CMD_HELP_STR
1148 "SR-TE color\n"
1149 "The SR-TE color to configure\n"
1150 BFD_INTEGRATION_STR
1151 BFD_INTEGRATION_MULTI_HOP_STR
1152 BFD_INTEGRATION_SOURCE_STR
1153 BFD_INTEGRATION_SOURCEV4_STR
1154 BFD_PROFILE_STR
1155 BFD_PROFILE_NAME_STR)
1156 {
1157 struct static_route_args args = {
1158 .delete = !!no,
1159 .afi = AFI_IP6,
1160 .safi = SAFI_UNICAST,
1161 .prefix = prefix_str,
1162 .source = from_str,
1163 .gateway = gate_str,
1164 .interface_name = ifname,
1165 .tag = tag_str,
1166 .distance = distance_str,
1167 .label = label,
1168 .table = table_str,
1169 .color = color_str,
1170 .xpath_vrf = true,
1171 .nexthop_vrf = nexthop_vrf,
1172 .bfd = !!bfd,
1173 .bfd_multi_hop = !!bfd_multi_hop,
1174 .bfd_source = bfd_source_str,
1175 .bfd_profile = bfd_profile,
1176 };
1177
1178 return static_route_nb_run(vty, &args);
1179 }
1180
1181 void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
1182 bool show_defaults)
1183 {
1184 const char *vrf;
1185
1186 vrf = yang_dnode_get_string(dnode, "../vrf");
1187 if (strcmp(vrf, VRF_DEFAULT_NAME))
1188 vty_out(vty, "vrf %s\n", vrf);
1189 }
1190
1191 void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
1192 {
1193 const char *vrf;
1194
1195 vrf = yang_dnode_get_string(dnode, "../vrf");
1196 if (strcmp(vrf, VRF_DEFAULT_NAME))
1197 vty_out(vty, "exit-vrf\n");
1198 }
1199
1200 struct mpls_label_iter {
1201 struct vty *vty;
1202 bool first;
1203 };
1204
1205 static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg)
1206 {
1207 struct mpls_label_iter *iter = arg;
1208
1209 if (yang_dnode_exists(dnode, "./label")) {
1210 if (iter->first)
1211 vty_out(iter->vty, " label %s",
1212 yang_dnode_get_string(dnode, "./label"));
1213 else
1214 vty_out(iter->vty, "/%s",
1215 yang_dnode_get_string(dnode, "./label"));
1216 iter->first = false;
1217 }
1218
1219 return YANG_ITER_CONTINUE;
1220 }
1221
1222 static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route,
1223 const struct lyd_node *src,
1224 const struct lyd_node *path,
1225 const struct lyd_node *nexthop, bool show_defaults)
1226 {
1227 const char *vrf;
1228 const char *afi_safi;
1229 afi_t afi;
1230 safi_t safi;
1231 enum static_nh_type nh_type;
1232 enum static_blackhole_type bh_type;
1233 uint32_t tag;
1234 uint8_t distance;
1235 struct mpls_label_iter iter;
1236 const char *nexthop_vrf;
1237 uint32_t table_id;
1238 bool onlink;
1239
1240 vrf = yang_dnode_get_string(route, "../../vrf");
1241
1242 afi_safi = yang_dnode_get_string(route, "./afi-safi");
1243 yang_afi_safi_identity2value(afi_safi, &afi, &safi);
1244
1245 if (afi == AFI_IP)
1246 vty_out(vty, "%sip",
1247 strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
1248 else
1249 vty_out(vty, "%sipv6",
1250 strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
1251
1252 if (safi == SAFI_UNICAST)
1253 vty_out(vty, " route");
1254 else
1255 vty_out(vty, " mroute");
1256
1257 vty_out(vty, " %s", yang_dnode_get_string(route, "./prefix"));
1258
1259 if (src)
1260 vty_out(vty, " from %s",
1261 yang_dnode_get_string(src, "./src-prefix"));
1262
1263 nh_type = yang_dnode_get_enum(nexthop, "./nh-type");
1264 switch (nh_type) {
1265 case STATIC_IFNAME:
1266 vty_out(vty, " %s",
1267 yang_dnode_get_string(nexthop, "./interface"));
1268 break;
1269 case STATIC_IPV4_GATEWAY:
1270 case STATIC_IPV6_GATEWAY:
1271 vty_out(vty, " %s",
1272 yang_dnode_get_string(nexthop, "./gateway"));
1273 break;
1274 case STATIC_IPV4_GATEWAY_IFNAME:
1275 case STATIC_IPV6_GATEWAY_IFNAME:
1276 vty_out(vty, " %s",
1277 yang_dnode_get_string(nexthop, "./gateway"));
1278 vty_out(vty, " %s",
1279 yang_dnode_get_string(nexthop, "./interface"));
1280 break;
1281 case STATIC_BLACKHOLE:
1282 bh_type = yang_dnode_get_enum(nexthop, "./bh-type");
1283 switch (bh_type) {
1284 case STATIC_BLACKHOLE_DROP:
1285 vty_out(vty, " blackhole");
1286 break;
1287 case STATIC_BLACKHOLE_NULL:
1288 vty_out(vty, " Null0");
1289 break;
1290 case STATIC_BLACKHOLE_REJECT:
1291 vty_out(vty, " reject");
1292 break;
1293 }
1294 break;
1295 }
1296
1297 if (yang_dnode_exists(path, "./tag")) {
1298 tag = yang_dnode_get_uint32(path, "./tag");
1299 if (tag != 0 || show_defaults)
1300 vty_out(vty, " tag %" PRIu32, tag);
1301 }
1302
1303 distance = yang_dnode_get_uint8(path, "./distance");
1304 if (distance != ZEBRA_STATIC_DISTANCE_DEFAULT || show_defaults)
1305 vty_out(vty, " %" PRIu8, distance);
1306
1307 iter.vty = vty;
1308 iter.first = true;
1309 yang_dnode_iterate(mpls_label_iter_cb, &iter, nexthop,
1310 "./mpls-label-stack/entry");
1311
1312 nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf");
1313 if (strcmp(vrf, nexthop_vrf))
1314 vty_out(vty, " nexthop-vrf %s", nexthop_vrf);
1315
1316 table_id = yang_dnode_get_uint32(path, "./table-id");
1317 if (table_id || show_defaults)
1318 vty_out(vty, " table %" PRIu32, table_id);
1319
1320 if (yang_dnode_exists(nexthop, "./onlink")) {
1321 onlink = yang_dnode_get_bool(nexthop, "./onlink");
1322 if (onlink)
1323 vty_out(vty, " onlink");
1324 }
1325
1326 if (yang_dnode_exists(nexthop, "./srte-color"))
1327 vty_out(vty, " color %s",
1328 yang_dnode_get_string(nexthop, "./srte-color"));
1329
1330 if (yang_dnode_exists(nexthop, "./bfd-monitoring")) {
1331 const struct lyd_node *bfd_dnode =
1332 yang_dnode_get(nexthop, "./bfd-monitoring");
1333
1334 if (yang_dnode_get_bool(bfd_dnode, "./multi-hop")) {
1335 vty_out(vty, " bfd multi-hop");
1336
1337 if (yang_dnode_exists(bfd_dnode, "./source"))
1338 vty_out(vty, " source %s",
1339 yang_dnode_get_string(bfd_dnode,
1340 "./source"));
1341 } else
1342 vty_out(vty, " bfd");
1343
1344 if (yang_dnode_exists(bfd_dnode, "./profile"))
1345 vty_out(vty, " profile %s",
1346 yang_dnode_get_string(bfd_dnode, "./profile"));
1347 }
1348
1349 vty_out(vty, "\n");
1350 }
1351
1352 void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
1353 bool show_defaults)
1354 {
1355 const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
1356 const struct lyd_node *route =
1357 yang_dnode_get_parent(path, "route-list");
1358
1359 nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults);
1360 }
1361
1362 void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
1363 bool show_defaults)
1364 {
1365 const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
1366 const struct lyd_node *src = yang_dnode_get_parent(path, "src-list");
1367 const struct lyd_node *route = yang_dnode_get_parent(src, "route-list");
1368
1369 nexthop_cli_show(vty, route, src, path, dnode, show_defaults);
1370 }
1371
1372 int static_nexthop_cli_cmp(const struct lyd_node *dnode1,
1373 const struct lyd_node *dnode2)
1374 {
1375 enum static_nh_type nh_type1, nh_type2;
1376 struct prefix prefix1, prefix2;
1377 int ret = 0;
1378
1379 nh_type1 = yang_dnode_get_enum(dnode1, "./nh-type");
1380 nh_type2 = yang_dnode_get_enum(dnode2, "./nh-type");
1381
1382 if (nh_type1 != nh_type2)
1383 return (int)nh_type1 - (int)nh_type2;
1384
1385 switch (nh_type1) {
1386 case STATIC_IFNAME:
1387 ret = if_cmp_name_func(
1388 yang_dnode_get_string(dnode1, "./interface"),
1389 yang_dnode_get_string(dnode2, "./interface"));
1390 break;
1391 case STATIC_IPV4_GATEWAY:
1392 case STATIC_IPV6_GATEWAY:
1393 yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
1394 yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
1395 ret = prefix_cmp(&prefix1, &prefix2);
1396 break;
1397 case STATIC_IPV4_GATEWAY_IFNAME:
1398 case STATIC_IPV6_GATEWAY_IFNAME:
1399 yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
1400 yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
1401 ret = prefix_cmp(&prefix1, &prefix2);
1402 if (!ret)
1403 ret = if_cmp_name_func(
1404 yang_dnode_get_string(dnode1, "./interface"),
1405 yang_dnode_get_string(dnode2, "./interface"));
1406 break;
1407 case STATIC_BLACKHOLE:
1408 /* There's only one blackhole nexthop per route */
1409 ret = 0;
1410 break;
1411 }
1412
1413 if (ret)
1414 return ret;
1415
1416 return if_cmp_name_func(yang_dnode_get_string(dnode1, "./vrf"),
1417 yang_dnode_get_string(dnode2, "./vrf"));
1418 }
1419
1420 int static_route_list_cli_cmp(const struct lyd_node *dnode1,
1421 const struct lyd_node *dnode2)
1422 {
1423 const char *afi_safi1, *afi_safi2;
1424 afi_t afi1, afi2;
1425 safi_t safi1, safi2;
1426 struct prefix prefix1, prefix2;
1427
1428 afi_safi1 = yang_dnode_get_string(dnode1, "./afi-safi");
1429 yang_afi_safi_identity2value(afi_safi1, &afi1, &safi1);
1430
1431 afi_safi2 = yang_dnode_get_string(dnode2, "./afi-safi");
1432 yang_afi_safi_identity2value(afi_safi2, &afi2, &safi2);
1433
1434 if (afi1 != afi2)
1435 return (int)afi1 - (int)afi2;
1436
1437 if (safi1 != safi2)
1438 return (int)safi1 - (int)safi2;
1439
1440 yang_dnode_get_prefix(&prefix1, dnode1, "./prefix");
1441 yang_dnode_get_prefix(&prefix2, dnode2, "./prefix");
1442
1443 return prefix_cmp(&prefix1, &prefix2);
1444 }
1445
1446 int static_src_list_cli_cmp(const struct lyd_node *dnode1,
1447 const struct lyd_node *dnode2)
1448 {
1449 struct prefix prefix1, prefix2;
1450
1451 yang_dnode_get_prefix(&prefix1, dnode1, "./src-prefix");
1452 yang_dnode_get_prefix(&prefix2, dnode2, "./src-prefix");
1453
1454 return prefix_cmp(&prefix1, &prefix2);
1455 }
1456
1457 int static_path_list_cli_cmp(const struct lyd_node *dnode1,
1458 const struct lyd_node *dnode2)
1459 {
1460 uint32_t table_id1, table_id2;
1461 uint8_t distance1, distance2;
1462
1463 table_id1 = yang_dnode_get_uint32(dnode1, "./table-id");
1464 table_id2 = yang_dnode_get_uint32(dnode2, "./table-id");
1465
1466 if (table_id1 != table_id2)
1467 return (int)table_id1 - (int)table_id2;
1468
1469 distance1 = yang_dnode_get_uint8(dnode1, "./distance");
1470 distance2 = yang_dnode_get_uint8(dnode2, "./distance");
1471
1472 return (int)distance1 - (int)distance2;
1473 }
1474
1475 DEFPY_YANG(debug_staticd, debug_staticd_cmd,
1476 "[no] debug static [{events$events|route$route|bfd$bfd}]",
1477 NO_STR DEBUG_STR STATICD_STR
1478 "Debug events\n"
1479 "Debug route\n"
1480 "Debug bfd\n")
1481 {
1482 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1483 /* If no specific category, change all */
1484 if (strmatch(argv[argc - 1]->text, "static"))
1485 static_debug_set(vty->node, !no, true, true, true);
1486 else
1487 static_debug_set(vty->node, !no, !!events, !!route, !!bfd);
1488 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1489
1490 return CMD_SUCCESS;
1491 }
1492
1493 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1494 DEFPY(staticd_show_bfd_routes, staticd_show_bfd_routes_cmd,
1495 "show bfd static route [json]$isjson",
1496 SHOW_STR
1497 BFD_INTEGRATION_STR
1498 STATICD_STR
1499 ROUTE_STR
1500 JSON_STR)
1501 {
1502 static_bfd_show(vty, !!isjson);
1503 return CMD_SUCCESS;
1504 }
1505
1506 DEFUN_NOSH (show_debugging_static,
1507 show_debugging_static_cmd,
1508 "show debugging [static]",
1509 SHOW_STR
1510 DEBUG_STR
1511 "Static Information\n")
1512 {
1513 vty_out(vty, "Staticd debugging status\n");
1514
1515 static_debug_status_write(vty);
1516
1517 cmd_show_lib_debugs(vty);
1518
1519 return CMD_SUCCESS;
1520 }
1521
1522 static struct cmd_node debug_node = {
1523 .name = "debug",
1524 .node = DEBUG_NODE,
1525 .prompt = "",
1526 .config_write = static_config_write_debug,
1527 };
1528
1529 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1530
1531 void static_vty_init(void)
1532 {
1533 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1534 install_node(&debug_node);
1535 install_element(ENABLE_NODE, &show_debugging_static_cmd);
1536 install_element(ENABLE_NODE, &staticd_show_bfd_routes_cmd);
1537 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1538
1539 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1540
1541 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1542 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1543 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1544 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1545 install_element(CONFIG_NODE, &ip_route_cmd);
1546 install_element(VRF_NODE, &ip_route_vrf_cmd);
1547
1548 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1549 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1550 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1551 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1552 install_element(CONFIG_NODE, &ipv6_route_cmd);
1553 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1554
1555 install_element(ENABLE_NODE, &debug_staticd_cmd);
1556 install_element(CONFIG_NODE, &debug_staticd_cmd);
1557
1558 mgmt_be_client_lib_vty_init();
1559 }