1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Cumulus Networks, Inc.
15 #include "srcdest_table.h"
17 #include "northbound.h"
19 #include "routing_nb.h"
20 #include "northbound_cli.h"
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"
29 #define STATICD_STR "Static route daemon\n"
31 /** All possible route parameters available in CLI. */
32 struct static_route_args
{
35 /** Is VRF obtained from XPath? */
43 const char *nexthop_vrf
;
45 const char *prefix_mask
;
48 const char *interface_name
;
58 const char *bfd_source
;
59 const char *bfd_profile
;
62 static int static_route_nb_run(struct vty
*vty
, struct static_route_args
*args
)
67 enum static_nh_type 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
;
82 uint32_t table_id
= 0;
83 const struct lyd_node
*dnode
;
84 const struct lyd_node
*vrf_dnode
;
86 if (args
->xpath_vrf
) {
87 vrf_dnode
= yang_dnode_get(vty
->candidate_config
->dnode
,
89 if (vrf_dnode
== NULL
) {
91 "%% Failed to get vrf dnode in candidate db\n");
92 return CMD_WARNING_CONFIG_FAILED
;
95 args
->vrf
= yang_dnode_get_string(vrf_dnode
, "./name");
97 if (args
->vrf
== NULL
)
98 args
->vrf
= VRF_DEFAULT_NAME
;
100 if (args
->nexthop_vrf
== NULL
)
101 args
->nexthop_vrf
= args
->vrf
;
103 if (args
->interface_name
&&
104 !strcasecmp(args
->interface_name
, "Null0")) {
105 args
->flag
= "Null0";
106 args
->interface_name
= NULL
;
109 assert(!!str2prefix(args
->prefix
, &p
));
113 /* Cisco like mask notation. */
114 if (args
->prefix_mask
) {
115 assert(inet_pton(AF_INET
, args
->prefix_mask
, &mask
) ==
117 p
.prefixlen
= ip_masklen(mask
);
121 /* srcdest routing */
123 assert(!!str2prefix(args
->source
, &src
));
131 /* Apply mask for given prefix. */
133 prefix2str(&p
, buf_prefix
, sizeof(buf_prefix
));
135 if (args
->bfd
&& args
->gateway
== NULL
) {
136 vty_out(vty
, "%% Route monitoring requires a gateway\n");
137 return CMD_WARNING_CONFIG_FAILED
;
141 prefix2str(&src
, buf_src_prefix
, sizeof(buf_src_prefix
));
143 buf_gate_str
= args
->gateway
;
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
;
153 type
= STATIC_IPV6_GATEWAY_IFNAME
;
154 } else if (args
->interface_name
)
155 type
= STATIC_IFNAME
;
157 if (args
->afi
== AFI_IP
)
158 type
= STATIC_IPV4_GATEWAY
;
160 type
= STATIC_IPV6_GATEWAY
;
163 /* Administrative distance. */
165 distance
= strtol(args
->distance
, NULL
, 10);
169 tag
= strtoul(args
->tag
, NULL
, 10);
173 table_id
= strtol(args
->table
, NULL
, 10);
175 static_get_nh_type(type
, buf_nh_type
, sizeof(buf_nh_type
));
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
,
182 yang_afi_safi_value2identity(args
->afi
,
184 buf_src_prefix
, table_id
, buf_nh_type
,
185 args
->nexthop_vrf
, buf_gate_str
,
186 args
->interface_name
);
188 snprintf(ab_xpath
, sizeof(ab_xpath
),
189 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
190 "frr-staticd:staticd", "staticd", args
->vrf
,
192 yang_afi_safi_value2identity(args
->afi
,
194 table_id
, buf_nh_type
, args
->nexthop_vrf
,
195 buf_gate_str
, args
->interface_name
);
198 * If there's already the same nexthop but with a different
199 * distance, then remove it for the replacement.
201 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
203 dnode
= yang_get_subtree_with_no_sibling(dnode
);
205 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
207 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
,
211 /* route + path procesing */
213 snprintf(xpath_prefix
, sizeof(xpath_prefix
),
214 FRR_S_ROUTE_SRC_INFO_KEY_XPATH
,
215 "frr-staticd:staticd", "staticd", args
->vrf
,
217 yang_afi_safi_value2identity(args
->afi
,
219 buf_src_prefix
, table_id
, distance
);
221 snprintf(xpath_prefix
, sizeof(xpath_prefix
),
222 FRR_STATIC_ROUTE_INFO_KEY_XPATH
,
223 "frr-staticd:staticd", "staticd", args
->vrf
,
225 yang_afi_safi_value2identity(args
->afi
,
229 nb_cli_enqueue_change(vty
, xpath_prefix
, NB_OP_CREATE
, NULL
);
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
,
236 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_MODIFY
, buf_tag
);
238 /* nexthop processing */
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
);
247 if (type
== STATIC_BLACKHOLE
) {
248 strlcpy(ab_xpath
, xpath_nexthop
, sizeof(ab_xpath
));
249 strlcat(ab_xpath
, FRR_STATIC_ROUTE_NH_BH_XPATH
,
254 switch (args
->flag
[0]) {
268 nb_cli_enqueue_change(vty
, ab_xpath
,
269 NB_OP_MODIFY
, bh_type
);
271 nb_cli_enqueue_change(vty
, ab_xpath
,
272 NB_OP_MODIFY
, "null");
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
,
282 nb_cli_enqueue_change(vty
, ab_xpath
,
283 NB_OP_MODIFY
, "true");
285 nb_cli_enqueue_change(vty
, ab_xpath
,
286 NB_OP_MODIFY
, "false");
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
,
296 nb_cli_enqueue_change(vty
, ab_xpath
,
301 /* copy of label string (start) */
303 /* pointer to next segment */
306 strlcpy(xpath_mpls
, xpath_nexthop
, sizeof(xpath_mpls
));
307 strlcat(xpath_mpls
, FRR_STATIC_ROUTE_NH_LABEL_XPATH
,
310 nb_cli_enqueue_change(vty
, xpath_mpls
, NB_OP_DESTROY
,
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
,
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
,
326 XFREE(MTYPE_TMP
, ostr
);
328 strlcpy(xpath_mpls
, xpath_nexthop
, sizeof(xpath_mpls
));
329 strlcat(xpath_mpls
, FRR_STATIC_ROUTE_NH_LABEL_XPATH
,
331 nb_cli_enqueue_change(vty
, xpath_mpls
, NB_OP_DESTROY
,
336 char xpath_bfd
[XPATH_MAXLEN
];
338 if (args
->bfd_source
) {
339 strlcpy(xpath_bfd
, xpath_nexthop
,
342 "/frr-staticd:bfd-monitoring/source",
344 nb_cli_enqueue_change(vty
, xpath_bfd
,
349 strlcpy(xpath_bfd
, xpath_nexthop
, sizeof(xpath_bfd
));
351 "/frr-staticd:bfd-monitoring/multi-hop",
353 nb_cli_enqueue_change(vty
, xpath_bfd
, NB_OP_MODIFY
,
354 args
->bfd_multi_hop
? "true"
357 if (args
->bfd_profile
) {
358 strlcpy(xpath_bfd
, xpath_nexthop
,
361 "/frr-staticd:bfd-monitoring/profile",
363 nb_cli_enqueue_change(vty
, xpath_bfd
,
369 ret
= nb_cli_apply_changes(vty
, "%s", xpath_prefix
);
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
,
376 yang_afi_safi_value2identity(args
->afi
,
378 buf_src_prefix
, table_id
, buf_nh_type
,
379 args
->nexthop_vrf
, buf_gate_str
,
380 args
->interface_name
);
382 snprintf(ab_xpath
, sizeof(ab_xpath
),
383 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
384 "frr-staticd:staticd", "staticd", args
->vrf
,
386 yang_afi_safi_value2identity(args
->afi
,
388 table_id
, buf_nh_type
, args
->nexthop_vrf
,
389 buf_gate_str
, args
->interface_name
);
391 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
394 "%% Refusing to remove a non-existent route\n");
398 dnode
= yang_get_subtree_with_no_sibling(dnode
);
400 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
402 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
, NULL
);
403 ret
= nb_cli_apply_changes(vty
, "%s", ab_xpath
);
409 /* Static unicast routes for multicast RPF lookup. */
410 DEFPY_YANG (ip_mroute_dist
,
412 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [{"
414 "|bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}]"
418 "Configure static unicast route into MRIB for multicast RPF lookup\n"
419 "IP destination prefix (e.g. 10.0.0.0/8)\n"
421 "Nexthop interface name\n"
424 BFD_INTEGRATION_MULTI_HOP_STR
425 BFD_INTEGRATION_SOURCE_STR
426 BFD_INTEGRATION_SOURCEV4_STR
428 BFD_PROFILE_NAME_STR
)
430 struct static_route_args args
= {
433 .safi
= SAFI_MULTICAST
,
434 .prefix
= prefix_str
,
436 .interface_name
= ifname
,
437 .distance
= distance_str
,
439 .bfd_multi_hop
= !!bfd_multi_hop
,
440 .bfd_source
= bfd_source_str
,
441 .bfd_profile
= bfd_profile
,
444 return static_route_nb_run(vty
, &args
);
447 /* Static route configuration. */
448 DEFPY_YANG(ip_route_blackhole
,
449 ip_route_blackhole_cmd
,
451 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
452 <reject|blackhole>$flag \
458 |table (1-4294967295) \
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"
469 "Distance value for this route\n"
472 "Table to configure\n"
473 "The table number to configure\n")
475 struct static_route_args args
= {
478 .safi
= SAFI_UNICAST
,
480 .prefix_mask
= mask_str
,
483 .distance
= distance_str
,
489 return static_route_nb_run(vty
, &args
);
492 DEFPY_YANG(ip_route_blackhole_vrf
,
493 ip_route_blackhole_vrf_cmd
,
495 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
496 <reject|blackhole>$flag \
501 |table (1-4294967295) \
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"
512 "Distance value for this route\n"
514 "Table to configure\n"
515 "The table number to configure\n")
517 struct static_route_args args
= {
520 .safi
= SAFI_UNICAST
,
522 .prefix_mask
= mask_str
,
525 .distance
= distance_str
,
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
538 return static_route_nb_run(vty
, &args
);
541 DEFPY_YANG(ip_route_address_interface
,
542 ip_route_address_interface_cmd
,
544 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
546 <INTERFACE|Null0>$ifname \
552 |table (1-4294967295) \
555 |color (1-4294967295) \
556 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
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"
566 "Set tag for this route\n"
568 "Distance value for this route\n"
571 "Table to configure\n"
572 "The table number to configure\n"
574 "Treat the nexthop as directly attached to the interface\n"
576 "The SR-TE color to configure\n"
578 BFD_INTEGRATION_MULTI_HOP_STR
579 BFD_INTEGRATION_SOURCE_STR
580 BFD_INTEGRATION_SOURCEV4_STR
582 BFD_PROFILE_NAME_STR
)
584 struct static_route_args args
= {
587 .safi
= SAFI_UNICAST
,
589 .prefix_mask
= mask_str
,
591 .interface_name
= ifname
,
593 .distance
= distance_str
,
599 .nexthop_vrf
= nexthop_vrf
,
601 .bfd_multi_hop
= !!bfd_multi_hop
,
602 .bfd_source
= bfd_source_str
,
603 .bfd_profile
= bfd_profile
,
606 return static_route_nb_run(vty
, &args
);
609 DEFPY_YANG(ip_route_address_interface_vrf
,
610 ip_route_address_interface_vrf_cmd
,
612 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
614 <INTERFACE|Null0>$ifname \
619 |table (1-4294967295) \
622 |color (1-4294967295) \
623 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
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"
633 "Set tag for this route\n"
635 "Distance value for this route\n"
637 "Table to configure\n"
638 "The table number to configure\n"
640 "Treat the nexthop as directly attached to the interface\n"
642 "The SR-TE color to configure\n"
644 BFD_INTEGRATION_MULTI_HOP_STR
645 BFD_INTEGRATION_SOURCE_STR
646 BFD_INTEGRATION_SOURCEV4_STR
648 BFD_PROFILE_NAME_STR
)
650 struct static_route_args args
= {
653 .safi
= SAFI_UNICAST
,
655 .prefix_mask
= mask_str
,
657 .interface_name
= ifname
,
659 .distance
= distance_str
,
665 .nexthop_vrf
= nexthop_vrf
,
667 .bfd_multi_hop
= !!bfd_multi_hop
,
668 .bfd_source
= bfd_source_str
,
669 .bfd_profile
= bfd_profile
,
672 return static_route_nb_run(vty
, &args
);
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> \
685 |table (1-4294967295) \
687 |color (1-4294967295) \
688 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
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"
698 "Set tag for this route\n"
700 "Distance value for this route\n"
703 "Table to configure\n"
704 "The table number to configure\n"
707 "The SR-TE color to configure\n"
709 BFD_INTEGRATION_MULTI_HOP_STR
710 BFD_INTEGRATION_SOURCE_STR
711 BFD_INTEGRATION_SOURCEV4_STR
713 BFD_PROFILE_NAME_STR
)
715 struct static_route_args args
= {
718 .safi
= SAFI_UNICAST
,
720 .prefix_mask
= mask_str
,
722 .interface_name
= ifname
,
724 .distance
= distance_str
,
729 .nexthop_vrf
= nexthop_vrf
,
731 .bfd_multi_hop
= !!bfd_multi_hop
,
732 .bfd_source
= bfd_source_str
,
733 .bfd_profile
= bfd_profile
,
736 return static_route_nb_run(vty
, &args
);
739 DEFPY_YANG(ip_route_vrf
,
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> \
748 |table (1-4294967295) \
750 |color (1-4294967295) \
751 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
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"
761 "Set tag for this route\n"
763 "Distance value for this route\n"
765 "Table to configure\n"
766 "The table number to configure\n"
769 "The SR-TE color to configure\n"
771 BFD_INTEGRATION_MULTI_HOP_STR
772 BFD_INTEGRATION_SOURCE_STR
773 BFD_INTEGRATION_SOURCEV4_STR
775 BFD_PROFILE_NAME_STR
)
777 struct static_route_args args
= {
780 .safi
= SAFI_UNICAST
,
782 .prefix_mask
= mask_str
,
784 .interface_name
= ifname
,
786 .distance
= distance_str
,
791 .nexthop_vrf
= nexthop_vrf
,
793 .bfd_multi_hop
= !!bfd_multi_hop
,
794 .bfd_source
= bfd_source_str
,
795 .bfd_profile
= bfd_profile
,
798 return static_route_nb_run(vty
, &args
);
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 \
810 |table (1-4294967295) \
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"
822 "Distance value for this prefix\n"
825 "Table to configure\n"
826 "The table number to configure\n")
828 struct static_route_args args
= {
831 .safi
= SAFI_UNICAST
,
832 .prefix
= prefix_str
,
836 .distance
= distance_str
,
842 return static_route_nb_run(vty
, &args
);
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 \
853 |table (1-4294967295) \
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"
865 "Distance value for this prefix\n"
867 "Table to configure\n"
868 "The table number to configure\n")
870 struct static_route_args args
= {
873 .safi
= SAFI_UNICAST
,
874 .prefix
= prefix_str
,
878 .distance
= distance_str
,
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
891 return static_route_nb_run(vty
, &args
);
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] \
898 <INTERFACE|Null0>$ifname \
904 |table (1-4294967295) \
907 |color (1-4294967295) \
908 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
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"
919 "Set tag for this route\n"
921 "Distance value for this prefix\n"
924 "Table to configure\n"
925 "The table number to configure\n"
927 "Treat the nexthop as directly attached to the interface\n"
929 "The SR-TE color to configure\n"
931 BFD_INTEGRATION_MULTI_HOP_STR
932 BFD_INTEGRATION_SOURCE_STR
933 BFD_INTEGRATION_SOURCEV4_STR
935 BFD_PROFILE_NAME_STR
)
937 struct static_route_args args
= {
940 .safi
= SAFI_UNICAST
,
941 .prefix
= prefix_str
,
944 .interface_name
= ifname
,
946 .distance
= distance_str
,
952 .nexthop_vrf
= nexthop_vrf
,
954 .bfd_multi_hop
= !!bfd_multi_hop
,
955 .bfd_source
= bfd_source_str
,
956 .bfd_profile
= bfd_profile
,
959 return static_route_nb_run(vty
, &args
);
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] \
966 <INTERFACE|Null0>$ifname \
971 |table (1-4294967295) \
974 |color (1-4294967295) \
975 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
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"
986 "Set tag for this route\n"
988 "Distance value for this prefix\n"
990 "Table to configure\n"
991 "The table number to configure\n"
993 "Treat the nexthop as directly attached to the interface\n"
995 "The SR-TE color to configure\n"
997 BFD_INTEGRATION_MULTI_HOP_STR
998 BFD_INTEGRATION_SOURCE_STR
999 BFD_INTEGRATION_SOURCEV4_STR
1001 BFD_PROFILE_NAME_STR
)
1003 struct static_route_args args
= {
1006 .safi
= SAFI_UNICAST
,
1007 .prefix
= prefix_str
,
1009 .gateway
= gate_str
,
1010 .interface_name
= ifname
,
1012 .distance
= distance_str
,
1018 .nexthop_vrf
= nexthop_vrf
,
1020 .bfd_multi_hop
= !!bfd_multi_hop
,
1021 .bfd_source
= bfd_source_str
,
1022 .bfd_profile
= bfd_profile
,
1025 return static_route_nb_run(vty
, &args
);
1028 DEFPY_YANG(ipv6_route
,
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> \
1033 tag (1-4294967295) \
1037 |table (1-4294967295) \
1039 |color (1-4294967295) \
1040 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
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"
1051 "Set tag for this route\n"
1053 "Distance value for this prefix\n"
1056 "Table to configure\n"
1057 "The table number to configure\n"
1060 "The SR-TE color to configure\n"
1062 BFD_INTEGRATION_MULTI_HOP_STR
1063 BFD_INTEGRATION_SOURCE_STR
1064 BFD_INTEGRATION_SOURCEV4_STR
1066 BFD_PROFILE_NAME_STR
)
1068 struct static_route_args args
= {
1071 .safi
= SAFI_UNICAST
,
1072 .prefix
= prefix_str
,
1074 .gateway
= gate_str
,
1075 .interface_name
= ifname
,
1077 .distance
= distance_str
,
1082 .nexthop_vrf
= nexthop_vrf
,
1084 .bfd_multi_hop
= !!bfd_multi_hop
,
1085 .bfd_source
= bfd_source_str
,
1086 .bfd_profile
= bfd_profile
,
1089 return static_route_nb_run(vty
, &args
);
1092 DEFPY_YANG(ipv6_route_vrf
,
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> \
1097 tag (1-4294967295) \
1100 |table (1-4294967295) \
1102 |color (1-4294967295) \
1103 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
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"
1114 "Set tag for this route\n"
1116 "Distance value for this prefix\n"
1118 "Table to configure\n"
1119 "The table number to configure\n"
1122 "The SR-TE color to configure\n"
1124 BFD_INTEGRATION_MULTI_HOP_STR
1125 BFD_INTEGRATION_SOURCE_STR
1126 BFD_INTEGRATION_SOURCEV4_STR
1128 BFD_PROFILE_NAME_STR
)
1130 struct static_route_args args
= {
1133 .safi
= SAFI_UNICAST
,
1134 .prefix
= prefix_str
,
1136 .gateway
= gate_str
,
1137 .interface_name
= ifname
,
1139 .distance
= distance_str
,
1144 .nexthop_vrf
= nexthop_vrf
,
1146 .bfd_multi_hop
= !!bfd_multi_hop
,
1147 .bfd_source
= bfd_source_str
,
1148 .bfd_profile
= bfd_profile
,
1151 return static_route_nb_run(vty
, &args
);
1154 void static_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1159 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1160 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1161 vty_out(vty
, "vrf %s\n", vrf
);
1164 void static_cli_show_end(struct vty
*vty
, const struct lyd_node
*dnode
)
1168 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1169 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1170 vty_out(vty
, "exit-vrf\n");
1173 struct mpls_label_iter
{
1178 static int mpls_label_iter_cb(const struct lyd_node
*dnode
, void *arg
)
1180 struct mpls_label_iter
*iter
= arg
;
1182 if (yang_dnode_exists(dnode
, "./label")) {
1184 vty_out(iter
->vty
, " label %s",
1185 yang_dnode_get_string(dnode
, "./label"));
1187 vty_out(iter
->vty
, "/%s",
1188 yang_dnode_get_string(dnode
, "./label"));
1189 iter
->first
= false;
1192 return YANG_ITER_CONTINUE
;
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
)
1201 const char *afi_safi
;
1204 enum static_nh_type nh_type
;
1205 enum static_blackhole_type bh_type
;
1208 struct mpls_label_iter iter
;
1209 const char *nexthop_vrf
;
1213 vrf
= yang_dnode_get_string(route
, "../../vrf");
1215 afi_safi
= yang_dnode_get_string(route
, "./afi-safi");
1216 yang_afi_safi_identity2value(afi_safi
, &afi
, &safi
);
1219 vty_out(vty
, "%sip",
1220 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1222 vty_out(vty
, "%sipv6",
1223 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1225 if (safi
== SAFI_UNICAST
)
1226 vty_out(vty
, " route");
1228 vty_out(vty
, " mroute");
1230 vty_out(vty
, " %s", yang_dnode_get_string(route
, "./prefix"));
1233 vty_out(vty
, " from %s",
1234 yang_dnode_get_string(src
, "./src-prefix"));
1236 nh_type
= yang_dnode_get_enum(nexthop
, "./nh-type");
1240 yang_dnode_get_string(nexthop
, "./interface"));
1242 case STATIC_IPV4_GATEWAY
:
1243 case STATIC_IPV6_GATEWAY
:
1245 yang_dnode_get_string(nexthop
, "./gateway"));
1247 case STATIC_IPV4_GATEWAY_IFNAME
:
1248 case STATIC_IPV6_GATEWAY_IFNAME
:
1250 yang_dnode_get_string(nexthop
, "./gateway"));
1252 yang_dnode_get_string(nexthop
, "./interface"));
1254 case STATIC_BLACKHOLE
:
1255 bh_type
= yang_dnode_get_enum(nexthop
, "./bh-type");
1257 case STATIC_BLACKHOLE_DROP
:
1258 vty_out(vty
, " blackhole");
1260 case STATIC_BLACKHOLE_NULL
:
1261 vty_out(vty
, " Null0");
1263 case STATIC_BLACKHOLE_REJECT
:
1264 vty_out(vty
, " reject");
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
);
1276 distance
= yang_dnode_get_uint8(path
, "./distance");
1277 if (distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
|| show_defaults
)
1278 vty_out(vty
, " %" PRIu8
, distance
);
1282 yang_dnode_iterate(mpls_label_iter_cb
, &iter
, nexthop
,
1283 "./mpls-label-stack/entry");
1285 nexthop_vrf
= yang_dnode_get_string(nexthop
, "./vrf");
1286 if (strcmp(vrf
, nexthop_vrf
))
1287 vty_out(vty
, " nexthop-vrf %s", nexthop_vrf
);
1289 table_id
= yang_dnode_get_uint32(path
, "./table-id");
1290 if (table_id
|| show_defaults
)
1291 vty_out(vty
, " table %" PRIu32
, table_id
);
1293 if (yang_dnode_exists(nexthop
, "./onlink")) {
1294 onlink
= yang_dnode_get_bool(nexthop
, "./onlink");
1296 vty_out(vty
, " onlink");
1299 if (yang_dnode_exists(nexthop
, "./srte-color"))
1300 vty_out(vty
, " color %s",
1301 yang_dnode_get_string(nexthop
, "./srte-color"));
1303 if (yang_dnode_exists(nexthop
, "./bfd-monitoring")) {
1304 const struct lyd_node
*bfd_dnode
=
1305 yang_dnode_get(nexthop
, "./bfd-monitoring");
1307 if (yang_dnode_get_bool(bfd_dnode
, "./multi-hop")) {
1308 vty_out(vty
, " bfd multi-hop");
1310 if (yang_dnode_exists(bfd_dnode
, "./source"))
1311 vty_out(vty
, " source %s",
1312 yang_dnode_get_string(bfd_dnode
,
1315 vty_out(vty
, " bfd");
1317 if (yang_dnode_exists(bfd_dnode
, "./profile"))
1318 vty_out(vty
, " profile %s",
1319 yang_dnode_get_string(bfd_dnode
, "./profile"));
1325 void static_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
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");
1332 nexthop_cli_show(vty
, route
, NULL
, path
, dnode
, show_defaults
);
1335 void static_src_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
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");
1342 nexthop_cli_show(vty
, route
, src
, path
, dnode
, show_defaults
);
1345 int static_nexthop_cli_cmp(const struct lyd_node
*dnode1
,
1346 const struct lyd_node
*dnode2
)
1348 enum static_nh_type nh_type1
, nh_type2
;
1349 struct prefix prefix1
, prefix2
;
1352 nh_type1
= yang_dnode_get_enum(dnode1
, "./nh-type");
1353 nh_type2
= yang_dnode_get_enum(dnode2
, "./nh-type");
1355 if (nh_type1
!= nh_type2
)
1356 return (int)nh_type1
- (int)nh_type2
;
1360 ret
= if_cmp_name_func(
1361 yang_dnode_get_string(dnode1
, "./interface"),
1362 yang_dnode_get_string(dnode2
, "./interface"));
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
);
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
);
1376 ret
= if_cmp_name_func(
1377 yang_dnode_get_string(dnode1
, "./interface"),
1378 yang_dnode_get_string(dnode2
, "./interface"));
1380 case STATIC_BLACKHOLE
:
1381 /* There's only one blackhole nexthop per route */
1389 return if_cmp_name_func(yang_dnode_get_string(dnode1
, "./vrf"),
1390 yang_dnode_get_string(dnode2
, "./vrf"));
1393 int static_route_list_cli_cmp(const struct lyd_node
*dnode1
,
1394 const struct lyd_node
*dnode2
)
1396 const char *afi_safi1
, *afi_safi2
;
1398 safi_t safi1
, safi2
;
1399 struct prefix prefix1
, prefix2
;
1401 afi_safi1
= yang_dnode_get_string(dnode1
, "./afi-safi");
1402 yang_afi_safi_identity2value(afi_safi1
, &afi1
, &safi1
);
1404 afi_safi2
= yang_dnode_get_string(dnode2
, "./afi-safi");
1405 yang_afi_safi_identity2value(afi_safi2
, &afi2
, &safi2
);
1408 return (int)afi1
- (int)afi2
;
1411 return (int)safi1
- (int)safi2
;
1413 yang_dnode_get_prefix(&prefix1
, dnode1
, "./prefix");
1414 yang_dnode_get_prefix(&prefix2
, dnode2
, "./prefix");
1416 return prefix_cmp(&prefix1
, &prefix2
);
1419 int static_src_list_cli_cmp(const struct lyd_node
*dnode1
,
1420 const struct lyd_node
*dnode2
)
1422 struct prefix prefix1
, prefix2
;
1424 yang_dnode_get_prefix(&prefix1
, dnode1
, "./src-prefix");
1425 yang_dnode_get_prefix(&prefix2
, dnode2
, "./src-prefix");
1427 return prefix_cmp(&prefix1
, &prefix2
);
1430 int static_path_list_cli_cmp(const struct lyd_node
*dnode1
,
1431 const struct lyd_node
*dnode2
)
1433 uint32_t table_id1
, table_id2
;
1434 uint8_t distance1
, distance2
;
1436 table_id1
= yang_dnode_get_uint32(dnode1
, "./table-id");
1437 table_id2
= yang_dnode_get_uint32(dnode2
, "./table-id");
1439 if (table_id1
!= table_id2
)
1440 return (int)table_id1
- (int)table_id2
;
1442 distance1
= yang_dnode_get_uint8(dnode1
, "./distance");
1443 distance2
= yang_dnode_get_uint8(dnode2
, "./distance");
1445 return (int)distance1
- (int)distance2
;
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
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);
1459 static_debug_set(vty
->node
, !no
, !!events
, !!route
, !!bfd
);
1464 DEFPY(staticd_show_bfd_routes
, staticd_show_bfd_routes_cmd
,
1465 "show bfd static route [json]$isjson",
1472 static_bfd_show(vty
, !!isjson
);
1476 DEFUN_NOSH (show_debugging_static
,
1477 show_debugging_static_cmd
,
1478 "show debugging [static]",
1481 "Static Information\n")
1483 vty_out(vty
, "Staticd debugging status\n");
1485 static_debug_status_write(vty
);
1487 cmd_show_lib_debugs(vty
);
1492 static struct cmd_node debug_node
= {
1496 .config_write
= static_config_write_debug
,
1499 void static_vty_init(void)
1501 install_node(&debug_node
);
1503 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
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
);
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
);
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
);
1523 install_element(ENABLE_NODE
, &staticd_show_bfd_routes_cmd
);