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