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