3 * Copyright (C) 2018 Cumulus Networks, Inc.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "srcdest_table.h"
30 #include "northbound.h"
32 #include "routing_nb.h"
33 #include "northbound_cli.h"
35 #include "static_vrf.h"
36 #include "static_vty.h"
37 #include "static_routes.h"
38 #include "static_debug.h"
39 #include "staticd/static_vty_clippy.c"
40 #include "static_nb.h"
42 #define STATICD_STR "Static route daemon\n"
44 /** All possible route parameters available in CLI. */
45 struct static_route_args
{
48 /** Is VRF obtained from XPath? */
56 const char *nexthop_vrf
;
58 const char *prefix_mask
;
61 const char *interface_name
;
70 static int static_route_nb_run(struct vty
*vty
, struct static_route_args
*args
)
75 enum static_nh_type type
;
77 char xpath_prefix
[XPATH_MAXLEN
];
78 char xpath_nexthop
[XPATH_MAXLEN
];
79 char xpath_mpls
[XPATH_MAXLEN
];
80 char xpath_label
[XPATH_MAXLEN
];
81 char ab_xpath
[XPATH_MAXLEN
];
82 char buf_prefix
[PREFIX_STRLEN
];
83 char buf_src_prefix
[PREFIX_STRLEN
] = {};
84 char buf_nh_type
[PREFIX_STRLEN
] = {};
85 char buf_tag
[PREFIX_STRLEN
];
86 uint8_t label_stack_id
= 0;
87 const char *buf_gate_str
;
88 uint8_t distance
= ZEBRA_STATIC_DISTANCE_DEFAULT
;
90 uint32_t table_id
= 0;
91 const struct lyd_node
*dnode
;
92 const struct lyd_node
*vrf_dnode
;
94 if (args
->xpath_vrf
) {
95 vrf_dnode
= yang_dnode_get(vty
->candidate_config
->dnode
,
97 if (vrf_dnode
== NULL
) {
99 "%% Failed to get vrf dnode in candidate db\n");
100 return CMD_WARNING_CONFIG_FAILED
;
103 args
->vrf
= yang_dnode_get_string(vrf_dnode
, "./name");
105 if (args
->vrf
== NULL
)
106 args
->vrf
= VRF_DEFAULT_NAME
;
108 if (args
->nexthop_vrf
== NULL
)
109 args
->nexthop_vrf
= args
->vrf
;
111 if (args
->interface_name
&&
112 !strcasecmp(args
->interface_name
, "Null0")) {
113 args
->flag
= "Null0";
114 args
->interface_name
= NULL
;
117 assert(!!str2prefix(args
->prefix
, &p
));
121 /* Cisco like mask notation. */
122 if (args
->prefix_mask
) {
123 assert(inet_pton(AF_INET
, args
->prefix_mask
, &mask
) ==
125 p
.prefixlen
= ip_masklen(mask
);
129 /* srcdest routing */
131 assert(!!str2prefix(args
->source
, &src
));
137 /* Apply mask for given prefix. */
139 prefix2str(&p
, buf_prefix
, sizeof(buf_prefix
));
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
,
335 ret
= nb_cli_apply_changes(vty
, xpath_prefix
);
338 snprintf(ab_xpath
, sizeof(ab_xpath
),
339 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH
,
340 "frr-staticd:staticd", "staticd", args
->vrf
,
342 yang_afi_safi_value2identity(args
->afi
,
344 buf_src_prefix
, table_id
, buf_nh_type
,
345 args
->nexthop_vrf
, buf_gate_str
,
346 args
->interface_name
);
348 snprintf(ab_xpath
, sizeof(ab_xpath
),
349 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH
,
350 "frr-staticd:staticd", "staticd", args
->vrf
,
352 yang_afi_safi_value2identity(args
->afi
,
354 table_id
, buf_nh_type
, args
->nexthop_vrf
,
355 buf_gate_str
, args
->interface_name
);
357 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, ab_xpath
);
360 "%% Refusing to remove a non-existent route\n");
364 dnode
= yang_get_subtree_with_no_sibling(dnode
);
366 yang_dnode_get_path(dnode
, ab_xpath
, XPATH_MAXLEN
);
368 nb_cli_enqueue_change(vty
, ab_xpath
, NB_OP_DESTROY
, NULL
);
369 ret
= nb_cli_apply_changes(vty
, ab_xpath
);
375 /* Static unicast routes for multicast RPF lookup. */
376 DEFPY_YANG (ip_mroute_dist
,
378 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
381 "Configure static unicast route into MRIB for multicast RPF lookup\n"
382 "IP destination prefix (e.g. 10.0.0.0/8)\n"
384 "Nexthop interface name\n"
387 struct static_route_args args
= {
390 .safi
= SAFI_MULTICAST
,
391 .prefix
= prefix_str
,
393 .interface_name
= ifname
,
394 .distance
= distance_str
,
397 return static_route_nb_run(vty
, &args
);
400 /* Static route configuration. */
401 DEFPY_YANG(ip_route_blackhole
,
402 ip_route_blackhole_cmd
,
404 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
405 <reject|blackhole>$flag \
411 |table (1-4294967295) \
414 "Establish static routes\n"
415 "IP destination prefix (e.g. 10.0.0.0/8)\n"
416 "IP destination prefix\n"
417 "IP destination prefix mask\n"
418 "Emit an ICMP unreachable when matched\n"
419 "Silently discard pkts when matched\n"
420 "Set tag for this route\n"
422 "Distance value for this route\n"
425 "Table to configure\n"
426 "The table number to configure\n")
428 struct static_route_args args
= {
431 .safi
= SAFI_UNICAST
,
433 .prefix_mask
= mask_str
,
436 .distance
= distance_str
,
442 return static_route_nb_run(vty
, &args
);
445 DEFPY_YANG(ip_route_blackhole_vrf
,
446 ip_route_blackhole_vrf_cmd
,
448 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
449 <reject|blackhole>$flag \
454 |table (1-4294967295) \
457 "Establish static routes\n"
458 "IP destination prefix (e.g. 10.0.0.0/8)\n"
459 "IP destination prefix\n"
460 "IP destination prefix mask\n"
461 "Emit an ICMP unreachable when matched\n"
462 "Silently discard pkts when matched\n"
463 "Set tag for this route\n"
465 "Distance value for this route\n"
467 "Table to configure\n"
468 "The table number to configure\n")
470 struct static_route_args args
= {
473 .safi
= SAFI_UNICAST
,
475 .prefix_mask
= mask_str
,
478 .distance
= distance_str
,
485 * Coverity is complaining that prefix could
486 * be dereferenced, but we know that prefix will
487 * valid. Add an assert to make it happy
491 return static_route_nb_run(vty
, &args
);
494 DEFPY_YANG(ip_route_address_interface
,
495 ip_route_address_interface_cmd
,
497 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
499 <INTERFACE|Null0>$ifname \
505 |table (1-4294967295) \
508 |color (1-4294967295) \
511 "Establish static routes\n"
512 "IP destination prefix (e.g. 10.0.0.0/8)\n"
513 "IP destination prefix\n"
514 "IP destination prefix mask\n"
515 "IP gateway address\n"
516 "IP gateway interface name\n"
518 "Set tag for this route\n"
520 "Distance value for this route\n"
523 "Table to configure\n"
524 "The table number to configure\n"
526 "Treat the nexthop as directly attached to the interface\n"
528 "The SR-TE color to configure\n")
530 struct static_route_args args
= {
533 .safi
= SAFI_UNICAST
,
535 .prefix_mask
= mask_str
,
537 .interface_name
= ifname
,
539 .distance
= distance_str
,
545 .nexthop_vrf
= nexthop_vrf
,
548 return static_route_nb_run(vty
, &args
);
551 DEFPY_YANG(ip_route_address_interface_vrf
,
552 ip_route_address_interface_vrf_cmd
,
554 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
556 <INTERFACE|Null0>$ifname \
561 |table (1-4294967295) \
564 |color (1-4294967295) \
567 "Establish static routes\n"
568 "IP destination prefix (e.g. 10.0.0.0/8)\n"
569 "IP destination prefix\n"
570 "IP destination prefix mask\n"
571 "IP gateway address\n"
572 "IP gateway interface name\n"
574 "Set tag for this route\n"
576 "Distance value for this route\n"
578 "Table to configure\n"
579 "The table number to configure\n"
581 "Treat the nexthop as directly attached to the interface\n"
583 "The SR-TE color to configure\n")
585 struct static_route_args args
= {
588 .safi
= SAFI_UNICAST
,
590 .prefix_mask
= mask_str
,
592 .interface_name
= ifname
,
594 .distance
= distance_str
,
600 .nexthop_vrf
= nexthop_vrf
,
603 return static_route_nb_run(vty
, &args
);
609 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
610 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
616 |table (1-4294967295) \
618 |color (1-4294967295) \
621 "Establish static routes\n"
622 "IP destination prefix (e.g. 10.0.0.0/8)\n"
623 "IP destination prefix\n"
624 "IP destination prefix mask\n"
625 "IP gateway address\n"
626 "IP gateway interface name\n"
628 "Set tag for this route\n"
630 "Distance value for this route\n"
633 "Table to configure\n"
634 "The table number to configure\n"
637 "The SR-TE color to configure\n")
639 struct static_route_args args
= {
642 .safi
= SAFI_UNICAST
,
644 .prefix_mask
= mask_str
,
646 .interface_name
= ifname
,
648 .distance
= distance_str
,
653 .nexthop_vrf
= nexthop_vrf
,
656 return static_route_nb_run(vty
, &args
);
659 DEFPY_YANG(ip_route_vrf
,
662 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
663 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
668 |table (1-4294967295) \
670 |color (1-4294967295) \
673 "Establish static routes\n"
674 "IP destination prefix (e.g. 10.0.0.0/8)\n"
675 "IP destination prefix\n"
676 "IP destination prefix mask\n"
677 "IP gateway address\n"
678 "IP gateway interface name\n"
680 "Set tag for this route\n"
682 "Distance value for this route\n"
684 "Table to configure\n"
685 "The table number to configure\n"
688 "The SR-TE color to configure\n")
690 struct static_route_args args
= {
693 .safi
= SAFI_UNICAST
,
695 .prefix_mask
= mask_str
,
697 .interface_name
= ifname
,
699 .distance
= distance_str
,
704 .nexthop_vrf
= nexthop_vrf
,
707 return static_route_nb_run(vty
, &args
);
710 DEFPY_YANG(ipv6_route_blackhole
,
711 ipv6_route_blackhole_cmd
,
712 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
713 <reject|blackhole>$flag \
719 |table (1-4294967295) \
723 "Establish static routes\n"
724 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
725 "IPv6 source-dest route\n"
726 "IPv6 source prefix\n"
727 "Emit an ICMP unreachable when matched\n"
728 "Silently discard pkts when matched\n"
729 "Set tag for this route\n"
731 "Distance value for this prefix\n"
734 "Table to configure\n"
735 "The table number to configure\n")
737 struct static_route_args args
= {
740 .safi
= SAFI_UNICAST
,
741 .prefix
= prefix_str
,
745 .distance
= distance_str
,
751 return static_route_nb_run(vty
, &args
);
754 DEFPY_YANG(ipv6_route_blackhole_vrf
,
755 ipv6_route_blackhole_vrf_cmd
,
756 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
757 <reject|blackhole>$flag \
762 |table (1-4294967295) \
766 "Establish static routes\n"
767 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
768 "IPv6 source-dest route\n"
769 "IPv6 source prefix\n"
770 "Emit an ICMP unreachable when matched\n"
771 "Silently discard pkts when matched\n"
772 "Set tag for this route\n"
774 "Distance value for this prefix\n"
776 "Table to configure\n"
777 "The table number to configure\n")
779 struct static_route_args args
= {
782 .safi
= SAFI_UNICAST
,
783 .prefix
= prefix_str
,
787 .distance
= distance_str
,
794 * Coverity is complaining that prefix could
795 * be dereferenced, but we know that prefix will
796 * valid. Add an assert to make it happy
800 return static_route_nb_run(vty
, &args
);
803 DEFPY_YANG(ipv6_route_address_interface
,
804 ipv6_route_address_interface_cmd
,
805 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
807 <INTERFACE|Null0>$ifname \
813 |table (1-4294967295) \
816 |color (1-4294967295) \
820 "Establish static routes\n"
821 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
822 "IPv6 source-dest route\n"
823 "IPv6 source prefix\n"
824 "IPv6 gateway address\n"
825 "IPv6 gateway interface name\n"
827 "Set tag for this route\n"
829 "Distance value for this prefix\n"
832 "Table to configure\n"
833 "The table number to configure\n"
835 "Treat the nexthop as directly attached to the interface\n"
837 "The SR-TE color to configure\n")
839 struct static_route_args args
= {
842 .safi
= SAFI_UNICAST
,
843 .prefix
= prefix_str
,
846 .interface_name
= ifname
,
848 .distance
= distance_str
,
854 .nexthop_vrf
= nexthop_vrf
,
857 return static_route_nb_run(vty
, &args
);
860 DEFPY_YANG(ipv6_route_address_interface_vrf
,
861 ipv6_route_address_interface_vrf_cmd
,
862 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
864 <INTERFACE|Null0>$ifname \
869 |table (1-4294967295) \
872 |color (1-4294967295) \
876 "Establish static routes\n"
877 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
878 "IPv6 source-dest route\n"
879 "IPv6 source prefix\n"
880 "IPv6 gateway address\n"
881 "IPv6 gateway interface name\n"
883 "Set tag for this route\n"
885 "Distance value for this prefix\n"
887 "Table to configure\n"
888 "The table number to configure\n"
890 "Treat the nexthop as directly attached to the interface\n"
892 "The SR-TE color to configure\n")
894 struct static_route_args args
= {
897 .safi
= SAFI_UNICAST
,
898 .prefix
= prefix_str
,
901 .interface_name
= ifname
,
903 .distance
= distance_str
,
909 .nexthop_vrf
= nexthop_vrf
,
912 return static_route_nb_run(vty
, &args
);
915 DEFPY_YANG(ipv6_route
,
917 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
918 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
924 |table (1-4294967295) \
926 |color (1-4294967295) \
930 "Establish static routes\n"
931 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
932 "IPv6 source-dest route\n"
933 "IPv6 source prefix\n"
934 "IPv6 gateway address\n"
935 "IPv6 gateway interface name\n"
937 "Set tag for this route\n"
939 "Distance value for this prefix\n"
942 "Table to configure\n"
943 "The table number to configure\n"
946 "The SR-TE color to configure\n")
948 struct static_route_args args
= {
951 .safi
= SAFI_UNICAST
,
952 .prefix
= prefix_str
,
955 .interface_name
= ifname
,
957 .distance
= distance_str
,
962 .nexthop_vrf
= nexthop_vrf
,
965 return static_route_nb_run(vty
, &args
);
968 DEFPY_YANG(ipv6_route_vrf
,
970 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
971 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
976 |table (1-4294967295) \
978 |color (1-4294967295) \
982 "Establish static routes\n"
983 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
984 "IPv6 source-dest route\n"
985 "IPv6 source prefix\n"
986 "IPv6 gateway address\n"
987 "IPv6 gateway interface name\n"
989 "Set tag for this route\n"
991 "Distance value for this prefix\n"
993 "Table to configure\n"
994 "The table number to configure\n"
997 "The SR-TE color to configure\n")
999 struct static_route_args args
= {
1002 .safi
= SAFI_UNICAST
,
1003 .prefix
= prefix_str
,
1005 .gateway
= gate_str
,
1006 .interface_name
= ifname
,
1008 .distance
= distance_str
,
1013 .nexthop_vrf
= nexthop_vrf
,
1016 return static_route_nb_run(vty
, &args
);
1019 void static_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1024 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1025 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1026 vty_out(vty
, "vrf %s\n", vrf
);
1029 void static_cli_show_end(struct vty
*vty
, const struct lyd_node
*dnode
)
1033 vrf
= yang_dnode_get_string(dnode
, "../vrf");
1034 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
1035 vty_out(vty
, "exit-vrf\n");
1038 struct mpls_label_iter
{
1043 static int mpls_label_iter_cb(const struct lyd_node
*dnode
, void *arg
)
1045 struct mpls_label_iter
*iter
= arg
;
1047 if (yang_dnode_exists(dnode
, "./label")) {
1049 vty_out(iter
->vty
, " label %s",
1050 yang_dnode_get_string(dnode
, "./label"));
1052 vty_out(iter
->vty
, "/%s",
1053 yang_dnode_get_string(dnode
, "./label"));
1054 iter
->first
= false;
1057 return YANG_ITER_CONTINUE
;
1060 static void nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*route
,
1061 const struct lyd_node
*src
,
1062 const struct lyd_node
*path
,
1063 const struct lyd_node
*nexthop
, bool show_defaults
)
1066 const char *afi_safi
;
1069 enum static_nh_type nh_type
;
1070 enum static_blackhole_type bh_type
;
1073 struct mpls_label_iter iter
;
1074 const char *nexthop_vrf
;
1078 vrf
= yang_dnode_get_string(route
, "../../vrf");
1080 afi_safi
= yang_dnode_get_string(route
, "./afi-safi");
1081 yang_afi_safi_identity2value(afi_safi
, &afi
, &safi
);
1084 vty_out(vty
, "%sip",
1085 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1087 vty_out(vty
, "%sipv6",
1088 strmatch(vrf
, VRF_DEFAULT_NAME
) ? "" : " ");
1090 if (safi
== SAFI_UNICAST
)
1091 vty_out(vty
, " route");
1093 vty_out(vty
, " mroute");
1095 vty_out(vty
, " %s", yang_dnode_get_string(route
, "./prefix"));
1098 vty_out(vty
, " from %s",
1099 yang_dnode_get_string(src
, "./src-prefix"));
1101 nh_type
= yang_dnode_get_enum(nexthop
, "./nh-type");
1105 yang_dnode_get_string(nexthop
, "./interface"));
1107 case STATIC_IPV4_GATEWAY
:
1108 case STATIC_IPV6_GATEWAY
:
1110 yang_dnode_get_string(nexthop
, "./gateway"));
1112 case STATIC_IPV4_GATEWAY_IFNAME
:
1113 case STATIC_IPV6_GATEWAY_IFNAME
:
1115 yang_dnode_get_string(nexthop
, "./gateway"));
1117 yang_dnode_get_string(nexthop
, "./interface"));
1119 case STATIC_BLACKHOLE
:
1120 bh_type
= yang_dnode_get_enum(nexthop
, "./bh-type");
1122 case STATIC_BLACKHOLE_DROP
:
1123 vty_out(vty
, " blackhole");
1125 case STATIC_BLACKHOLE_NULL
:
1126 vty_out(vty
, " Null0");
1128 case STATIC_BLACKHOLE_REJECT
:
1129 vty_out(vty
, " reject");
1135 if (yang_dnode_exists(path
, "./tag")) {
1136 tag
= yang_dnode_get_uint32(path
, "./tag");
1137 if (tag
!= 0 || show_defaults
)
1138 vty_out(vty
, " tag %" PRIu32
, tag
);
1141 distance
= yang_dnode_get_uint8(path
, "./distance");
1142 if (distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
|| show_defaults
)
1143 vty_out(vty
, " %" PRIu8
, distance
);
1147 yang_dnode_iterate(mpls_label_iter_cb
, &iter
, nexthop
,
1148 "./mpls-label-stack/entry");
1150 nexthop_vrf
= yang_dnode_get_string(nexthop
, "./vrf");
1151 if (strcmp(vrf
, nexthop_vrf
))
1152 vty_out(vty
, " nexthop-vrf %s", nexthop_vrf
);
1154 table_id
= yang_dnode_get_uint32(path
, "./table-id");
1155 if (table_id
|| show_defaults
)
1156 vty_out(vty
, " table %" PRIu32
, table_id
);
1158 if (yang_dnode_exists(nexthop
, "./onlink")) {
1159 onlink
= yang_dnode_get_bool(nexthop
, "./onlink");
1161 vty_out(vty
, " onlink");
1164 if (yang_dnode_exists(nexthop
, "./srte-color"))
1165 vty_out(vty
, " color %s",
1166 yang_dnode_get_string(nexthop
, "./srte-color"));
1171 void static_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1174 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1175 const struct lyd_node
*route
=
1176 yang_dnode_get_parent(path
, "route-list");
1178 nexthop_cli_show(vty
, route
, NULL
, path
, dnode
, show_defaults
);
1181 void static_src_nexthop_cli_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1184 const struct lyd_node
*path
= yang_dnode_get_parent(dnode
, "path-list");
1185 const struct lyd_node
*src
= yang_dnode_get_parent(path
, "src-list");
1186 const struct lyd_node
*route
= yang_dnode_get_parent(src
, "route-list");
1188 nexthop_cli_show(vty
, route
, src
, path
, dnode
, show_defaults
);
1191 int static_nexthop_cli_cmp(const struct lyd_node
*dnode1
,
1192 const struct lyd_node
*dnode2
)
1194 enum static_nh_type nh_type1
, nh_type2
;
1195 struct prefix prefix1
, prefix2
;
1198 nh_type1
= yang_dnode_get_enum(dnode1
, "./nh-type");
1199 nh_type2
= yang_dnode_get_enum(dnode2
, "./nh-type");
1201 if (nh_type1
!= nh_type2
)
1202 return (int)nh_type1
- (int)nh_type2
;
1206 ret
= if_cmp_name_func(
1207 yang_dnode_get_string(dnode1
, "./interface"),
1208 yang_dnode_get_string(dnode2
, "./interface"));
1210 case STATIC_IPV4_GATEWAY
:
1211 case STATIC_IPV6_GATEWAY
:
1212 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1213 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1214 ret
= prefix_cmp(&prefix1
, &prefix2
);
1216 case STATIC_IPV4_GATEWAY_IFNAME
:
1217 case STATIC_IPV6_GATEWAY_IFNAME
:
1218 yang_dnode_get_prefix(&prefix1
, dnode1
, "./gateway");
1219 yang_dnode_get_prefix(&prefix2
, dnode2
, "./gateway");
1220 ret
= prefix_cmp(&prefix1
, &prefix2
);
1222 ret
= if_cmp_name_func(
1223 yang_dnode_get_string(dnode1
, "./interface"),
1224 yang_dnode_get_string(dnode2
, "./interface"));
1226 case STATIC_BLACKHOLE
:
1227 /* There's only one blackhole nexthop per route */
1235 return if_cmp_name_func(yang_dnode_get_string(dnode1
, "./vrf"),
1236 yang_dnode_get_string(dnode2
, "./vrf"));
1239 int static_route_list_cli_cmp(const struct lyd_node
*dnode1
,
1240 const struct lyd_node
*dnode2
)
1242 const char *afi_safi1
, *afi_safi2
;
1244 safi_t safi1
, safi2
;
1245 struct prefix prefix1
, prefix2
;
1247 afi_safi1
= yang_dnode_get_string(dnode1
, "./afi-safi");
1248 yang_afi_safi_identity2value(afi_safi1
, &afi1
, &safi1
);
1250 afi_safi2
= yang_dnode_get_string(dnode2
, "./afi-safi");
1251 yang_afi_safi_identity2value(afi_safi2
, &afi2
, &safi2
);
1254 return (int)afi1
- (int)afi2
;
1257 return (int)safi1
- (int)safi2
;
1259 yang_dnode_get_prefix(&prefix1
, dnode1
, "./prefix");
1260 yang_dnode_get_prefix(&prefix2
, dnode2
, "./prefix");
1262 return prefix_cmp(&prefix1
, &prefix2
);
1265 int static_src_list_cli_cmp(const struct lyd_node
*dnode1
,
1266 const struct lyd_node
*dnode2
)
1268 struct prefix prefix1
, prefix2
;
1270 yang_dnode_get_prefix(&prefix1
, dnode1
, "./src-prefix");
1271 yang_dnode_get_prefix(&prefix2
, dnode2
, "./src-prefix");
1273 return prefix_cmp(&prefix1
, &prefix2
);
1276 int static_path_list_cli_cmp(const struct lyd_node
*dnode1
,
1277 const struct lyd_node
*dnode2
)
1279 uint32_t table_id1
, table_id2
;
1280 uint8_t distance1
, distance2
;
1282 table_id1
= yang_dnode_get_uint32(dnode1
, "./table-id");
1283 table_id2
= yang_dnode_get_uint32(dnode2
, "./table-id");
1285 if (table_id1
!= table_id2
)
1286 return (int)table_id1
- (int)table_id2
;
1288 distance1
= yang_dnode_get_uint8(dnode1
, "./distance");
1289 distance2
= yang_dnode_get_uint8(dnode2
, "./distance");
1291 return (int)distance1
- (int)distance2
;
1294 DEFPY_YANG(debug_staticd
, debug_staticd_cmd
,
1295 "[no] debug static [{events$events|route$route}]",
1296 NO_STR DEBUG_STR STATICD_STR
1300 /* If no specific category, change all */
1301 if (strmatch(argv
[argc
- 1]->text
, "static"))
1302 static_debug_set(vty
->node
, !no
, true, true);
1304 static_debug_set(vty
->node
, !no
, !!events
, !!route
);
1309 DEFUN_NOSH (show_debugging_static
,
1310 show_debugging_static_cmd
,
1311 "show debugging [static]",
1314 "Static Information\n")
1316 vty_out(vty
, "Staticd debugging status\n");
1318 static_debug_status_write(vty
);
1320 cmd_show_lib_debugs(vty
);
1325 static struct cmd_node debug_node
= {
1329 .config_write
= static_config_write_debug
,
1332 void static_vty_init(void)
1334 install_node(&debug_node
);
1336 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
1338 install_element(CONFIG_NODE
, &ip_route_blackhole_cmd
);
1339 install_element(VRF_NODE
, &ip_route_blackhole_vrf_cmd
);
1340 install_element(CONFIG_NODE
, &ip_route_address_interface_cmd
);
1341 install_element(VRF_NODE
, &ip_route_address_interface_vrf_cmd
);
1342 install_element(CONFIG_NODE
, &ip_route_cmd
);
1343 install_element(VRF_NODE
, &ip_route_vrf_cmd
);
1345 install_element(CONFIG_NODE
, &ipv6_route_blackhole_cmd
);
1346 install_element(VRF_NODE
, &ipv6_route_blackhole_vrf_cmd
);
1347 install_element(CONFIG_NODE
, &ipv6_route_address_interface_cmd
);
1348 install_element(VRF_NODE
, &ipv6_route_address_interface_vrf_cmd
);
1349 install_element(CONFIG_NODE
, &ipv6_route_cmd
);
1350 install_element(VRF_NODE
, &ipv6_route_vrf_cmd
);
1352 install_element(ENABLE_NODE
, &show_debugging_static_cmd
);
1353 install_element(ENABLE_NODE
, &debug_staticd_cmd
);
1354 install_element(CONFIG_NODE
, &debug_staticd_cmd
);