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"
31 #include "static_vrf.h"
32 #include "static_memory.h"
33 #include "static_vty.h"
34 #include "static_routes.h"
35 #ifndef VTYSH_EXTRACT_PL
36 #include "staticd/static_vty_clippy.c"
39 static struct static_vrf
*static_vty_get_unknown_vrf(struct vty
*vty
,
42 struct static_vrf
*svrf
;
45 svrf
= static_vrf_lookup_by_name(vrf_name
);
50 vrf
= vrf_get(VRF_UNKNOWN
, vrf_name
);
52 vty_out(vty
, "%% Could not create vrf %s\n", vrf_name
);
57 vty_out(vty
, "%% Could not create vrf-info %s\n",
61 /* Mark as having FRR configuration */
62 vrf_set_user_cfged(vrf
);
67 struct static_hold_route
{
84 /* processed & masked destination, used for config display */
88 static struct list
*static_list
;
90 static int static_list_compare_helper(const char *s1
, const char *s2
)
92 /* extra (!s1 && !s2) to keep SA happy */
93 if (s1
== s2
|| (!s1
&& !s2
))
102 return strcmp(s1
, s2
);
105 static void static_list_delete(struct static_hold_route
*shr
)
107 XFREE(MTYPE_STATIC_ROUTE
, shr
->vrf_name
);
108 XFREE(MTYPE_STATIC_ROUTE
, shr
->nhvrf_name
);
109 XFREE(MTYPE_STATIC_ROUTE
, shr
->dest_str
);
110 XFREE(MTYPE_STATIC_ROUTE
, shr
->mask_str
);
111 XFREE(MTYPE_STATIC_ROUTE
, shr
->src_str
);
112 XFREE(MTYPE_STATIC_ROUTE
, shr
->gate_str
);
113 XFREE(MTYPE_STATIC_ROUTE
, shr
->ifname
);
114 XFREE(MTYPE_STATIC_ROUTE
, shr
->flag_str
);
115 XFREE(MTYPE_STATIC_ROUTE
, shr
->tag_str
);
116 XFREE(MTYPE_STATIC_ROUTE
, shr
->distance_str
);
117 XFREE(MTYPE_STATIC_ROUTE
, shr
->label_str
);
118 XFREE(MTYPE_STATIC_ROUTE
, shr
->table_str
);
120 XFREE(MTYPE_STATIC_ROUTE
, shr
);
123 static int static_list_compare(void *arg1
, void *arg2
)
125 struct static_hold_route
*shr1
= arg1
;
126 struct static_hold_route
*shr2
= arg2
;
129 ret
= strcmp(shr1
->vrf_name
, shr2
->vrf_name
);
133 ret
= strcmp(shr1
->nhvrf_name
, shr2
->nhvrf_name
);
137 ret
= shr1
->afi
- shr2
->afi
;
141 ret
= shr1
->safi
- shr2
->safi
;
145 ret
= prefix_cmp(&shr1
->dest
, &shr2
->dest
);
149 ret
= static_list_compare_helper(shr1
->src_str
, shr2
->src_str
);
153 ret
= static_list_compare_helper(shr1
->gate_str
, shr2
->gate_str
);
157 ret
= static_list_compare_helper(shr1
->ifname
, shr2
->ifname
);
161 ret
= static_list_compare_helper(shr1
->flag_str
, shr2
->flag_str
);
165 ret
= static_list_compare_helper(shr1
->tag_str
, shr2
->tag_str
);
169 ret
= static_list_compare_helper(shr1
->distance_str
,
174 ret
= static_list_compare_helper(shr1
->table_str
,
179 return static_list_compare_helper(shr1
->label_str
, shr2
->label_str
);
183 /* General function for static route. */
184 static int zebra_static_route_holdem(
185 struct static_vrf
*svrf
, struct static_vrf
*nh_svrf
, afi_t afi
,
186 safi_t safi
, const char *negate
, struct prefix
*dest
,
187 const char *dest_str
, const char *mask_str
, const char *src_str
,
188 const char *gate_str
, const char *ifname
, const char *flag_str
,
189 const char *tag_str
, const char *distance_str
, const char *label_str
,
190 const char *table_str
, bool onlink
)
192 struct static_hold_route
*shr
, *lookup
;
193 struct listnode
*node
;
195 zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
198 shr
= XCALLOC(MTYPE_STATIC_ROUTE
, sizeof(*shr
));
199 shr
->vrf_name
= XSTRDUP(MTYPE_STATIC_ROUTE
, svrf
->vrf
->name
);
200 shr
->nhvrf_name
= XSTRDUP(MTYPE_STATIC_ROUTE
, nh_svrf
->vrf
->name
);
203 shr
->onlink
= onlink
;
205 prefix_copy(&shr
->dest
, dest
);
207 shr
->dest_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, dest_str
);
209 shr
->mask_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, mask_str
);
211 shr
->src_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, src_str
);
213 shr
->gate_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, gate_str
);
215 shr
->ifname
= XSTRDUP(MTYPE_STATIC_ROUTE
, ifname
);
217 shr
->flag_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, flag_str
);
219 shr
->tag_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, tag_str
);
221 shr
->distance_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, distance_str
);
223 shr
->label_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, label_str
);
225 shr
->table_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, table_str
);
227 for (ALL_LIST_ELEMENTS_RO(static_list
, node
, lookup
)) {
228 if (static_list_compare(shr
, lookup
) == 0)
234 listnode_delete(static_list
, lookup
);
235 static_list_delete(shr
);
236 static_list_delete(lookup
);
242 * If a person enters the same line again
243 * we need to silently accept it
249 listnode_add_sort(static_list
, shr
);
254 XFREE(MTYPE_STATIC_ROUTE
, shr
->nhvrf_name
);
255 XFREE(MTYPE_STATIC_ROUTE
, shr
->vrf_name
);
256 XFREE(MTYPE_STATIC_ROUTE
, shr
);
261 static int static_route_leak(
262 struct vty
*vty
, struct static_vrf
*svrf
, struct static_vrf
*nh_svrf
,
263 afi_t afi
, safi_t safi
, const char *negate
, const char *dest_str
,
264 const char *mask_str
, const char *src_str
, const char *gate_str
,
265 const char *ifname
, const char *flag_str
, const char *tag_str
,
266 const char *distance_str
, const char *label_str
, const char *table_str
,
271 struct prefix p
, src
;
272 struct prefix_ipv6
*src_p
= NULL
;
274 union g_addr
*gatep
= NULL
;
276 enum static_blackhole_type bh_type
= 0;
279 struct static_nh_label snh_label
;
280 uint32_t table_id
= 0;
282 ret
= str2prefix(dest_str
, &p
);
285 vty_out(vty
, "%% Malformed address\n");
287 zlog_warn("%s: Malformed address: %s",
288 __PRETTY_FUNCTION__
, dest_str
);
289 return CMD_WARNING_CONFIG_FAILED
;
294 /* Cisco like mask notation. */
296 ret
= inet_aton(mask_str
, &mask
);
299 vty_out(vty
, "%% Malformed address\n");
301 zlog_warn("%s: Malformed address: %s",
304 return CMD_WARNING_CONFIG_FAILED
;
306 p
.prefixlen
= ip_masklen(mask
);
310 /* srcdest routing */
312 ret
= str2prefix(src_str
, &src
);
313 if (ret
<= 0 || src
.family
!= AF_INET6
) {
316 "%% Malformed source address\n");
319 "%s: Malformed source address: %s",
320 __PRETTY_FUNCTION__
, src_str
);
321 return CMD_WARNING_CONFIG_FAILED
;
323 src_p
= (struct prefix_ipv6
*)&src
;
330 /* Apply mask for given prefix. */
333 if (svrf
->vrf
->vrf_id
== VRF_UNKNOWN
334 || nh_svrf
->vrf
->vrf_id
== VRF_UNKNOWN
) {
335 vrf_set_user_cfged(svrf
->vrf
);
336 return zebra_static_route_holdem(
337 svrf
, nh_svrf
, afi
, safi
, negate
, &p
, dest_str
,
338 mask_str
, src_str
, gate_str
, ifname
, flag_str
, tag_str
,
339 distance_str
, label_str
, table_str
, onlink
);
343 /* table configured. check consistent with vrf config
345 if (svrf
->vrf
->data
.l
.table_id
!= RT_TABLE_MAIN
) {
348 "%% Table %s overlaps vrf table %u\n",
349 table_str
, svrf
->vrf
->data
.l
.table_id
);
352 "%s: Table %s overlaps vrf table %u",
354 table_str
, svrf
->vrf
->data
.l
.table_id
);
355 return CMD_WARNING_CONFIG_FAILED
;
359 /* Administrative distance. */
361 distance
= atoi(distance_str
);
363 distance
= ZEBRA_STATIC_DISTANCE_DEFAULT
;
367 tag
= strtoul(tag_str
, NULL
, 10);
370 memset(&snh_label
, 0, sizeof(struct static_nh_label
));
375 "%% MPLS not turned on in kernel, ignoring command\n");
378 "%s: MPLS not turned on in kernel ignoring static route to %s",
379 __PRETTY_FUNCTION__
, dest_str
);
380 return CMD_WARNING_CONFIG_FAILED
;
382 int rc
= mpls_str2label(label_str
, &snh_label
.num_labels
,
388 vty_out(vty
, "%% Malformed label(s)\n");
391 "%s: Malformed labels specified for route %s",
392 __PRETTY_FUNCTION__
, dest_str
);
397 "%% Cannot use reserved label(s) (%d-%d)\n",
398 MPLS_LABEL_RESERVED_MIN
,
399 MPLS_LABEL_RESERVED_MAX
);
402 "%s: Cannot use reserved labels (%d-%d) for %s",
404 MPLS_LABEL_RESERVED_MIN
,
405 MPLS_LABEL_RESERVED_MAX
,
411 "%% Too many labels. Enter %d or fewer\n",
415 "%s: Too many labels, Enter %d or fewer for %s",
417 MPLS_MAX_LABELS
, dest_str
);
420 return CMD_WARNING_CONFIG_FAILED
;
426 table_id
= atol(table_str
);
428 /* Null0 static route. */
429 if (ifname
!= NULL
) {
430 if (strncasecmp(ifname
, "Null0", strlen(ifname
)) == 0
431 || strncasecmp(ifname
, "reject", strlen(ifname
)) == 0
432 || strncasecmp(ifname
, "blackhole", strlen(ifname
)) == 0) {
435 "%% Nexthop interface cannot be Null0, reject or blackhole\n");
438 "%s: Nexthop interface cannot be Null0, reject or blackhole for %s",
439 __PRETTY_FUNCTION__
, dest_str
);
440 return CMD_WARNING_CONFIG_FAILED
;
446 switch (flag_str
[0]) {
448 bh_type
= STATIC_BLACKHOLE_REJECT
;
451 bh_type
= STATIC_BLACKHOLE_DROP
;
454 bh_type
= STATIC_BLACKHOLE_NULL
;
458 vty_out(vty
, "%% Malformed flag %s \n",
461 zlog_warn("%s: Malformed flag %s for %s",
462 __PRETTY_FUNCTION__
, flag_str
,
464 return CMD_WARNING_CONFIG_FAILED
;
469 if (inet_pton(afi2family(afi
), gate_str
, &gate
) != 1) {
472 "%% Malformed nexthop address %s\n",
476 "%s: Malformed nexthop address %s for %s",
477 __PRETTY_FUNCTION__
, gate_str
,
479 return CMD_WARNING_CONFIG_FAILED
;
484 if (gate_str
== NULL
&& ifname
== NULL
)
485 type
= STATIC_BLACKHOLE
;
486 else if (gate_str
&& ifname
) {
488 type
= STATIC_IPV4_GATEWAY_IFNAME
;
490 type
= STATIC_IPV6_GATEWAY_IFNAME
;
492 type
= STATIC_IFNAME
;
495 type
= STATIC_IPV4_GATEWAY
;
497 type
= STATIC_IPV6_GATEWAY
;
501 static_add_route(afi
, safi
, type
, &p
, src_p
, gatep
, ifname
,
502 bh_type
, tag
, distance
, svrf
, nh_svrf
,
503 &snh_label
, table_id
, onlink
);
504 /* Mark as having FRR configuration */
505 vrf_set_user_cfged(svrf
->vrf
);
507 static_delete_route(afi
, safi
, type
, &p
, src_p
, gatep
, ifname
,
508 tag
, distance
, svrf
, &snh_label
, table_id
);
509 /* If no other FRR config for this VRF, mark accordingly. */
510 if (!static_vrf_has_config(svrf
))
511 vrf_reset_user_cfged(svrf
->vrf
);
517 static int static_route(struct vty
*vty
, afi_t afi
, safi_t safi
,
518 const char *negate
, const char *dest_str
,
519 const char *mask_str
, const char *src_str
,
520 const char *gate_str
, const char *ifname
,
521 const char *flag_str
, const char *tag_str
,
522 const char *distance_str
, const char *vrf_name
,
523 const char *label_str
, const char *table_str
)
525 struct static_vrf
*svrf
;
528 svrf
= static_vrf_lookup_by_name(vrf_name
);
530 /* When trying to delete, the VRF must exist. */
531 if (negate
&& !svrf
) {
532 vty_out(vty
, "%% vrf %s is not defined\n", vrf_name
);
533 return CMD_WARNING_CONFIG_FAILED
;
536 /* When trying to create, create the VRF if it doesn't exist.
537 * Note: The VRF isn't active until we hear about it from the kernel.
540 svrf
= static_vty_get_unknown_vrf(vty
, vrf_name
);
542 return CMD_WARNING_CONFIG_FAILED
;
544 return static_route_leak(vty
, svrf
, svrf
, afi
, safi
, negate
, dest_str
,
545 mask_str
, src_str
, gate_str
, ifname
, flag_str
,
546 tag_str
, distance_str
, label_str
, table_str
,
550 void static_config_install_delayed_routes(struct static_vrf
*svrf
)
552 struct listnode
*node
, *nnode
;
553 struct static_hold_route
*shr
;
554 struct static_vrf
*osvrf
, *nh_svrf
;
557 for (ALL_LIST_ELEMENTS(static_list
, node
, nnode
, shr
)) {
558 osvrf
= static_vrf_lookup_by_name(shr
->vrf_name
);
559 nh_svrf
= static_vrf_lookup_by_name(shr
->nhvrf_name
);
561 if (osvrf
!= svrf
&& nh_svrf
!= svrf
)
564 if (osvrf
->vrf
->vrf_id
== VRF_UNKNOWN
565 || nh_svrf
->vrf
->vrf_id
== VRF_UNKNOWN
)
568 installed
= static_route_leak(
569 NULL
, osvrf
, nh_svrf
, shr
->afi
, shr
->safi
, NULL
,
570 shr
->dest_str
, shr
->mask_str
, shr
->src_str
,
571 shr
->gate_str
, shr
->ifname
, shr
->flag_str
, shr
->tag_str
,
572 shr
->distance_str
, shr
->label_str
, shr
->table_str
,
575 if (installed
!= CMD_SUCCESS
)
577 "%s: Attempt to install %s as a route and it was rejected",
578 __PRETTY_FUNCTION__
, shr
->dest_str
);
579 listnode_delete(static_list
, shr
);
580 static_list_delete(shr
);
584 /* Write static route configuration. */
585 int static_config(struct vty
*vty
, struct static_vrf
*svrf
, afi_t afi
,
586 safi_t safi
, const char *cmd
)
588 struct static_hold_route
*shr
;
589 struct listnode
*node
;
591 struct route_node
*rn
;
592 struct static_route
*si
;
593 struct route_table
*stable
;
594 char buf
[SRCDEST2STR_BUFFER
];
597 stable
= svrf
->stable
[afi
][safi
];
601 sprintf(spacing
, "%s%s", (svrf
->vrf
->vrf_id
== VRF_DEFAULT
) ? "" : " ",
605 * Static routes for vrfs not fully inited
607 for (ALL_LIST_ELEMENTS_RO(static_list
, node
, shr
)) {
608 if (shr
->afi
!= afi
|| shr
->safi
!= safi
)
611 if (strcmp(svrf
->vrf
->name
, shr
->vrf_name
) != 0)
614 char dest_str
[PREFIX_STRLEN
];
616 prefix2str(&shr
->dest
, dest_str
, sizeof(dest_str
));
618 vty_out(vty
, "%s ", spacing
);
620 vty_out(vty
, "%s ", dest_str
);
622 vty_out(vty
, "from %s ", shr
->src_str
);
624 vty_out(vty
, "%s ", shr
->gate_str
);
626 vty_out(vty
, "%s ", shr
->ifname
);
628 vty_out(vty
, "%s ", shr
->flag_str
);
630 vty_out(vty
, "tag %s ", shr
->tag_str
);
631 if (shr
->distance_str
)
632 vty_out(vty
, "%s ", shr
->distance_str
);
634 vty_out(vty
, "label %s ", shr
->label_str
);
636 vty_out(vty
, "table %s", shr
->table_str
);
637 if (strcmp(shr
->vrf_name
, shr
->nhvrf_name
) != 0)
638 vty_out(vty
, "nexthop-vrf %s ", shr
->nhvrf_name
);
640 vty_out(vty
, "onlink");
644 for (rn
= route_top(stable
); rn
; rn
= srcdest_route_next(rn
))
645 for (si
= rn
->info
; si
; si
= si
->next
) {
646 vty_out(vty
, "%s %s", spacing
,
647 srcdest_rnode2str(rn
, buf
, sizeof(buf
)));
650 case STATIC_IPV4_GATEWAY
:
651 vty_out(vty
, " %s", inet_ntoa(si
->addr
.ipv4
));
653 case STATIC_IPV6_GATEWAY
:
655 inet_ntop(AF_INET6
, &si
->addr
.ipv6
, buf
,
659 vty_out(vty
, " %s", si
->ifname
);
661 case STATIC_BLACKHOLE
:
662 switch (si
->bh_type
) {
663 case STATIC_BLACKHOLE_DROP
:
664 vty_out(vty
, " blackhole");
666 case STATIC_BLACKHOLE_NULL
:
667 vty_out(vty
, " Null0");
669 case STATIC_BLACKHOLE_REJECT
:
670 vty_out(vty
, " reject");
674 case STATIC_IPV4_GATEWAY_IFNAME
:
675 vty_out(vty
, " %s %s",
676 inet_ntop(AF_INET
, &si
->addr
.ipv4
, buf
,
680 case STATIC_IPV6_GATEWAY_IFNAME
:
681 vty_out(vty
, " %s %s",
682 inet_ntop(AF_INET6
, &si
->addr
.ipv6
, buf
,
689 vty_out(vty
, " tag %" ROUTE_TAG_PRI
, si
->tag
);
691 if (si
->distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
)
692 vty_out(vty
, " %d", si
->distance
);
694 /* Label information */
695 if (si
->snh_label
.num_labels
)
696 vty_out(vty
, " label %s",
697 mpls_label2str(si
->snh_label
.num_labels
,
698 si
->snh_label
.label
, buf
,
701 if (si
->nh_vrf_id
!= si
->vrf_id
)
702 vty_out(vty
, " nexthop-vrf %s", si
->nh_vrfname
);
705 * table ID from VRF overrides configured
708 svrf
->vrf
->data
.l
.table_id
== RT_TABLE_MAIN
)
709 vty_out(vty
, " table %u", si
->table_id
);
712 vty_out(vty
, " onlink");
721 /* Static unicast routes for multicast RPF lookup. */
722 DEFPY (ip_mroute_dist
,
724 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
727 "Configure static unicast route into MRIB for multicast RPF lookup\n"
728 "IP destination prefix (e.g. 10.0.0.0/8)\n"
730 "Nexthop interface name\n"
733 return static_route(vty
, AFI_IP
, SAFI_MULTICAST
, no
, prefix_str
,
734 NULL
, NULL
, gate_str
, ifname
, NULL
, NULL
,
735 distance_str
, NULL
, NULL
, NULL
);
738 /* Static route configuration. */
739 DEFPY(ip_route_blackhole
,
740 ip_route_blackhole_cmd
,
742 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
743 <reject|blackhole>$flag \
749 |table (1-4294967295) \
752 "Establish static routes\n"
753 "IP destination prefix (e.g. 10.0.0.0/8)\n"
754 "IP destination prefix\n"
755 "IP destination prefix mask\n"
756 "Emit an ICMP unreachable when matched\n"
757 "Silently discard pkts when matched\n"
758 "Set tag for this route\n"
760 "Distance value for this route\n"
763 "Table to configure\n"
764 "The table number to configure\n")
766 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
768 "%% table param only available when running on netns-based vrfs\n");
769 return CMD_WARNING_CONFIG_FAILED
;
772 return static_route(vty
, AFI_IP
, SAFI_UNICAST
, no
, prefix
,
773 mask_str
, NULL
, NULL
, NULL
, flag
, tag_str
,
774 distance_str
, vrf
, label
, table_str
);
777 DEFPY(ip_route_blackhole_vrf
,
778 ip_route_blackhole_vrf_cmd
,
780 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
781 <reject|blackhole>$flag \
786 |table (1-4294967295) \
789 "Establish static routes\n"
790 "IP destination prefix (e.g. 10.0.0.0/8)\n"
791 "IP destination prefix\n"
792 "IP destination prefix mask\n"
793 "Emit an ICMP unreachable when matched\n"
794 "Silently discard pkts when matched\n"
795 "Set tag for this route\n"
797 "Distance value for this route\n"
799 "Table to configure\n"
800 "The table number to configure\n")
802 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
803 struct static_vrf
*svrf
= vrf
->info
;
805 if (table_str
&& !vrf_is_backend_netns()) {
807 "%% table param only available when running on netns-based vrfs\n");
808 return CMD_WARNING_CONFIG_FAILED
;
812 * Coverity is complaining that prefix could
813 * be dereferenced, but we know that prefix will
814 * valid. Add an assert to make it happy
817 return static_route_leak(vty
, svrf
, svrf
, AFI_IP
, SAFI_UNICAST
, no
,
818 prefix
, mask_str
, NULL
, NULL
, NULL
, flag
,
819 tag_str
, distance_str
, label
, table_str
,
823 DEFPY(ip_route_address_interface
,
824 ip_route_address_interface_cmd
,
826 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
828 <INTERFACE|Null0>$ifname \
834 |table (1-4294967295) \
839 "Establish static routes\n"
840 "IP destination prefix (e.g. 10.0.0.0/8)\n"
841 "IP destination prefix\n"
842 "IP destination prefix mask\n"
843 "IP gateway address\n"
844 "IP gateway interface name\n"
846 "Set tag for this route\n"
848 "Distance value for this route\n"
851 "Table to configure\n"
852 "The table number to configure\n"
854 "Treat the nexthop as directly attached to the interface")
856 struct static_vrf
*svrf
;
857 struct static_vrf
*nh_svrf
;
858 const char *flag
= NULL
;
860 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
865 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
867 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
868 return CMD_WARNING_CONFIG_FAILED
;
871 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
873 "%% table param only available when running on netns-based vrfs\n");
874 return CMD_WARNING_CONFIG_FAILED
;
878 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
883 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
884 return CMD_WARNING_CONFIG_FAILED
;
887 return static_route_leak(vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
,
888 prefix
, mask_str
, NULL
, gate_str
, ifname
, flag
,
889 tag_str
, distance_str
, label
, table_str
,
893 DEFPY(ip_route_address_interface_vrf
,
894 ip_route_address_interface_vrf_cmd
,
896 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
898 <INTERFACE|Null0>$ifname \
903 |table (1-4294967295) \
908 "Establish static routes\n"
909 "IP destination prefix (e.g. 10.0.0.0/8)\n"
910 "IP destination prefix\n"
911 "IP destination prefix mask\n"
912 "IP gateway address\n"
913 "IP gateway interface name\n"
915 "Set tag for this route\n"
917 "Distance value for this route\n"
919 "Table to configure\n"
920 "The table number to configure\n"
922 "Treat the nexthop as directly attached to the interface")
924 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
925 const char *flag
= NULL
;
926 struct static_vrf
*svrf
= vrf
->info
;
927 struct static_vrf
*nh_svrf
;
929 if (table_str
&& !vrf_is_backend_netns()) {
931 "%% table param only available when running on netns-based vrfs\n");
932 return CMD_WARNING_CONFIG_FAILED
;
935 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
941 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
946 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
947 return CMD_WARNING_CONFIG_FAILED
;
950 return static_route_leak(vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
,
951 prefix
, mask_str
, NULL
, gate_str
, ifname
, flag
,
952 tag_str
, distance_str
, label
, table_str
,
959 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
960 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
966 |table (1-4294967295) \
970 "Establish static routes\n"
971 "IP destination prefix (e.g. 10.0.0.0/8)\n"
972 "IP destination prefix\n"
973 "IP destination prefix mask\n"
974 "IP gateway address\n"
975 "IP gateway interface name\n"
977 "Set tag for this route\n"
979 "Distance value for this route\n"
982 "Table to configure\n"
983 "The table number to configure\n"
986 struct static_vrf
*svrf
;
987 struct static_vrf
*nh_svrf
;
988 const char *flag
= NULL
;
990 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
992 "%% table param only available when running on netns-based vrfs\n");
993 return CMD_WARNING_CONFIG_FAILED
;
996 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1001 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1003 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1004 return CMD_WARNING_CONFIG_FAILED
;
1008 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1013 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1014 return CMD_WARNING_CONFIG_FAILED
;
1017 return static_route_leak(
1018 vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
, prefix
, mask_str
,
1019 NULL
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1026 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
1027 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
1029 tag (1-4294967295) \
1032 |table (1-4294967295) \
1036 "Establish static routes\n"
1037 "IP destination prefix (e.g. 10.0.0.0/8)\n"
1038 "IP destination prefix\n"
1039 "IP destination prefix mask\n"
1040 "IP gateway address\n"
1041 "IP gateway interface name\n"
1043 "Set tag for this route\n"
1045 "Distance value for this route\n"
1047 "Table to configure\n"
1048 "The table number to configure\n"
1051 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1052 struct static_vrf
*svrf
= vrf
->info
;
1053 struct static_vrf
*nh_svrf
;
1054 const char *flag
= NULL
;
1056 if (table_str
&& !vrf_is_backend_netns()) {
1058 "%% table param only available when running on netns-based vrfs\n");
1059 return CMD_WARNING_CONFIG_FAILED
;
1062 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1068 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1073 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1074 return CMD_WARNING_CONFIG_FAILED
;
1077 return static_route_leak(
1078 vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
, prefix
, mask_str
,
1079 NULL
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1083 DEFPY(ipv6_route_blackhole
,
1084 ipv6_route_blackhole_cmd
,
1085 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1086 <reject|blackhole>$flag \
1088 tag (1-4294967295) \
1092 |table (1-4294967295) \
1096 "Establish static routes\n"
1097 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1098 "IPv6 source-dest route\n"
1099 "IPv6 source prefix\n"
1100 "Emit an ICMP unreachable when matched\n"
1101 "Silently discard pkts when matched\n"
1102 "Set tag for this route\n"
1104 "Distance value for this prefix\n"
1107 "Table to configure\n"
1108 "The table number to configure\n")
1110 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1112 "%% table param only available when running on netns-based vrfs\n");
1113 return CMD_WARNING_CONFIG_FAILED
;
1116 return static_route(vty
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
,
1117 NULL
, from_str
, NULL
, NULL
, flag
, tag_str
,
1118 distance_str
, vrf
, label
, table_str
);
1121 DEFPY(ipv6_route_blackhole_vrf
,
1122 ipv6_route_blackhole_vrf_cmd
,
1123 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1124 <reject|blackhole>$flag \
1126 tag (1-4294967295) \
1129 |table (1-4294967295) \
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 "Emit an ICMP unreachable when matched\n"
1138 "Silently discard pkts when matched\n"
1139 "Set tag for this route\n"
1141 "Distance value for this prefix\n"
1143 "Table to configure\n"
1144 "The table number to configure\n")
1146 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1147 struct static_vrf
*svrf
= vrf
->info
;
1149 if (table_str
&& !vrf_is_backend_netns()) {
1151 "%% table param only available when running on netns-based vrfs\n");
1152 return CMD_WARNING_CONFIG_FAILED
;
1156 * Coverity is complaining that prefix could
1157 * be dereferenced, but we know that prefix will
1158 * valid. Add an assert to make it happy
1161 return static_route_leak(
1162 vty
, svrf
, svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1163 from_str
, NULL
, NULL
, flag
, tag_str
, distance_str
, label
,
1167 DEFPY(ipv6_route_address_interface
,
1168 ipv6_route_address_interface_cmd
,
1169 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1171 <INTERFACE|Null0>$ifname \
1173 tag (1-4294967295) \
1177 |table (1-4294967295) \
1183 "Establish static routes\n"
1184 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1185 "IPv6 source-dest route\n"
1186 "IPv6 source prefix\n"
1187 "IPv6 gateway address\n"
1188 "IPv6 gateway interface name\n"
1190 "Set tag for this route\n"
1192 "Distance value for this prefix\n"
1195 "Table to configure\n"
1196 "The table number to configure\n"
1198 "Treat the nexthop as directly attached to the interface")
1200 struct static_vrf
*svrf
;
1201 struct static_vrf
*nh_svrf
;
1202 const char *flag
= NULL
;
1204 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1206 "%% table param only available when running on netns-based vrfs\n");
1207 return CMD_WARNING_CONFIG_FAILED
;
1210 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1212 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1213 return CMD_WARNING_CONFIG_FAILED
;
1217 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1222 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1223 return CMD_WARNING_CONFIG_FAILED
;
1226 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1231 return static_route_leak(
1232 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1233 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1234 table_str
, !!onlink
);
1237 DEFPY(ipv6_route_address_interface_vrf
,
1238 ipv6_route_address_interface_vrf_cmd
,
1239 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1241 <INTERFACE|Null0>$ifname \
1243 tag (1-4294967295) \
1246 |table (1-4294967295) \
1252 "Establish static routes\n"
1253 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1254 "IPv6 source-dest route\n"
1255 "IPv6 source prefix\n"
1256 "IPv6 gateway address\n"
1257 "IPv6 gateway interface name\n"
1259 "Set tag for this route\n"
1261 "Distance value for this prefix\n"
1263 "Table to configure\n"
1264 "The table number to configure\n"
1266 "Treat the nexthop as directly attached to the interface")
1268 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1269 struct static_vrf
*svrf
= vrf
->info
;
1270 struct static_vrf
*nh_svrf
;
1271 const char *flag
= NULL
;
1273 if (table_str
&& !vrf_is_backend_netns()) {
1275 "%% table param only available when running on netns-based vrfs\n");
1276 return CMD_WARNING_CONFIG_FAILED
;
1280 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1285 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1286 return CMD_WARNING_CONFIG_FAILED
;
1289 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1294 return static_route_leak(
1295 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1296 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1297 table_str
, !!onlink
);
1302 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1303 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1305 tag (1-4294967295) \
1309 |table (1-4294967295) \
1314 "Establish static routes\n"
1315 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1316 "IPv6 source-dest route\n"
1317 "IPv6 source prefix\n"
1318 "IPv6 gateway address\n"
1319 "IPv6 gateway interface name\n"
1321 "Set tag for this route\n"
1323 "Distance value for this prefix\n"
1326 "Table to configure\n"
1327 "The table number to configure\n"
1330 struct static_vrf
*svrf
;
1331 struct static_vrf
*nh_svrf
;
1332 const char *flag
= NULL
;
1334 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1336 "%% table param only available when running on netns-based vrfs\n");
1337 return CMD_WARNING_CONFIG_FAILED
;
1340 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1342 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1343 return CMD_WARNING_CONFIG_FAILED
;
1347 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1352 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1353 return CMD_WARNING_CONFIG_FAILED
;
1356 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1361 return static_route_leak(
1362 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1363 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1367 DEFPY(ipv6_route_vrf
,
1369 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1370 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1372 tag (1-4294967295) \
1375 |table (1-4294967295) \
1380 "Establish static routes\n"
1381 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1382 "IPv6 source-dest route\n"
1383 "IPv6 source prefix\n"
1384 "IPv6 gateway address\n"
1385 "IPv6 gateway interface name\n"
1387 "Set tag for this route\n"
1389 "Distance value for this prefix\n"
1391 "Table to configure\n"
1392 "The table number to configure\n"
1395 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1396 struct static_vrf
*svrf
= vrf
->info
;
1397 struct static_vrf
*nh_svrf
;
1398 const char *flag
= NULL
;
1400 if (table_str
&& !vrf_is_backend_netns()) {
1402 "%% table param only available when running on netns-based vrfs\n");
1403 return CMD_WARNING_CONFIG_FAILED
;
1407 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1412 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1413 return CMD_WARNING_CONFIG_FAILED
;
1416 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1421 return static_route_leak(
1422 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1423 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1427 DEFUN_NOSH (show_debugging_staticd
,
1428 show_debugging_staticd_cmd
,
1429 "show debugging [static]",
1432 "Static Information\n")
1434 vty_out(vty
, "Static debugging status\n");
1439 void static_vty_init(void)
1441 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
1443 install_element(CONFIG_NODE
, &ip_route_blackhole_cmd
);
1444 install_element(VRF_NODE
, &ip_route_blackhole_vrf_cmd
);
1445 install_element(CONFIG_NODE
, &ip_route_address_interface_cmd
);
1446 install_element(VRF_NODE
, &ip_route_address_interface_vrf_cmd
);
1447 install_element(CONFIG_NODE
, &ip_route_cmd
);
1448 install_element(VRF_NODE
, &ip_route_vrf_cmd
);
1450 install_element(CONFIG_NODE
, &ipv6_route_blackhole_cmd
);
1451 install_element(VRF_NODE
, &ipv6_route_blackhole_vrf_cmd
);
1452 install_element(CONFIG_NODE
, &ipv6_route_address_interface_cmd
);
1453 install_element(VRF_NODE
, &ipv6_route_address_interface_vrf_cmd
);
1454 install_element(CONFIG_NODE
, &ipv6_route_cmd
);
1455 install_element(VRF_NODE
, &ipv6_route_vrf_cmd
);
1457 install_element(VIEW_NODE
, &show_debugging_staticd_cmd
);
1459 static_list
= list_new();
1460 static_list
->cmp
= (int (*)(void *, void *))static_list_compare
;
1461 static_list
->del
= (void (*)(void *))static_list_delete
;