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
);
373 snprintf(ab_xpath
, sizeof(ab_xpath
),
374 FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH
,
375 "frr-staticd:staticd", "staticd",
376 args
->vrf
, buf_prefix
,
377 yang_afi_safi_value2identity(
378 args
->afi
, args
->safi
),
379 buf_src_prefix
, table_id
, distance
,
380 buf_nh_type
, args
->nexthop_vrf
,
381 buf_gate_str
, args
->interface_name
);
384 ab_xpath
, sizeof(ab_xpath
),
385 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH
,
386 "frr-staticd:staticd", "staticd",
387 args
->vrf
, buf_prefix
,
388 yang_afi_safi_value2identity(
389 args
->afi
, args
->safi
),
390 buf_src_prefix
, table_id
, buf_nh_type
,
391 args
->nexthop_vrf
, buf_gate_str
,
392 args
->interface_name
);
395 snprintf(ab_xpath
, sizeof(ab_xpath
),
396 FRR_DEL_S_ROUTE_NH_KEY_XPATH
,
397 "frr-staticd:staticd", "staticd",
398 args
->vrf
, buf_prefix
,
399 yang_afi_safi_value2identity(
400 args
->afi
, args
->safi
),
401 table_id
, distance
, buf_nh_type
,
402 args
->nexthop_vrf
, buf_gate_str
,
403 args
->interface_name
);
406 ab_xpath
, sizeof(ab_xpath
),
407 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
408 "frr-staticd:staticd", "staticd",
409 args
->vrf
, buf_prefix
,
410 yang_afi_safi_value2identity(
411 args
->afi
, args
->safi
),
412 table_id
, buf_nh_type
,
413 args
->nexthop_vrf
, buf_gate_str
,
414 args
->interface_name
);
417 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
420 "%% Refusing to remove a non-existent route\n");
424 dnode
= yang_get_subtree_with_no_sibling(dnode
);
426 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
428 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
, NULL
);
429 ret
= nb_cli_apply_changes(vty
, "%s", ab_xpath
);
435 /* Static unicast routes for multicast RPF lookup. */
436 DEFPY_YANG (ip_mroute_dist
,
438 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [{"
440 "|bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}]"
444 "Configure static unicast route into MRIB for multicast RPF lookup\n"
445 "IP destination prefix (e.g. 10.0.0.0/8)\n"
447 "Nexthop interface name\n"
450 BFD_INTEGRATION_MULTI_HOP_STR
451 BFD_INTEGRATION_SOURCE_STR
452 BFD_INTEGRATION_SOURCEV4_STR
454 BFD_PROFILE_NAME_STR
)
456 struct static_route_args args
= {
459 .safi
= SAFI_MULTICAST
,
460 .prefix
= prefix_str
,
462 .interface_name
= ifname
,
463 .distance
= distance_str
,
465 .bfd_multi_hop
= !!bfd_multi_hop
,
466 .bfd_source
= bfd_source_str
,
467 .bfd_profile
= bfd_profile
,
470 return static_route_nb_run(vty
, &args
);
473 /* Static route configuration. */
474 DEFPY_YANG(ip_route_blackhole
,
475 ip_route_blackhole_cmd
,
477 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
478 <reject|blackhole>$flag \
484 |table (1-4294967295) \
487 "Establish static routes\n"
488 "IP destination prefix (e.g. 10.0.0.0/8)\n"
489 "IP destination prefix\n"
490 "IP destination prefix mask\n"
491 "Emit an ICMP unreachable when matched\n"
492 "Silently discard pkts when matched\n"
493 "Set tag for this route\n"
495 "Distance value for this route\n"
498 "Table to configure\n"
499 "The table number to configure\n")
501 struct static_route_args args
= {
504 .safi
= SAFI_UNICAST
,
506 .prefix_mask
= mask_str
,
509 .distance
= distance_str
,
515 return static_route_nb_run(vty
, &args
);
518 DEFPY_YANG(ip_route_blackhole_vrf
,
519 ip_route_blackhole_vrf_cmd
,
521 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
522 <reject|blackhole>$flag \
527 |table (1-4294967295) \
530 "Establish static routes\n"
531 "IP destination prefix (e.g. 10.0.0.0/8)\n"
532 "IP destination prefix\n"
533 "IP destination prefix mask\n"
534 "Emit an ICMP unreachable when matched\n"
535 "Silently discard pkts when matched\n"
536 "Set tag for this route\n"
538 "Distance value for this route\n"
540 "Table to configure\n"
541 "The table number to configure\n")
543 struct static_route_args args
= {
546 .safi
= SAFI_UNICAST
,
548 .prefix_mask
= mask_str
,
551 .distance
= distance_str
,
558 * Coverity is complaining that prefix could
559 * be dereferenced, but we know that prefix will
560 * valid. Add an assert to make it happy
564 return static_route_nb_run(vty
, &args
);
567 DEFPY_YANG(ip_route_address_interface
,
568 ip_route_address_interface_cmd
,
570 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
572 <INTERFACE|Null0>$ifname \
578 |table (1-4294967295) \
581 |color (1-4294967295) \
582 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
585 "Establish static routes\n"
586 "IP destination prefix (e.g. 10.0.0.0/8)\n"
587 "IP destination prefix\n"
588 "IP destination prefix mask\n"
589 "IP gateway address\n"
590 "IP gateway interface name\n"
592 "Set tag for this route\n"
594 "Distance value for this route\n"
597 "Table to configure\n"
598 "The table number to configure\n"
600 "Treat the nexthop as directly attached to the interface\n"
602 "The SR-TE color to configure\n"
604 BFD_INTEGRATION_MULTI_HOP_STR
605 BFD_INTEGRATION_SOURCE_STR
606 BFD_INTEGRATION_SOURCEV4_STR
608 BFD_PROFILE_NAME_STR
)
610 struct static_route_args args
= {
613 .safi
= SAFI_UNICAST
,
615 .prefix_mask
= mask_str
,
617 .interface_name
= ifname
,
619 .distance
= distance_str
,
625 .nexthop_vrf
= nexthop_vrf
,
627 .bfd_multi_hop
= !!bfd_multi_hop
,
628 .bfd_source
= bfd_source_str
,
629 .bfd_profile
= bfd_profile
,
632 return static_route_nb_run(vty
, &args
);
635 DEFPY_YANG(ip_route_address_interface_vrf
,
636 ip_route_address_interface_vrf_cmd
,
638 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
640 <INTERFACE|Null0>$ifname \
645 |table (1-4294967295) \
648 |color (1-4294967295) \
649 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
652 "Establish static routes\n"
653 "IP destination prefix (e.g. 10.0.0.0/8)\n"
654 "IP destination prefix\n"
655 "IP destination prefix mask\n"
656 "IP gateway address\n"
657 "IP gateway interface name\n"
659 "Set tag for this route\n"
661 "Distance value for this route\n"
663 "Table to configure\n"
664 "The table number to configure\n"
666 "Treat the nexthop as directly attached to the interface\n"
668 "The SR-TE color to configure\n"
670 BFD_INTEGRATION_MULTI_HOP_STR
671 BFD_INTEGRATION_SOURCE_STR
672 BFD_INTEGRATION_SOURCEV4_STR
674 BFD_PROFILE_NAME_STR
)
676 struct static_route_args args
= {
679 .safi
= SAFI_UNICAST
,
681 .prefix_mask
= mask_str
,
683 .interface_name
= ifname
,
685 .distance
= distance_str
,
691 .nexthop_vrf
= nexthop_vrf
,
693 .bfd_multi_hop
= !!bfd_multi_hop
,
694 .bfd_source
= bfd_source_str
,
695 .bfd_profile
= bfd_profile
,
698 return static_route_nb_run(vty
, &args
);
704 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
705 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
711 |table (1-4294967295) \
713 |color (1-4294967295) \
714 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
717 "Establish static routes\n"
718 "IP destination prefix (e.g. 10.0.0.0/8)\n"
719 "IP destination prefix\n"
720 "IP destination prefix mask\n"
721 "IP gateway address\n"
722 "IP gateway interface name\n"
724 "Set tag for this route\n"
726 "Distance value for this route\n"
729 "Table to configure\n"
730 "The table number to configure\n"
733 "The SR-TE color to configure\n"
735 BFD_INTEGRATION_MULTI_HOP_STR
736 BFD_INTEGRATION_SOURCE_STR
737 BFD_INTEGRATION_SOURCEV4_STR
739 BFD_PROFILE_NAME_STR
)
741 struct static_route_args args
= {
744 .safi
= SAFI_UNICAST
,
746 .prefix_mask
= mask_str
,
748 .interface_name
= ifname
,
750 .distance
= distance_str
,
755 .nexthop_vrf
= nexthop_vrf
,
757 .bfd_multi_hop
= !!bfd_multi_hop
,
758 .bfd_source
= bfd_source_str
,
759 .bfd_profile
= bfd_profile
,
762 return static_route_nb_run(vty
, &args
);
765 DEFPY_YANG(ip_route_vrf
,
768 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
769 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
774 |table (1-4294967295) \
776 |color (1-4294967295) \
777 |bfd$bfd [{multi-hop$bfd_multi_hop|source A.B.C.D$bfd_source|profile BFDPROF$bfd_profile}] \
780 "Establish static routes\n"
781 "IP destination prefix (e.g. 10.0.0.0/8)\n"
782 "IP destination prefix\n"
783 "IP destination prefix mask\n"
784 "IP gateway address\n"
785 "IP gateway interface name\n"
787 "Set tag for this route\n"
789 "Distance value for this route\n"
791 "Table to configure\n"
792 "The table number to configure\n"
795 "The SR-TE color to configure\n"
797 BFD_INTEGRATION_MULTI_HOP_STR
798 BFD_INTEGRATION_SOURCE_STR
799 BFD_INTEGRATION_SOURCEV4_STR
801 BFD_PROFILE_NAME_STR
)
803 struct static_route_args args
= {
806 .safi
= SAFI_UNICAST
,
808 .prefix_mask
= mask_str
,
810 .interface_name
= ifname
,
812 .distance
= distance_str
,
817 .nexthop_vrf
= nexthop_vrf
,
819 .bfd_multi_hop
= !!bfd_multi_hop
,
820 .bfd_source
= bfd_source_str
,
821 .bfd_profile
= bfd_profile
,
824 return static_route_nb_run(vty
, &args
);
827 DEFPY_YANG(ipv6_route_blackhole
,
828 ipv6_route_blackhole_cmd
,
829 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
830 <reject|blackhole>$flag \
836 |table (1-4294967295) \
840 "Establish static routes\n"
841 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
842 "IPv6 source-dest route\n"
843 "IPv6 source prefix\n"
844 "Emit an ICMP unreachable when matched\n"
845 "Silently discard pkts when matched\n"
846 "Set tag for this route\n"
848 "Distance value for this prefix\n"
851 "Table to configure\n"
852 "The table number to configure\n")
854 struct static_route_args args
= {
857 .safi
= SAFI_UNICAST
,
858 .prefix
= prefix_str
,
862 .distance
= distance_str
,
868 return static_route_nb_run(vty
, &args
);
871 DEFPY_YANG(ipv6_route_blackhole_vrf
,
872 ipv6_route_blackhole_vrf_cmd
,
873 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
874 <reject|blackhole>$flag \
879 |table (1-4294967295) \
883 "Establish static routes\n"
884 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
885 "IPv6 source-dest route\n"
886 "IPv6 source prefix\n"
887 "Emit an ICMP unreachable when matched\n"
888 "Silently discard pkts when matched\n"
889 "Set tag for this route\n"
891 "Distance value for this prefix\n"
893 "Table to configure\n"
894 "The table number to configure\n")
896 struct static_route_args args
= {
899 .safi
= SAFI_UNICAST
,
900 .prefix
= prefix_str
,
904 .distance
= distance_str
,
911 * Coverity is complaining that prefix could
912 * be dereferenced, but we know that prefix will
913 * valid. Add an assert to make it happy
917 return static_route_nb_run(vty
, &args
);
920 DEFPY_YANG(ipv6_route_address_interface
,
921 ipv6_route_address_interface_cmd
,
922 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
924 <INTERFACE|Null0>$ifname \
930 |table (1-4294967295) \
933 |color (1-4294967295) \
934 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
938 "Establish static routes\n"
939 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
940 "IPv6 source-dest route\n"
941 "IPv6 source prefix\n"
942 "IPv6 gateway address\n"
943 "IPv6 gateway interface name\n"
945 "Set tag for this route\n"
947 "Distance value for this prefix\n"
950 "Table to configure\n"
951 "The table number to configure\n"
953 "Treat the nexthop as directly attached to the interface\n"
955 "The SR-TE color to configure\n"
957 BFD_INTEGRATION_MULTI_HOP_STR
958 BFD_INTEGRATION_SOURCE_STR
959 BFD_INTEGRATION_SOURCEV4_STR
961 BFD_PROFILE_NAME_STR
)
963 struct static_route_args args
= {
966 .safi
= SAFI_UNICAST
,
967 .prefix
= prefix_str
,
970 .interface_name
= ifname
,
972 .distance
= distance_str
,
978 .nexthop_vrf
= nexthop_vrf
,
980 .bfd_multi_hop
= !!bfd_multi_hop
,
981 .bfd_source
= bfd_source_str
,
982 .bfd_profile
= bfd_profile
,
985 return static_route_nb_run(vty
, &args
);
988 DEFPY_YANG(ipv6_route_address_interface_vrf
,
989 ipv6_route_address_interface_vrf_cmd
,
990 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
992 <INTERFACE|Null0>$ifname \
997 |table (1-4294967295) \
1000 |color (1-4294967295) \
1001 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1005 "Establish static routes\n"
1006 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1007 "IPv6 source-dest route\n"
1008 "IPv6 source prefix\n"
1009 "IPv6 gateway address\n"
1010 "IPv6 gateway interface name\n"
1012 "Set tag for this route\n"
1014 "Distance value for this prefix\n"
1016 "Table to configure\n"
1017 "The table number to configure\n"
1019 "Treat the nexthop as directly attached to the interface\n"
1021 "The SR-TE color to configure\n"
1023 BFD_INTEGRATION_MULTI_HOP_STR
1024 BFD_INTEGRATION_SOURCE_STR
1025 BFD_INTEGRATION_SOURCEV4_STR
1027 BFD_PROFILE_NAME_STR
)
1029 struct static_route_args args
= {
1032 .safi
= SAFI_UNICAST
,
1033 .prefix
= prefix_str
,
1035 .gateway
= gate_str
,
1036 .interface_name
= ifname
,
1038 .distance
= distance_str
,
1044 .nexthop_vrf
= nexthop_vrf
,
1046 .bfd_multi_hop
= !!bfd_multi_hop
,
1047 .bfd_source
= bfd_source_str
,
1048 .bfd_profile
= bfd_profile
,
1051 return static_route_nb_run(vty
, &args
);
1054 DEFPY_YANG(ipv6_route
,
1056 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1057 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1059 tag (1-4294967295) \
1063 |table (1-4294967295) \
1065 |color (1-4294967295) \
1066 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1070 "Establish static routes\n"
1071 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1072 "IPv6 source-dest route\n"
1073 "IPv6 source prefix\n"
1074 "IPv6 gateway address\n"
1075 "IPv6 gateway interface name\n"
1077 "Set tag for this route\n"
1079 "Distance value for this prefix\n"
1082 "Table to configure\n"
1083 "The table number to configure\n"
1086 "The SR-TE color to configure\n"
1088 BFD_INTEGRATION_MULTI_HOP_STR
1089 BFD_INTEGRATION_SOURCE_STR
1090 BFD_INTEGRATION_SOURCEV4_STR
1092 BFD_PROFILE_NAME_STR
)
1094 struct static_route_args args
= {
1097 .safi
= SAFI_UNICAST
,
1098 .prefix
= prefix_str
,
1100 .gateway
= gate_str
,
1101 .interface_name
= ifname
,
1103 .distance
= distance_str
,
1108 .nexthop_vrf
= nexthop_vrf
,
1110 .bfd_multi_hop
= !!bfd_multi_hop
,
1111 .bfd_source
= bfd_source_str
,
1112 .bfd_profile
= bfd_profile
,
1115 return static_route_nb_run(vty
, &args
);
1118 DEFPY_YANG(ipv6_route_vrf
,
1120 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1121 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1123 tag (1-4294967295) \
1126 |table (1-4294967295) \
1128 |color (1-4294967295) \
1129 |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \
1133 "Establish static routes\n"
1134 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1135 "IPv6 source-dest route\n"
1136 "IPv6 source prefix\n"
1137 "IPv6 gateway address\n"
1138 "IPv6 gateway interface name\n"
1140 "Set tag for this route\n"
1142 "Distance value for this prefix\n"
1144 "Table to configure\n"
1145 "The table number to configure\n"
1148 "The SR-TE color to configure\n"
1150 BFD_INTEGRATION_MULTI_HOP_STR
1151 BFD_INTEGRATION_SOURCE_STR
1152 BFD_INTEGRATION_SOURCEV4_STR
1154 BFD_PROFILE_NAME_STR
)
1156 struct static_route_args args
= {
1159 .safi
= SAFI_UNICAST
,
1160 .prefix
= prefix_str
,
1162 .gateway
= gate_str
,
1163 .interface_name
= ifname
,
1165 .distance
= distance_str
,
1170 .nexthop_vrf
= nexthop_vrf
,
1172 .bfd_multi_hop
= !!bfd_multi_hop
,
1173 .bfd_source
= bfd_source_str
,
1174 .bfd_profile
= bfd_profile
,
1177 return static_route_nb_run(vty
, &args
);
1180 void static_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1185 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1186 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1187 vty_out(vty
, "vrf %s\n", vrf
);
1190 void static_cli_show_end(struct vty
*vty
, const struct lyd_node
*dnode
)
1194 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1195 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1196 vty_out(vty
, "exit-vrf\n");
1199 struct mpls_label_iter
{
1204 static int mpls_label_iter_cb(const struct lyd_node
*dnode
, void *arg
)
1206 struct mpls_label_iter
*iter
= arg
;
1208 if (yang_dnode_exists(dnode
, "./label")) {
1210 vty_out(iter
->vty
, " label %s",
1211 yang_dnode_get_string(dnode
, "./label"));
1213 vty_out(iter
->vty
, "/%s",
1214 yang_dnode_get_string(dnode
, "./label"));
1215 iter
->first
= false;
1218 return YANG_ITER_CONTINUE
;
1221 static void nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*route
,
1222 const struct lyd_node
*src
,
1223 const struct lyd_node
*path
,
1224 const struct lyd_node
*nexthop
, bool show_defaults
)
1227 const char *afi_safi
;
1230 enum static_nh_type nh_type
;
1231 enum static_blackhole_type bh_type
;
1234 struct mpls_label_iter iter
;
1235 const char *nexthop_vrf
;
1239 vrf
= yang_dnode_get_string(route
, "../../vrf");
1241 afi_safi
= yang_dnode_get_string(route
, "./afi-safi");
1242 yang_afi_safi_identity2value(afi_safi
, &afi
, &safi
);
1245 vty_out(vty
, "%sip",
1246 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1248 vty_out(vty
, "%sipv6",
1249 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1251 if (safi
== SAFI_UNICAST
)
1252 vty_out(vty
, " route");
1254 vty_out(vty
, " mroute");
1256 vty_out(vty
, " %s", yang_dnode_get_string(route
, "./prefix"));
1259 vty_out(vty
, " from %s",
1260 yang_dnode_get_string(src
, "./src-prefix"));
1262 nh_type
= yang_dnode_get_enum(nexthop
, "./nh-type");
1266 yang_dnode_get_string(nexthop
, "./interface"));
1268 case STATIC_IPV4_GATEWAY
:
1269 case STATIC_IPV6_GATEWAY
:
1271 yang_dnode_get_string(nexthop
, "./gateway"));
1273 case STATIC_IPV4_GATEWAY_IFNAME
:
1274 case STATIC_IPV6_GATEWAY_IFNAME
:
1276 yang_dnode_get_string(nexthop
, "./gateway"));
1278 yang_dnode_get_string(nexthop
, "./interface"));
1280 case STATIC_BLACKHOLE
:
1281 bh_type
= yang_dnode_get_enum(nexthop
, "./bh-type");
1283 case STATIC_BLACKHOLE_DROP
:
1284 vty_out(vty
, " blackhole");
1286 case STATIC_BLACKHOLE_NULL
:
1287 vty_out(vty
, " Null0");
1289 case STATIC_BLACKHOLE_REJECT
:
1290 vty_out(vty
, " reject");
1296 if (yang_dnode_exists(path
, "./tag")) {
1297 tag
= yang_dnode_get_uint32(path
, "./tag");
1298 if (tag
!= 0 || show_defaults
)
1299 vty_out(vty
, " tag %" PRIu32
, tag
);
1302 distance
= yang_dnode_get_uint8(path
, "./distance");
1303 if (distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
|| show_defaults
)
1304 vty_out(vty
, " %" PRIu8
, distance
);
1308 yang_dnode_iterate(mpls_label_iter_cb
, &iter
, nexthop
,
1309 "./mpls-label-stack/entry");
1311 nexthop_vrf
= yang_dnode_get_string(nexthop
, "./vrf");
1312 if (strcmp(vrf
, nexthop_vrf
))
1313 vty_out(vty
, " nexthop-vrf %s", nexthop_vrf
);
1315 table_id
= yang_dnode_get_uint32(path
, "./table-id");
1316 if (table_id
|| show_defaults
)
1317 vty_out(vty
, " table %" PRIu32
, table_id
);
1319 if (yang_dnode_exists(nexthop
, "./onlink")) {
1320 onlink
= yang_dnode_get_bool(nexthop
, "./onlink");
1322 vty_out(vty
, " onlink");
1325 if (yang_dnode_exists(nexthop
, "./srte-color"))
1326 vty_out(vty
, " color %s",
1327 yang_dnode_get_string(nexthop
, "./srte-color"));
1329 if (yang_dnode_exists(nexthop
, "./bfd-monitoring")) {
1330 const struct lyd_node
*bfd_dnode
=
1331 yang_dnode_get(nexthop
, "./bfd-monitoring");
1333 if (yang_dnode_get_bool(bfd_dnode
, "./multi-hop")) {
1334 vty_out(vty
, " bfd multi-hop");
1336 if (yang_dnode_exists(bfd_dnode
, "./source"))
1337 vty_out(vty
, " source %s",
1338 yang_dnode_get_string(bfd_dnode
,
1341 vty_out(vty
, " bfd");
1343 if (yang_dnode_exists(bfd_dnode
, "./profile"))
1344 vty_out(vty
, " profile %s",
1345 yang_dnode_get_string(bfd_dnode
, "./profile"));
1351 void static_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1354 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1355 const struct lyd_node
*route
=
1356 yang_dnode_get_parent(path
, "route-list");
1358 nexthop_cli_show(vty
, route
, NULL
, path
, dnode
, show_defaults
);
1361 void static_src_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1364 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1365 const struct lyd_node
*src
= yang_dnode_get_parent(path
, "src-list");
1366 const struct lyd_node
*route
= yang_dnode_get_parent(src
, "route-list");
1368 nexthop_cli_show(vty
, route
, src
, path
, dnode
, show_defaults
);
1371 int static_nexthop_cli_cmp(const struct lyd_node
*dnode1
,
1372 const struct lyd_node
*dnode2
)
1374 enum static_nh_type nh_type1
, nh_type2
;
1375 struct prefix prefix1
, prefix2
;
1378 nh_type1
= yang_dnode_get_enum(dnode1
, "./nh-type");
1379 nh_type2
= yang_dnode_get_enum(dnode2
, "./nh-type");
1381 if (nh_type1
!= nh_type2
)
1382 return (int)nh_type1
- (int)nh_type2
;
1386 ret
= if_cmp_name_func(
1387 yang_dnode_get_string(dnode1
, "./interface"),
1388 yang_dnode_get_string(dnode2
, "./interface"));
1390 case STATIC_IPV4_GATEWAY
:
1391 case STATIC_IPV6_GATEWAY
:
1392 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1393 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1394 ret
= prefix_cmp(&prefix1
, &prefix2
);
1396 case STATIC_IPV4_GATEWAY_IFNAME
:
1397 case STATIC_IPV6_GATEWAY_IFNAME
:
1398 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1399 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1400 ret
= prefix_cmp(&prefix1
, &prefix2
);
1402 ret
= if_cmp_name_func(
1403 yang_dnode_get_string(dnode1
, "./interface"),
1404 yang_dnode_get_string(dnode2
, "./interface"));
1406 case STATIC_BLACKHOLE
:
1407 /* There's only one blackhole nexthop per route */
1415 return if_cmp_name_func(yang_dnode_get_string(dnode1
, "./vrf"),
1416 yang_dnode_get_string(dnode2
, "./vrf"));
1419 int static_route_list_cli_cmp(const struct lyd_node
*dnode1
,
1420 const struct lyd_node
*dnode2
)
1422 const char *afi_safi1
, *afi_safi2
;
1424 safi_t safi1
, safi2
;
1425 struct prefix prefix1
, prefix2
;
1427 afi_safi1
= yang_dnode_get_string(dnode1
, "./afi-safi");
1428 yang_afi_safi_identity2value(afi_safi1
, &afi1
, &safi1
);
1430 afi_safi2
= yang_dnode_get_string(dnode2
, "./afi-safi");
1431 yang_afi_safi_identity2value(afi_safi2
, &afi2
, &safi2
);
1434 return (int)afi1
- (int)afi2
;
1437 return (int)safi1
- (int)safi2
;
1439 yang_dnode_get_prefix(&prefix1
, dnode1
, "./prefix");
1440 yang_dnode_get_prefix(&prefix2
, dnode2
, "./prefix");
1442 return prefix_cmp(&prefix1
, &prefix2
);
1445 int static_src_list_cli_cmp(const struct lyd_node
*dnode1
,
1446 const struct lyd_node
*dnode2
)
1448 struct prefix prefix1
, prefix2
;
1450 yang_dnode_get_prefix(&prefix1
, dnode1
, "./src-prefix");
1451 yang_dnode_get_prefix(&prefix2
, dnode2
, "./src-prefix");
1453 return prefix_cmp(&prefix1
, &prefix2
);
1456 int static_path_list_cli_cmp(const struct lyd_node
*dnode1
,
1457 const struct lyd_node
*dnode2
)
1459 uint32_t table_id1
, table_id2
;
1460 uint8_t distance1
, distance2
;
1462 table_id1
= yang_dnode_get_uint32(dnode1
, "./table-id");
1463 table_id2
= yang_dnode_get_uint32(dnode2
, "./table-id");
1465 if (table_id1
!= table_id2
)
1466 return (int)table_id1
- (int)table_id2
;
1468 distance1
= yang_dnode_get_uint8(dnode1
, "./distance");
1469 distance2
= yang_dnode_get_uint8(dnode2
, "./distance");
1471 return (int)distance1
- (int)distance2
;
1474 DEFPY_YANG(debug_staticd
, debug_staticd_cmd
,
1475 "[no] debug static [{events$events|route$route|bfd$bfd}]",
1476 NO_STR DEBUG_STR STATICD_STR
1481 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1482 /* If no specific category, change all */
1483 if (strmatch(argv
[argc
- 1]->text
, "static"))
1484 static_debug_set(vty
->node
, !no
, true, true, true);
1486 static_debug_set(vty
->node
, !no
, !!events
, !!route
, !!bfd
);
1487 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1492 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1493 DEFPY(staticd_show_bfd_routes
, staticd_show_bfd_routes_cmd
,
1494 "show bfd static route [json]$isjson",
1501 static_bfd_show(vty
, !!isjson
);
1505 DEFUN_NOSH (show_debugging_static
,
1506 show_debugging_static_cmd
,
1507 "show debugging [static]",
1510 "Static Information\n")
1512 vty_out(vty
, "Staticd debugging status\n");
1514 static_debug_status_write(vty
);
1516 cmd_show_lib_debugs(vty
);
1521 static struct cmd_node debug_node
= {
1525 .config_write
= static_config_write_debug
,
1528 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1530 void static_vty_init(void)
1532 #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
1533 install_node(&debug_node
);
1534 install_element(ENABLE_NODE
, &show_debugging_static_cmd
);
1535 install_element(ENABLE_NODE
, &staticd_show_bfd_routes_cmd
);
1536 #endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
1538 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
1540 install_element(CONFIG_NODE
, &ip_route_blackhole_cmd
);
1541 install_element(VRF_NODE
, &ip_route_blackhole_vrf_cmd
);
1542 install_element(CONFIG_NODE
, &ip_route_address_interface_cmd
);
1543 install_element(VRF_NODE
, &ip_route_address_interface_vrf_cmd
);
1544 install_element(CONFIG_NODE
, &ip_route_cmd
);
1545 install_element(VRF_NODE
, &ip_route_vrf_cmd
);
1547 install_element(CONFIG_NODE
, &ipv6_route_blackhole_cmd
);
1548 install_element(VRF_NODE
, &ipv6_route_blackhole_vrf_cmd
);
1549 install_element(CONFIG_NODE
, &ipv6_route_address_interface_cmd
);
1550 install_element(VRF_NODE
, &ipv6_route_address_interface_vrf_cmd
);
1551 install_element(CONFIG_NODE
, &ipv6_route_cmd
);
1552 install_element(VRF_NODE
, &ipv6_route_vrf_cmd
);
1554 install_element(ENABLE_NODE
, &debug_staticd_cmd
);
1555 install_element(CONFIG_NODE
, &debug_staticd_cmd
);