1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Cumulus Networks, Inc.
15 #include "srcdest_table.h"
16 #include "mgmt_be_client.h"
18 #include "northbound.h"
20 #include "routing_nb.h"
21 #include "northbound_cli.h"
23 #include "static_vrf.h"
24 #include "static_vty.h"
25 #include "static_routes.h"
26 #include "static_debug.h"
27 #include "staticd/static_vty_clippy.c"
28 #include "static_nb.h"
30 #define STATICD_STR "Static route daemon\n"
32 /** All possible route parameters available in CLI. */
33 struct static_route_args
{
36 /** Is VRF obtained from XPath? */
44 const char *nexthop_vrf
;
46 const char *prefix_mask
;
49 const char *interface_name
;
59 const char *bfd_source
;
60 const char *bfd_profile
;
63 static int static_route_nb_run(struct vty
*vty
, struct static_route_args
*args
)
68 enum static_nh_type type
;
70 char xpath_prefix
[XPATH_MAXLEN
];
71 char xpath_nexthop
[XPATH_MAXLEN
];
72 char xpath_mpls
[XPATH_MAXLEN
];
73 char xpath_label
[XPATH_MAXLEN
];
74 char ab_xpath
[XPATH_MAXLEN
];
75 char buf_prefix
[PREFIX_STRLEN
];
76 char buf_src_prefix
[PREFIX_STRLEN
] = {};
77 char buf_nh_type
[PREFIX_STRLEN
] = {};
78 char buf_tag
[PREFIX_STRLEN
];
79 uint8_t label_stack_id
= 0;
80 const char *buf_gate_str
;
81 uint8_t distance
= ZEBRA_STATIC_DISTANCE_DEFAULT
;
83 uint32_t table_id
= 0;
84 const struct lyd_node
*dnode
;
85 const struct lyd_node
*vrf_dnode
;
87 if (args
->xpath_vrf
) {
88 vrf_dnode
= yang_dnode_get(vty
->candidate_config
->dnode
,
90 if (vrf_dnode
== NULL
) {
92 "%% Failed to get vrf dnode in candidate db\n");
93 return CMD_WARNING_CONFIG_FAILED
;
96 args
->vrf
= yang_dnode_get_string(vrf_dnode
, "./name");
98 if (args
->vrf
== NULL
)
99 args
->vrf
= VRF_DEFAULT_NAME
;
101 if (args
->nexthop_vrf
== NULL
)
102 args
->nexthop_vrf
= args
->vrf
;
104 if (args
->interface_name
&&
105 !strcasecmp(args
->interface_name
, "Null0")) {
106 args
->flag
= "Null0";
107 args
->interface_name
= NULL
;
110 assert(!!str2prefix(args
->prefix
, &p
));
114 /* Cisco like mask notation. */
115 if (args
->prefix_mask
) {
116 assert(inet_pton(AF_INET
, args
->prefix_mask
, &mask
) ==
118 p
.prefixlen
= ip_masklen(mask
);
122 /* srcdest routing */
124 assert(!!str2prefix(args
->source
, &src
));
132 /* Apply mask for given prefix. */
134 prefix2str(&p
, buf_prefix
, sizeof(buf_prefix
));
136 if (args
->bfd
&& args
->gateway
== NULL
) {
137 vty_out(vty
, "%% Route monitoring requires a gateway\n");
138 return CMD_WARNING_CONFIG_FAILED
;
142 prefix2str(&src
, buf_src_prefix
, sizeof(buf_src_prefix
));
144 buf_gate_str
= args
->gateway
;
148 if (args
->gateway
== NULL
&& args
->interface_name
== NULL
)
149 type
= STATIC_BLACKHOLE
;
150 else if (args
->gateway
&& args
->interface_name
) {
151 if (args
->afi
== AFI_IP
)
152 type
= STATIC_IPV4_GATEWAY_IFNAME
;
154 type
= STATIC_IPV6_GATEWAY_IFNAME
;
155 } else if (args
->interface_name
)
156 type
= STATIC_IFNAME
;
158 if (args
->afi
== AFI_IP
)
159 type
= STATIC_IPV4_GATEWAY
;
161 type
= STATIC_IPV6_GATEWAY
;
164 /* Administrative distance. */
166 distance
= strtol(args
->distance
, NULL
, 10);
170 tag
= strtoul(args
->tag
, NULL
, 10);
174 table_id
= strtol(args
->table
, NULL
, 10);
176 static_get_nh_type(type
, buf_nh_type
, sizeof(buf_nh_type
));
179 snprintf(ab_xpath
, sizeof(ab_xpath
),
180 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH
,
181 "frr-staticd:staticd", "staticd", args
->vrf
,
183 yang_afi_safi_value2identity(args
->afi
,
185 buf_src_prefix
, table_id
, buf_nh_type
,
186 args
->nexthop_vrf
, buf_gate_str
,
187 args
->interface_name
);
189 snprintf(ab_xpath
, sizeof(ab_xpath
),
190 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
191 "frr-staticd:staticd", "staticd", args
->vrf
,
193 yang_afi_safi_value2identity(args
->afi
,
195 table_id
, buf_nh_type
, args
->nexthop_vrf
,
196 buf_gate_str
, args
->interface_name
);
199 * If there's already the same nexthop but with a different
200 * distance, then remove it for the replacement.
202 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
204 dnode
= yang_get_subtree_with_no_sibling(dnode
);
206 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
208 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
,
212 /* route + path procesing */
214 snprintf(xpath_prefix
, sizeof(xpath_prefix
),
215 FRR_S_ROUTE_SRC_INFO_KEY_XPATH
,
216 "frr-staticd:staticd", "staticd", args
->vrf
,
218 yang_afi_safi_value2identity(args
->afi
,
220 buf_src_prefix
, table_id
, distance
);
222 snprintf(xpath_prefix
, sizeof(xpath_prefix
),
223 FRR_STATIC_ROUTE_INFO_KEY_XPATH
,
224 "frr-staticd:staticd", "staticd", args
->vrf
,
226 yang_afi_safi_value2identity(args
->afi
,
230 nb_cli_enqueue_change(vty
, xpath_prefix
, NB_OP_CREATE
, NULL
);
233 snprintf(buf_tag
, sizeof(buf_tag
), "%u", tag
);
234 strlcpy(ab_xpath
, xpath_prefix
, sizeof(ab_xpath
));
235 strlcat(ab_xpath
, FRR_STATIC_ROUTE_PATH_TAG_XPATH
,
237 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_MODIFY
, buf_tag
);
239 /* nexthop processing */
241 snprintf(ab_xpath
, sizeof(ab_xpath
),
242 FRR_STATIC_ROUTE_NH_KEY_XPATH
, buf_nh_type
,
243 args
->nexthop_vrf
, buf_gate_str
, args
->interface_name
);
244 strlcpy(xpath_nexthop
, xpath_prefix
, sizeof(xpath_nexthop
));
245 strlcat(xpath_nexthop
, ab_xpath
, sizeof(xpath_nexthop
));
246 nb_cli_enqueue_change(vty
, xpath_nexthop
, NB_OP_CREATE
, NULL
);
248 if (type
== STATIC_BLACKHOLE
) {
249 strlcpy(ab_xpath
, xpath_nexthop
, sizeof(ab_xpath
));
250 strlcat(ab_xpath
, FRR_STATIC_ROUTE_NH_BH_XPATH
,
255 switch (args
->flag
[0]) {
269 nb_cli_enqueue_change(vty
, ab_xpath
,
270 NB_OP_MODIFY
, bh_type
);
272 nb_cli_enqueue_change(vty
, ab_xpath
,
273 NB_OP_MODIFY
, "null");
276 if (type
== STATIC_IPV4_GATEWAY_IFNAME
277 || type
== STATIC_IPV6_GATEWAY_IFNAME
) {
278 strlcpy(ab_xpath
, xpath_nexthop
, sizeof(ab_xpath
));
279 strlcat(ab_xpath
, FRR_STATIC_ROUTE_NH_ONLINK_XPATH
,
283 nb_cli_enqueue_change(vty
, ab_xpath
,
284 NB_OP_MODIFY
, "true");
286 nb_cli_enqueue_change(vty
, ab_xpath
,
287 NB_OP_MODIFY
, "false");
289 if (type
== STATIC_IPV4_GATEWAY
||
290 type
== STATIC_IPV6_GATEWAY
||
291 type
== STATIC_IPV4_GATEWAY_IFNAME
||
292 type
== STATIC_IPV6_GATEWAY_IFNAME
) {
293 strlcpy(ab_xpath
, xpath_nexthop
, sizeof(ab_xpath
));
294 strlcat(ab_xpath
, FRR_STATIC_ROUTE_NH_COLOR_XPATH
,
297 nb_cli_enqueue_change(vty
, ab_xpath
,
302 /* copy of label string (start) */
304 /* pointer to next segment */
307 strlcpy(xpath_mpls
, xpath_nexthop
, sizeof(xpath_mpls
));
308 strlcat(xpath_mpls
, FRR_STATIC_ROUTE_NH_LABEL_XPATH
,
311 nb_cli_enqueue_change(vty
, xpath_mpls
, NB_OP_DESTROY
,
314 ostr
= XSTRDUP(MTYPE_TMP
, args
->label
);
315 while ((nump
= strsep(&ostr
, "/")) != NULL
) {
316 snprintf(ab_xpath
, sizeof(ab_xpath
),
317 FRR_STATIC_ROUTE_NHLB_KEY_XPATH
,
319 strlcpy(xpath_label
, xpath_mpls
,
320 sizeof(xpath_label
));
321 strlcat(xpath_label
, ab_xpath
,
322 sizeof(xpath_label
));
323 nb_cli_enqueue_change(vty
, xpath_label
,
327 XFREE(MTYPE_TMP
, ostr
);
329 strlcpy(xpath_mpls
, xpath_nexthop
, sizeof(xpath_mpls
));
330 strlcat(xpath_mpls
, FRR_STATIC_ROUTE_NH_LABEL_XPATH
,
332 nb_cli_enqueue_change(vty
, xpath_mpls
, NB_OP_DESTROY
,
337 char xpath_bfd
[XPATH_MAXLEN
];
339 if (args
->bfd_source
) {
340 strlcpy(xpath_bfd
, xpath_nexthop
,
343 "/frr-staticd:bfd-monitoring/source",
345 nb_cli_enqueue_change(vty
, xpath_bfd
,
350 strlcpy(xpath_bfd
, xpath_nexthop
, sizeof(xpath_bfd
));
352 "/frr-staticd:bfd-monitoring/multi-hop",
354 nb_cli_enqueue_change(vty
, xpath_bfd
, NB_OP_MODIFY
,
355 args
->bfd_multi_hop
? "true"
358 if (args
->bfd_profile
) {
359 strlcpy(xpath_bfd
, xpath_nexthop
,
362 "/frr-staticd:bfd-monitoring/profile",
364 nb_cli_enqueue_change(vty
, xpath_bfd
,
370 ret
= nb_cli_apply_changes(vty
, "%s", xpath_prefix
);
374 snprintf(ab_xpath
, sizeof(ab_xpath
),
375 FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH
,
376 "frr-staticd:staticd", "staticd",
377 args
->vrf
, buf_prefix
,
378 yang_afi_safi_value2identity(
379 args
->afi
, args
->safi
),
380 buf_src_prefix
, table_id
, distance
,
381 buf_nh_type
, args
->nexthop_vrf
,
382 buf_gate_str
, args
->interface_name
);
385 ab_xpath
, sizeof(ab_xpath
),
386 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH
,
387 "frr-staticd:staticd", "staticd",
388 args
->vrf
, buf_prefix
,
389 yang_afi_safi_value2identity(
390 args
->afi
, args
->safi
),
391 buf_src_prefix
, table_id
, buf_nh_type
,
392 args
->nexthop_vrf
, buf_gate_str
,
393 args
->interface_name
);
396 snprintf(ab_xpath
, sizeof(ab_xpath
),
397 FRR_DEL_S_ROUTE_NH_KEY_XPATH
,
398 "frr-staticd:staticd", "staticd",
399 args
->vrf
, buf_prefix
,
400 yang_afi_safi_value2identity(
401 args
->afi
, args
->safi
),
402 table_id
, distance
, buf_nh_type
,
403 args
->nexthop_vrf
, buf_gate_str
,
404 args
->interface_name
);
407 ab_xpath
, sizeof(ab_xpath
),
408 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
409 "frr-staticd:staticd", "staticd",
410 args
->vrf
, buf_prefix
,
411 yang_afi_safi_value2identity(
412 args
->afi
, args
->safi
),
413 table_id
, buf_nh_type
,
414 args
->nexthop_vrf
, buf_gate_str
,
415 args
->interface_name
);
418 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
421 "%% Refusing to remove a non-existent route\n");
425 dnode
= yang_get_subtree_with_no_sibling(dnode
);
427 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
429 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
, NULL
);
430 ret
= nb_cli_apply_changes(vty
, "%s", ab_xpath
);
436 /* Static unicast routes for multicast RPF lookup. */
437 DEFPY_YANG (ip_mroute_dist
,
439 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [{"
441 "|bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}]"
445 "Configure static unicast route into MRIB for multicast RPF lookup\n"
446 "IP destination prefix (e.g. 10.0.0.0/8)\n"
448 "Nexthop interface name\n"
451 BFD_INTEGRATION_MULTI_HOP_STR
452 BFD_INTEGRATION_SOURCE_STR
453 BFD_INTEGRATION_SOURCEV4_STR
455 BFD_PROFILE_NAME_STR
)
457 struct static_route_args args
= {
460 .safi
= SAFI_MULTICAST
,
461 .prefix
= prefix_str
,
463 .interface_name
= ifname
,
464 .distance
= distance_str
,
466 .bfd_multi_hop
= !!bfd_multi_hop
,
467 .bfd_source
= bfd_source_str
,
468 .bfd_profile
= bfd_profile
,
471 return static_route_nb_run(vty
, &args
);
474 /* Static route configuration. */
475 DEFPY_YANG(ip_route_blackhole
,
476 ip_route_blackhole_cmd
,
478 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
479 <reject|blackhole>$flag \
485 |table (1-4294967295) \
488 "Establish static routes\n"
489 "IP destination prefix (e.g. 10.0.0.0/8)\n"
490 "IP destination prefix\n"
491 "IP destination prefix mask\n"
492 "Emit an ICMP unreachable when matched\n"
493 "Silently discard pkts when matched\n"
494 "Set tag for this route\n"
496 "Distance value for this route\n"
499 "Table to configure\n"
500 "The table number to configure\n")
502 struct static_route_args args
= {
505 .safi
= SAFI_UNICAST
,
507 .prefix_mask
= mask_str
,
510 .distance
= distance_str
,
516 return static_route_nb_run(vty
, &args
);
519 DEFPY_YANG(ip_route_blackhole_vrf
,
520 ip_route_blackhole_vrf_cmd
,
522 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
523 <reject|blackhole>$flag \
528 |table (1-4294967295) \
531 "Establish static routes\n"
532 "IP destination prefix (e.g. 10.0.0.0/8)\n"
533 "IP destination prefix\n"
534 "IP destination prefix mask\n"
535 "Emit an ICMP unreachable when matched\n"
536 "Silently discard pkts when matched\n"
537 "Set tag for this route\n"
539 "Distance value for this route\n"
541 "Table to configure\n"
542 "The table number to configure\n")
544 struct static_route_args args
= {
547 .safi
= SAFI_UNICAST
,
549 .prefix_mask
= mask_str
,
552 .distance
= distance_str
,
559 * Coverity is complaining that prefix could
560 * be dereferenced, but we know that prefix will
561 * valid. Add an assert to make it happy
565 return static_route_nb_run(vty
, &args
);
568 DEFPY_YANG(ip_route_address_interface
,
569 ip_route_address_interface_cmd
,
571 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
573 <INTERFACE|Null0>$ifname \
579 |table (1-4294967295) \
582 |color (1-4294967295) \
583 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
586 "Establish static routes\n"
587 "IP destination prefix (e.g. 10.0.0.0/8)\n"
588 "IP destination prefix\n"
589 "IP destination prefix mask\n"
590 "IP gateway address\n"
591 "IP gateway interface name\n"
593 "Set tag for this route\n"
595 "Distance value for this route\n"
598 "Table to configure\n"
599 "The table number to configure\n"
601 "Treat the nexthop as directly attached to the interface\n"
603 "The SR-TE color to configure\n"
605 BFD_INTEGRATION_MULTI_HOP_STR
606 BFD_INTEGRATION_SOURCE_STR
607 BFD_INTEGRATION_SOURCEV4_STR
609 BFD_PROFILE_NAME_STR
)
611 struct static_route_args args
= {
614 .safi
= SAFI_UNICAST
,
616 .prefix_mask
= mask_str
,
618 .interface_name
= ifname
,
620 .distance
= distance_str
,
626 .nexthop_vrf
= nexthop_vrf
,
628 .bfd_multi_hop
= !!bfd_multi_hop
,
629 .bfd_source
= bfd_source_str
,
630 .bfd_profile
= bfd_profile
,
633 return static_route_nb_run(vty
, &args
);
636 DEFPY_YANG(ip_route_address_interface_vrf
,
637 ip_route_address_interface_vrf_cmd
,
639 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
641 <INTERFACE|Null0>$ifname \
646 |table (1-4294967295) \
649 |color (1-4294967295) \
650 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
653 "Establish static routes\n"
654 "IP destination prefix (e.g. 10.0.0.0/8)\n"
655 "IP destination prefix\n"
656 "IP destination prefix mask\n"
657 "IP gateway address\n"
658 "IP gateway interface name\n"
660 "Set tag for this route\n"
662 "Distance value for this route\n"
664 "Table to configure\n"
665 "The table number to configure\n"
667 "Treat the nexthop as directly attached to the interface\n"
669 "The SR-TE color to configure\n"
671 BFD_INTEGRATION_MULTI_HOP_STR
672 BFD_INTEGRATION_SOURCE_STR
673 BFD_INTEGRATION_SOURCEV4_STR
675 BFD_PROFILE_NAME_STR
)
677 struct static_route_args args
= {
680 .safi
= SAFI_UNICAST
,
682 .prefix_mask
= mask_str
,
684 .interface_name
= ifname
,
686 .distance
= distance_str
,
692 .nexthop_vrf
= nexthop_vrf
,
694 .bfd_multi_hop
= !!bfd_multi_hop
,
695 .bfd_source
= bfd_source_str
,
696 .bfd_profile
= bfd_profile
,
699 return static_route_nb_run(vty
, &args
);
705 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
706 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
712 |table (1-4294967295) \
714 |color (1-4294967295) \
715 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
718 "Establish static routes\n"
719 "IP destination prefix (e.g. 10.0.0.0/8)\n"
720 "IP destination prefix\n"
721 "IP destination prefix mask\n"
722 "IP gateway address\n"
723 "IP gateway interface name\n"
725 "Set tag for this route\n"
727 "Distance value for this route\n"
730 "Table to configure\n"
731 "The table number to configure\n"
734 "The SR-TE color to configure\n"
736 BFD_INTEGRATION_MULTI_HOP_STR
737 BFD_INTEGRATION_SOURCE_STR
738 BFD_INTEGRATION_SOURCEV4_STR
740 BFD_PROFILE_NAME_STR
)
742 struct static_route_args args
= {
745 .safi
= SAFI_UNICAST
,
747 .prefix_mask
= mask_str
,
749 .interface_name
= ifname
,
751 .distance
= distance_str
,
756 .nexthop_vrf
= nexthop_vrf
,
758 .bfd_multi_hop
= !!bfd_multi_hop
,
759 .bfd_source
= bfd_source_str
,
760 .bfd_profile
= bfd_profile
,
763 return static_route_nb_run(vty
, &args
);
766 DEFPY_YANG(ip_route_vrf
,
769 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
770 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
775 |table (1-4294967295) \
777 |color (1-4294967295) \
778 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
781 "Establish static routes\n"
782 "IP destination prefix (e.g. 10.0.0.0/8)\n"
783 "IP destination prefix\n"
784 "IP destination prefix mask\n"
785 "IP gateway address\n"
786 "IP gateway interface name\n"
788 "Set tag for this route\n"
790 "Distance value for this route\n"
792 "Table to configure\n"
793 "The table number to configure\n"
796 "The SR-TE color to configure\n"
798 BFD_INTEGRATION_MULTI_HOP_STR
799 BFD_INTEGRATION_SOURCE_STR
800 BFD_INTEGRATION_SOURCEV4_STR
802 BFD_PROFILE_NAME_STR
)
804 struct static_route_args args
= {
807 .safi
= SAFI_UNICAST
,
809 .prefix_mask
= mask_str
,
811 .interface_name
= ifname
,
813 .distance
= distance_str
,
818 .nexthop_vrf
= nexthop_vrf
,
820 .bfd_multi_hop
= !!bfd_multi_hop
,
821 .bfd_source
= bfd_source_str
,
822 .bfd_profile
= bfd_profile
,
825 return static_route_nb_run(vty
, &args
);
828 DEFPY_YANG(ipv6_route_blackhole
,
829 ipv6_route_blackhole_cmd
,
830 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
831 <reject|blackhole>$flag \
837 |table (1-4294967295) \
841 "Establish static routes\n"
842 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
843 "IPv6 source-dest route\n"
844 "IPv6 source prefix\n"
845 "Emit an ICMP unreachable when matched\n"
846 "Silently discard pkts when matched\n"
847 "Set tag for this route\n"
849 "Distance value for this prefix\n"
852 "Table to configure\n"
853 "The table number to configure\n")
855 struct static_route_args args
= {
858 .safi
= SAFI_UNICAST
,
859 .prefix
= prefix_str
,
863 .distance
= distance_str
,
869 return static_route_nb_run(vty
, &args
);
872 DEFPY_YANG(ipv6_route_blackhole_vrf
,
873 ipv6_route_blackhole_vrf_cmd
,
874 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
875 <reject|blackhole>$flag \
880 |table (1-4294967295) \
884 "Establish static routes\n"
885 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
886 "IPv6 source-dest route\n"
887 "IPv6 source prefix\n"
888 "Emit an ICMP unreachable when matched\n"
889 "Silently discard pkts when matched\n"
890 "Set tag for this route\n"
892 "Distance value for this prefix\n"
894 "Table to configure\n"
895 "The table number to configure\n")
897 struct static_route_args args
= {
900 .safi
= SAFI_UNICAST
,
901 .prefix
= prefix_str
,
905 .distance
= distance_str
,
912 * Coverity is complaining that prefix could
913 * be dereferenced, but we know that prefix will
914 * valid. Add an assert to make it happy
918 return static_route_nb_run(vty
, &args
);
921 DEFPY_YANG(ipv6_route_address_interface
,
922 ipv6_route_address_interface_cmd
,
923 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
925 <INTERFACE|Null0>$ifname \
931 |table (1-4294967295) \
934 |color (1-4294967295) \
935 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
939 "Establish static routes\n"
940 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
941 "IPv6 source-dest route\n"
942 "IPv6 source prefix\n"
943 "IPv6 gateway address\n"
944 "IPv6 gateway interface name\n"
946 "Set tag for this route\n"
948 "Distance value for this prefix\n"
951 "Table to configure\n"
952 "The table number to configure\n"
954 "Treat the nexthop as directly attached to the interface\n"
956 "The SR-TE color to configure\n"
958 BFD_INTEGRATION_MULTI_HOP_STR
959 BFD_INTEGRATION_SOURCE_STR
960 BFD_INTEGRATION_SOURCEV4_STR
962 BFD_PROFILE_NAME_STR
)
964 struct static_route_args args
= {
967 .safi
= SAFI_UNICAST
,
968 .prefix
= prefix_str
,
971 .interface_name
= ifname
,
973 .distance
= distance_str
,
979 .nexthop_vrf
= nexthop_vrf
,
981 .bfd_multi_hop
= !!bfd_multi_hop
,
982 .bfd_source
= bfd_source_str
,
983 .bfd_profile
= bfd_profile
,
986 return static_route_nb_run(vty
, &args
);
989 DEFPY_YANG(ipv6_route_address_interface_vrf
,
990 ipv6_route_address_interface_vrf_cmd
,
991 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
993 <INTERFACE|Null0>$ifname \
998 |table (1-4294967295) \
1001 |color (1-4294967295) \
1002 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1006 "Establish static routes\n"
1007 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1008 "IPv6 source-dest route\n"
1009 "IPv6 source prefix\n"
1010 "IPv6 gateway address\n"
1011 "IPv6 gateway interface name\n"
1013 "Set tag for this route\n"
1015 "Distance value for this prefix\n"
1017 "Table to configure\n"
1018 "The table number to configure\n"
1020 "Treat the nexthop as directly attached to the interface\n"
1022 "The SR-TE color to configure\n"
1024 BFD_INTEGRATION_MULTI_HOP_STR
1025 BFD_INTEGRATION_SOURCE_STR
1026 BFD_INTEGRATION_SOURCEV4_STR
1028 BFD_PROFILE_NAME_STR
)
1030 struct static_route_args args
= {
1033 .safi
= SAFI_UNICAST
,
1034 .prefix
= prefix_str
,
1036 .gateway
= gate_str
,
1037 .interface_name
= ifname
,
1039 .distance
= distance_str
,
1045 .nexthop_vrf
= nexthop_vrf
,
1047 .bfd_multi_hop
= !!bfd_multi_hop
,
1048 .bfd_source
= bfd_source_str
,
1049 .bfd_profile
= bfd_profile
,
1052 return static_route_nb_run(vty
, &args
);
1055 DEFPY_YANG(ipv6_route
,
1057 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1058 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1060 tag (1-4294967295) \
1064 |table (1-4294967295) \
1066 |color (1-4294967295) \
1067 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1071 "Establish static routes\n"
1072 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1073 "IPv6 source-dest route\n"
1074 "IPv6 source prefix\n"
1075 "IPv6 gateway address\n"
1076 "IPv6 gateway interface name\n"
1078 "Set tag for this route\n"
1080 "Distance value for this prefix\n"
1083 "Table to configure\n"
1084 "The table number to configure\n"
1087 "The SR-TE color to configure\n"
1089 BFD_INTEGRATION_MULTI_HOP_STR
1090 BFD_INTEGRATION_SOURCE_STR
1091 BFD_INTEGRATION_SOURCEV4_STR
1093 BFD_PROFILE_NAME_STR
)
1095 struct static_route_args args
= {
1098 .safi
= SAFI_UNICAST
,
1099 .prefix
= prefix_str
,
1101 .gateway
= gate_str
,
1102 .interface_name
= ifname
,
1104 .distance
= distance_str
,
1109 .nexthop_vrf
= nexthop_vrf
,
1111 .bfd_multi_hop
= !!bfd_multi_hop
,
1112 .bfd_source
= bfd_source_str
,
1113 .bfd_profile
= bfd_profile
,
1116 return static_route_nb_run(vty
, &args
);
1119 DEFPY_YANG(ipv6_route_vrf
,
1121 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1122 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1124 tag (1-4294967295) \
1127 |table (1-4294967295) \
1129 |color (1-4294967295) \
1130 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1134 "Establish static routes\n"
1135 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1136 "IPv6 source-dest route\n"
1137 "IPv6 source prefix\n"
1138 "IPv6 gateway address\n"
1139 "IPv6 gateway interface name\n"
1141 "Set tag for this route\n"
1143 "Distance value for this prefix\n"
1145 "Table to configure\n"
1146 "The table number to configure\n"
1149 "The SR-TE color to configure\n"
1151 BFD_INTEGRATION_MULTI_HOP_STR
1152 BFD_INTEGRATION_SOURCE_STR
1153 BFD_INTEGRATION_SOURCEV4_STR
1155 BFD_PROFILE_NAME_STR
)
1157 struct static_route_args args
= {
1160 .safi
= SAFI_UNICAST
,
1161 .prefix
= prefix_str
,
1163 .gateway
= gate_str
,
1164 .interface_name
= ifname
,
1166 .distance
= distance_str
,
1171 .nexthop_vrf
= nexthop_vrf
,
1173 .bfd_multi_hop
= !!bfd_multi_hop
,
1174 .bfd_source
= bfd_source_str
,
1175 .bfd_profile
= bfd_profile
,
1178 return static_route_nb_run(vty
, &args
);
1181 void static_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1186 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1187 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1188 vty_out(vty
, "vrf %s\n", vrf
);
1191 void static_cli_show_end(struct vty
*vty
, const struct lyd_node
*dnode
)
1195 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1196 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1197 vty_out(vty
, "exit-vrf\n");
1200 struct mpls_label_iter
{
1205 static int mpls_label_iter_cb(const struct lyd_node
*dnode
, void *arg
)
1207 struct mpls_label_iter
*iter
= arg
;
1209 if (yang_dnode_exists(dnode
, "./label")) {
1211 vty_out(iter
->vty
, " label %s",
1212 yang_dnode_get_string(dnode
, "./label"));
1214 vty_out(iter
->vty
, "/%s",
1215 yang_dnode_get_string(dnode
, "./label"));
1216 iter
->first
= false;
1219 return YANG_ITER_CONTINUE
;
1222 static void nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*route
,
1223 const struct lyd_node
*src
,
1224 const struct lyd_node
*path
,
1225 const struct lyd_node
*nexthop
, bool show_defaults
)
1228 const char *afi_safi
;
1231 enum static_nh_type nh_type
;
1232 enum static_blackhole_type bh_type
;
1235 struct mpls_label_iter iter
;
1236 const char *nexthop_vrf
;
1240 vrf
= yang_dnode_get_string(route
, "../../vrf");
1242 afi_safi
= yang_dnode_get_string(route
, "./afi-safi");
1243 yang_afi_safi_identity2value(afi_safi
, &afi
, &safi
);
1246 vty_out(vty
, "%sip",
1247 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1249 vty_out(vty
, "%sipv6",
1250 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1252 if (safi
== SAFI_UNICAST
)
1253 vty_out(vty
, " route");
1255 vty_out(vty
, " mroute");
1257 vty_out(vty
, " %s", yang_dnode_get_string(route
, "./prefix"));
1260 vty_out(vty
, " from %s",
1261 yang_dnode_get_string(src
, "./src-prefix"));
1263 nh_type
= yang_dnode_get_enum(nexthop
, "./nh-type");
1267 yang_dnode_get_string(nexthop
, "./interface"));
1269 case STATIC_IPV4_GATEWAY
:
1270 case STATIC_IPV6_GATEWAY
:
1272 yang_dnode_get_string(nexthop
, "./gateway"));
1274 case STATIC_IPV4_GATEWAY_IFNAME
:
1275 case STATIC_IPV6_GATEWAY_IFNAME
:
1277 yang_dnode_get_string(nexthop
, "./gateway"));
1279 yang_dnode_get_string(nexthop
, "./interface"));
1281 case STATIC_BLACKHOLE
:
1282 bh_type
= yang_dnode_get_enum(nexthop
, "./bh-type");
1284 case STATIC_BLACKHOLE_DROP
:
1285 vty_out(vty
, " blackhole");
1287 case STATIC_BLACKHOLE_NULL
:
1288 vty_out(vty
, " Null0");
1290 case STATIC_BLACKHOLE_REJECT
:
1291 vty_out(vty
, " reject");
1297 if (yang_dnode_exists(path
, "./tag")) {
1298 tag
= yang_dnode_get_uint32(path
, "./tag");
1299 if (tag
!= 0 || show_defaults
)
1300 vty_out(vty
, " tag %" PRIu32
, tag
);
1303 distance
= yang_dnode_get_uint8(path
, "./distance");
1304 if (distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
|| show_defaults
)
1305 vty_out(vty
, " %" PRIu8
, distance
);
1309 yang_dnode_iterate(mpls_label_iter_cb
, &iter
, nexthop
,
1310 "./mpls-label-stack/entry");
1312 nexthop_vrf
= yang_dnode_get_string(nexthop
, "./vrf");
1313 if (strcmp(vrf
, nexthop_vrf
))
1314 vty_out(vty
, " nexthop-vrf %s", nexthop_vrf
);
1316 table_id
= yang_dnode_get_uint32(path
, "./table-id");
1317 if (table_id
|| show_defaults
)
1318 vty_out(vty
, " table %" PRIu32
, table_id
);
1320 if (yang_dnode_exists(nexthop
, "./onlink")) {
1321 onlink
= yang_dnode_get_bool(nexthop
, "./onlink");
1323 vty_out(vty
, " onlink");
1326 if (yang_dnode_exists(nexthop
, "./srte-color"))
1327 vty_out(vty
, " color %s",
1328 yang_dnode_get_string(nexthop
, "./srte-color"));
1330 if (yang_dnode_exists(nexthop
, "./bfd-monitoring")) {
1331 const struct lyd_node
*bfd_dnode
=
1332 yang_dnode_get(nexthop
, "./bfd-monitoring");
1334 if (yang_dnode_get_bool(bfd_dnode
, "./multi-hop")) {
1335 vty_out(vty
, " bfd multi-hop");
1337 if (yang_dnode_exists(bfd_dnode
, "./source"))
1338 vty_out(vty
, " source %s",
1339 yang_dnode_get_string(bfd_dnode
,
1342 vty_out(vty
, " bfd");
1344 if (yang_dnode_exists(bfd_dnode
, "./profile"))
1345 vty_out(vty
, " profile %s",
1346 yang_dnode_get_string(bfd_dnode
, "./profile"));
1352 void static_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1355 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1356 const struct lyd_node
*route
=
1357 yang_dnode_get_parent(path
, "route-list");
1359 nexthop_cli_show(vty
, route
, NULL
, path
, dnode
, show_defaults
);
1362 void static_src_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1365 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1366 const struct lyd_node
*src
= yang_dnode_get_parent(path
, "src-list");
1367 const struct lyd_node
*route
= yang_dnode_get_parent(src
, "route-list");
1369 nexthop_cli_show(vty
, route
, src
, path
, dnode
, show_defaults
);
1372 int static_nexthop_cli_cmp(const struct lyd_node
*dnode1
,
1373 const struct lyd_node
*dnode2
)
1375 enum static_nh_type nh_type1
, nh_type2
;
1376 struct prefix prefix1
, prefix2
;
1379 nh_type1
= yang_dnode_get_enum(dnode1
, "./nh-type");
1380 nh_type2
= yang_dnode_get_enum(dnode2
, "./nh-type");
1382 if (nh_type1
!= nh_type2
)
1383 return (int)nh_type1
- (int)nh_type2
;
1387 ret
= if_cmp_name_func(
1388 yang_dnode_get_string(dnode1
, "./interface"),
1389 yang_dnode_get_string(dnode2
, "./interface"));
1391 case STATIC_IPV4_GATEWAY
:
1392 case STATIC_IPV6_GATEWAY
:
1393 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1394 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1395 ret
= prefix_cmp(&prefix1
, &prefix2
);
1397 case STATIC_IPV4_GATEWAY_IFNAME
:
1398 case STATIC_IPV6_GATEWAY_IFNAME
:
1399 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1400 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1401 ret
= prefix_cmp(&prefix1
, &prefix2
);
1403 ret
= if_cmp_name_func(
1404 yang_dnode_get_string(dnode1
, "./interface"),
1405 yang_dnode_get_string(dnode2
, "./interface"));
1407 case STATIC_BLACKHOLE
:
1408 /* There's only one blackhole nexthop per route */
1416 return if_cmp_name_func(yang_dnode_get_string(dnode1
, "./vrf"),
1417 yang_dnode_get_string(dnode2
, "./vrf"));
1420 int static_route_list_cli_cmp(const struct lyd_node
*dnode1
,
1421 const struct lyd_node
*dnode2
)
1423 const char *afi_safi1
, *afi_safi2
;
1425 safi_t safi1
, safi2
;
1426 struct prefix prefix1
, prefix2
;
1428 afi_safi1
= yang_dnode_get_string(dnode1
, "./afi-safi");
1429 yang_afi_safi_identity2value(afi_safi1
, &afi1
, &safi1
);
1431 afi_safi2
= yang_dnode_get_string(dnode2
, "./afi-safi");
1432 yang_afi_safi_identity2value(afi_safi2
, &afi2
, &safi2
);
1435 return (int)afi1
- (int)afi2
;
1438 return (int)safi1
- (int)safi2
;
1440 yang_dnode_get_prefix(&prefix1
, dnode1
, "./prefix");
1441 yang_dnode_get_prefix(&prefix2
, dnode2
, "./prefix");
1443 return prefix_cmp(&prefix1
, &prefix2
);
1446 int static_src_list_cli_cmp(const struct lyd_node
*dnode1
,
1447 const struct lyd_node
*dnode2
)
1449 struct prefix prefix1
, prefix2
;
1451 yang_dnode_get_prefix(&prefix1
, dnode1
, "./src-prefix");
1452 yang_dnode_get_prefix(&prefix2
, dnode2
, "./src-prefix");
1454 return prefix_cmp(&prefix1
, &prefix2
);
1457 int static_path_list_cli_cmp(const struct lyd_node
*dnode1
,
1458 const struct lyd_node
*dnode2
)
1460 uint32_t table_id1
, table_id2
;
1461 uint8_t distance1
, distance2
;
1463 table_id1
= yang_dnode_get_uint32(dnode1
, "./table-id");
1464 table_id2
= yang_dnode_get_uint32(dnode2
, "./table-id");
1466 if (table_id1
!= table_id2
)
1467 return (int)table_id1
- (int)table_id2
;
1469 distance1
= yang_dnode_get_uint8(dnode1
, "./distance");
1470 distance2
= yang_dnode_get_uint8(dnode2
, "./distance");
1472 return (int)distance1
- (int)distance2
;
1475 DEFPY_YANG(debug_staticd
, debug_staticd_cmd
,
1476 "[no] debug static [{events$events|route$route|bfd$bfd}]",
1477 NO_STR DEBUG_STR STATICD_STR
1482 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1483 /* If no specific category, change all */
1484 if (strmatch(argv
[argc
- 1]->text
, "static"))
1485 static_debug_set(vty
->node
, !no
, true, true, true);
1487 static_debug_set(vty
->node
, !no
, !!events
, !!route
, !!bfd
);
1488 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1493 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1494 DEFPY(staticd_show_bfd_routes
, staticd_show_bfd_routes_cmd
,
1495 "show bfd static route [json]$isjson",
1502 static_bfd_show(vty
, !!isjson
);
1506 DEFUN_NOSH (show_debugging_static
,
1507 show_debugging_static_cmd
,
1508 "show debugging [static]",
1511 "Static Information\n")
1513 vty_out(vty
, "Staticd debugging status\n");
1515 static_debug_status_write(vty
);
1517 cmd_show_lib_debugs(vty
);
1522 static struct cmd_node debug_node
= {
1526 .config_write
= static_config_write_debug
,
1529 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1531 void static_vty_init(void)
1533 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1534 install_node(&debug_node
);
1535 install_element(ENABLE_NODE
, &show_debugging_static_cmd
);
1536 install_element(ENABLE_NODE
, &staticd_show_bfd_routes_cmd
);
1537 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1539 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
1541 install_element(CONFIG_NODE
, &ip_route_blackhole_cmd
);
1542 install_element(VRF_NODE
, &ip_route_blackhole_vrf_cmd
);
1543 install_element(CONFIG_NODE
, &ip_route_address_interface_cmd
);
1544 install_element(VRF_NODE
, &ip_route_address_interface_vrf_cmd
);
1545 install_element(CONFIG_NODE
, &ip_route_cmd
);
1546 install_element(VRF_NODE
, &ip_route_vrf_cmd
);
1548 install_element(CONFIG_NODE
, &ipv6_route_blackhole_cmd
);
1549 install_element(VRF_NODE
, &ipv6_route_blackhole_vrf_cmd
);
1550 install_element(CONFIG_NODE
, &ipv6_route_address_interface_cmd
);
1551 install_element(VRF_NODE
, &ipv6_route_address_interface_vrf_cmd
);
1552 install_element(CONFIG_NODE
, &ipv6_route_cmd
);
1553 install_element(VRF_NODE
, &ipv6_route_vrf_cmd
);
1555 install_element(ENABLE_NODE
, &debug_staticd_cmd
);
1556 install_element(CONFIG_NODE
, &debug_staticd_cmd
);
1558 mgmt_be_client_lib_vty_init();