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 #include "static_debug.h"
36 #ifndef VTYSH_EXTRACT_PL
37 #include "staticd/static_vty_clippy.c"
40 #define STATICD_STR "Static route daemon\n"
42 static struct static_vrf
*static_vty_get_unknown_vrf(struct vty
*vty
,
45 struct static_vrf
*svrf
;
48 svrf
= static_vrf_lookup_by_name(vrf_name
);
53 vrf
= vrf_get(VRF_UNKNOWN
, vrf_name
);
55 vty_out(vty
, "%% Could not create vrf %s\n", vrf_name
);
60 vty_out(vty
, "%% Could not create vrf-info %s\n",
64 /* Mark as having FRR configuration */
65 vrf_set_user_cfged(vrf
);
70 struct static_hold_route
{
87 /* processed & masked destination, used for config display */
91 static struct list
*static_list
;
93 static int static_list_compare_helper(const char *s1
, const char *s2
)
95 /* extra (!s1 && !s2) to keep SA happy */
96 if (s1
== s2
|| (!s1
&& !s2
))
105 return strcmp(s1
, s2
);
108 static void static_list_delete(struct static_hold_route
*shr
)
110 XFREE(MTYPE_STATIC_ROUTE
, shr
->vrf_name
);
111 XFREE(MTYPE_STATIC_ROUTE
, shr
->nhvrf_name
);
112 XFREE(MTYPE_STATIC_ROUTE
, shr
->dest_str
);
113 XFREE(MTYPE_STATIC_ROUTE
, shr
->mask_str
);
114 XFREE(MTYPE_STATIC_ROUTE
, shr
->src_str
);
115 XFREE(MTYPE_STATIC_ROUTE
, shr
->gate_str
);
116 XFREE(MTYPE_STATIC_ROUTE
, shr
->ifname
);
117 XFREE(MTYPE_STATIC_ROUTE
, shr
->flag_str
);
118 XFREE(MTYPE_STATIC_ROUTE
, shr
->tag_str
);
119 XFREE(MTYPE_STATIC_ROUTE
, shr
->distance_str
);
120 XFREE(MTYPE_STATIC_ROUTE
, shr
->label_str
);
121 XFREE(MTYPE_STATIC_ROUTE
, shr
->table_str
);
123 XFREE(MTYPE_STATIC_ROUTE
, shr
);
126 static int static_list_compare(void *arg1
, void *arg2
)
128 struct static_hold_route
*shr1
= arg1
;
129 struct static_hold_route
*shr2
= arg2
;
132 ret
= strcmp(shr1
->vrf_name
, shr2
->vrf_name
);
136 ret
= strcmp(shr1
->nhvrf_name
, shr2
->nhvrf_name
);
140 ret
= shr1
->afi
- shr2
->afi
;
144 ret
= shr1
->safi
- shr2
->safi
;
148 ret
= prefix_cmp(&shr1
->dest
, &shr2
->dest
);
152 ret
= static_list_compare_helper(shr1
->src_str
, shr2
->src_str
);
156 ret
= static_list_compare_helper(shr1
->gate_str
, shr2
->gate_str
);
160 ret
= static_list_compare_helper(shr1
->ifname
, shr2
->ifname
);
164 ret
= static_list_compare_helper(shr1
->flag_str
, shr2
->flag_str
);
168 ret
= static_list_compare_helper(shr1
->tag_str
, shr2
->tag_str
);
172 ret
= static_list_compare_helper(shr1
->distance_str
,
177 ret
= static_list_compare_helper(shr1
->table_str
,
182 return static_list_compare_helper(shr1
->label_str
, shr2
->label_str
);
186 /* General function for static route. */
187 static int zebra_static_route_holdem(
188 struct static_vrf
*svrf
, struct static_vrf
*nh_svrf
, afi_t afi
,
189 safi_t safi
, const char *negate
, struct prefix
*dest
,
190 const char *dest_str
, const char *mask_str
, const char *src_str
,
191 const char *gate_str
, const char *ifname
, const char *flag_str
,
192 const char *tag_str
, const char *distance_str
, const char *label_str
,
193 const char *table_str
, bool onlink
)
195 struct static_hold_route
*shr
, *lookup
;
196 struct listnode
*node
;
198 zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
201 shr
= XCALLOC(MTYPE_STATIC_ROUTE
, sizeof(*shr
));
202 shr
->vrf_name
= XSTRDUP(MTYPE_STATIC_ROUTE
, svrf
->vrf
->name
);
203 shr
->nhvrf_name
= XSTRDUP(MTYPE_STATIC_ROUTE
, nh_svrf
->vrf
->name
);
206 shr
->onlink
= onlink
;
208 prefix_copy(&shr
->dest
, dest
);
210 shr
->dest_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, dest_str
);
212 shr
->mask_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, mask_str
);
214 shr
->src_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, src_str
);
216 shr
->gate_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, gate_str
);
218 shr
->ifname
= XSTRDUP(MTYPE_STATIC_ROUTE
, ifname
);
220 shr
->flag_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, flag_str
);
222 shr
->tag_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, tag_str
);
224 shr
->distance_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, distance_str
);
226 shr
->label_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, label_str
);
228 shr
->table_str
= XSTRDUP(MTYPE_STATIC_ROUTE
, table_str
);
230 for (ALL_LIST_ELEMENTS_RO(static_list
, node
, lookup
)) {
231 if (static_list_compare(shr
, lookup
) == 0)
237 listnode_delete(static_list
, lookup
);
238 static_list_delete(shr
);
239 static_list_delete(lookup
);
245 * If a person enters the same line again
246 * we need to silently accept it
252 listnode_add_sort(static_list
, shr
);
257 XFREE(MTYPE_STATIC_ROUTE
, shr
->nhvrf_name
);
258 XFREE(MTYPE_STATIC_ROUTE
, shr
->vrf_name
);
259 XFREE(MTYPE_STATIC_ROUTE
, shr
);
264 static int static_route_leak(
265 struct vty
*vty
, struct static_vrf
*svrf
, struct static_vrf
*nh_svrf
,
266 afi_t afi
, safi_t safi
, const char *negate
, const char *dest_str
,
267 const char *mask_str
, const char *src_str
, const char *gate_str
,
268 const char *ifname
, const char *flag_str
, const char *tag_str
,
269 const char *distance_str
, const char *label_str
, const char *table_str
,
274 struct prefix p
, src
;
275 struct prefix_ipv6
*src_p
= NULL
;
277 union g_addr
*gatep
= NULL
;
279 enum static_blackhole_type bh_type
= 0;
282 struct static_nh_label snh_label
;
283 uint32_t table_id
= 0;
285 ret
= str2prefix(dest_str
, &p
);
288 vty_out(vty
, "%% Malformed address\n");
290 zlog_warn("%s: Malformed address: %s",
291 __PRETTY_FUNCTION__
, dest_str
);
292 return CMD_WARNING_CONFIG_FAILED
;
297 /* Cisco like mask notation. */
299 ret
= inet_aton(mask_str
, &mask
);
302 vty_out(vty
, "%% Malformed address\n");
304 zlog_warn("%s: Malformed address: %s",
307 return CMD_WARNING_CONFIG_FAILED
;
309 p
.prefixlen
= ip_masklen(mask
);
313 /* srcdest routing */
315 ret
= str2prefix(src_str
, &src
);
316 if (ret
<= 0 || src
.family
!= AF_INET6
) {
319 "%% Malformed source address\n");
322 "%s: Malformed source address: %s",
323 __PRETTY_FUNCTION__
, src_str
);
324 return CMD_WARNING_CONFIG_FAILED
;
326 src_p
= (struct prefix_ipv6
*)&src
;
333 /* Apply mask for given prefix. */
336 if (svrf
->vrf
->vrf_id
== VRF_UNKNOWN
337 || nh_svrf
->vrf
->vrf_id
== VRF_UNKNOWN
) {
338 vrf_set_user_cfged(svrf
->vrf
);
339 return zebra_static_route_holdem(
340 svrf
, nh_svrf
, afi
, safi
, negate
, &p
, dest_str
,
341 mask_str
, src_str
, gate_str
, ifname
, flag_str
, tag_str
,
342 distance_str
, label_str
, table_str
, onlink
);
346 /* table configured. check consistent with vrf config
348 if (svrf
->vrf
->data
.l
.table_id
!= RT_TABLE_MAIN
) {
351 "%% Table %s overlaps vrf table %u\n",
352 table_str
, svrf
->vrf
->data
.l
.table_id
);
355 "%s: Table %s overlaps vrf table %u",
357 table_str
, svrf
->vrf
->data
.l
.table_id
);
358 return CMD_WARNING_CONFIG_FAILED
;
362 /* Administrative distance. */
364 distance
= atoi(distance_str
);
366 distance
= ZEBRA_STATIC_DISTANCE_DEFAULT
;
370 tag
= strtoul(tag_str
, NULL
, 10);
373 memset(&snh_label
, 0, sizeof(struct static_nh_label
));
378 "%% MPLS not turned on in kernel, ignoring command\n");
381 "%s: MPLS not turned on in kernel ignoring static route to %s",
382 __PRETTY_FUNCTION__
, dest_str
);
383 return CMD_WARNING_CONFIG_FAILED
;
385 int rc
= mpls_str2label(label_str
, &snh_label
.num_labels
,
391 vty_out(vty
, "%% Malformed label(s)\n");
394 "%s: Malformed labels specified for route %s",
395 __PRETTY_FUNCTION__
, dest_str
);
400 "%% Cannot use reserved label(s) (%d-%d)\n",
401 MPLS_LABEL_RESERVED_MIN
,
402 MPLS_LABEL_RESERVED_MAX
);
405 "%s: Cannot use reserved labels (%d-%d) for %s",
407 MPLS_LABEL_RESERVED_MIN
,
408 MPLS_LABEL_RESERVED_MAX
,
414 "%% Too many labels. Enter %d or fewer\n",
418 "%s: Too many labels, Enter %d or fewer for %s",
420 MPLS_MAX_LABELS
, dest_str
);
423 return CMD_WARNING_CONFIG_FAILED
;
429 table_id
= atol(table_str
);
431 /* Null0 static route. */
432 if (ifname
!= NULL
) {
433 if (strcasecmp(ifname
, "Null0") == 0
434 || strcasecmp(ifname
, "reject") == 0
435 || strcasecmp(ifname
, "blackhole") == 0) {
438 "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n");
441 "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)",
442 __PRETTY_FUNCTION__
, dest_str
);
443 return CMD_WARNING_CONFIG_FAILED
;
449 switch (flag_str
[0]) {
451 bh_type
= STATIC_BLACKHOLE_REJECT
;
454 bh_type
= STATIC_BLACKHOLE_DROP
;
457 bh_type
= STATIC_BLACKHOLE_NULL
;
461 vty_out(vty
, "%% Malformed flag %s \n",
464 zlog_warn("%s: Malformed flag %s for %s",
465 __PRETTY_FUNCTION__
, flag_str
,
467 return CMD_WARNING_CONFIG_FAILED
;
472 if (inet_pton(afi2family(afi
), gate_str
, &gate
) != 1) {
475 "%% Malformed nexthop address %s\n",
479 "%s: Malformed nexthop address %s for %s",
480 __PRETTY_FUNCTION__
, gate_str
,
482 return CMD_WARNING_CONFIG_FAILED
;
486 if (afi
== AFI_IP
&& !negate
) {
487 if (if_lookup_exact_address(&gatep
->ipv4
, AF_INET
,
491 "%% Warning!! Local connected address is configured as Gateway IP(%s)\n",
493 } else if (afi
== AFI_IP6
&& !negate
) {
494 if (if_lookup_exact_address(&gatep
->ipv6
, AF_INET6
,
498 "%% Warning!! Local connected address is configured as Gateway IPv6(%s)\n",
504 if (gate_str
== NULL
&& ifname
== NULL
)
505 type
= STATIC_BLACKHOLE
;
506 else if (gate_str
&& ifname
) {
508 type
= STATIC_IPV4_GATEWAY_IFNAME
;
510 type
= STATIC_IPV6_GATEWAY_IFNAME
;
512 type
= STATIC_IFNAME
;
515 type
= STATIC_IPV4_GATEWAY
;
517 type
= STATIC_IPV6_GATEWAY
;
521 static_add_route(afi
, safi
, type
, &p
, src_p
, gatep
, ifname
,
522 bh_type
, tag
, distance
, svrf
, nh_svrf
,
523 &snh_label
, table_id
, onlink
);
524 /* Mark as having FRR configuration */
525 vrf_set_user_cfged(svrf
->vrf
);
527 static_delete_route(afi
, safi
, type
, &p
, src_p
, gatep
, ifname
,
528 tag
, distance
, svrf
, &snh_label
, table_id
);
529 /* If no other FRR config for this VRF, mark accordingly. */
530 if (!static_vrf_has_config(svrf
))
531 vrf_reset_user_cfged(svrf
->vrf
);
537 static int static_route(struct vty
*vty
, afi_t afi
, safi_t safi
,
538 const char *negate
, const char *dest_str
,
539 const char *mask_str
, const char *src_str
,
540 const char *gate_str
, const char *ifname
,
541 const char *flag_str
, const char *tag_str
,
542 const char *distance_str
, const char *vrf_name
,
543 const char *label_str
, const char *table_str
)
545 struct static_vrf
*svrf
;
548 svrf
= static_vrf_lookup_by_name(vrf_name
);
550 /* When trying to delete, the VRF must exist. */
551 if (negate
&& !svrf
) {
552 vty_out(vty
, "%% vrf %s is not defined\n", vrf_name
);
553 return CMD_WARNING_CONFIG_FAILED
;
556 /* When trying to create, create the VRF if it doesn't exist.
557 * Note: The VRF isn't active until we hear about it from the kernel.
560 svrf
= static_vty_get_unknown_vrf(vty
, vrf_name
);
562 return CMD_WARNING_CONFIG_FAILED
;
564 return static_route_leak(vty
, svrf
, svrf
, afi
, safi
, negate
, dest_str
,
565 mask_str
, src_str
, gate_str
, ifname
, flag_str
,
566 tag_str
, distance_str
, label_str
, table_str
,
570 void static_config_install_delayed_routes(struct static_vrf
*svrf
)
572 struct listnode
*node
, *nnode
;
573 struct static_hold_route
*shr
;
574 struct static_vrf
*osvrf
, *nh_svrf
;
577 for (ALL_LIST_ELEMENTS(static_list
, node
, nnode
, shr
)) {
578 osvrf
= static_vrf_lookup_by_name(shr
->vrf_name
);
579 nh_svrf
= static_vrf_lookup_by_name(shr
->nhvrf_name
);
581 if (osvrf
!= svrf
&& nh_svrf
!= svrf
)
584 if (osvrf
->vrf
->vrf_id
== VRF_UNKNOWN
585 || nh_svrf
->vrf
->vrf_id
== VRF_UNKNOWN
)
588 installed
= static_route_leak(
589 NULL
, osvrf
, nh_svrf
, shr
->afi
, shr
->safi
, NULL
,
590 shr
->dest_str
, shr
->mask_str
, shr
->src_str
,
591 shr
->gate_str
, shr
->ifname
, shr
->flag_str
, shr
->tag_str
,
592 shr
->distance_str
, shr
->label_str
, shr
->table_str
,
595 if (installed
!= CMD_SUCCESS
)
597 "%s: Attempt to install %s as a route and it was rejected",
598 __PRETTY_FUNCTION__
, shr
->dest_str
);
599 listnode_delete(static_list
, shr
);
600 static_list_delete(shr
);
604 /* Write static route configuration. */
605 int static_config(struct vty
*vty
, struct static_vrf
*svrf
, afi_t afi
,
606 safi_t safi
, const char *cmd
)
608 struct static_hold_route
*shr
;
609 struct listnode
*node
;
611 struct route_node
*rn
;
612 struct static_route
*si
;
613 struct route_table
*stable
;
614 char buf
[SRCDEST2STR_BUFFER
];
617 stable
= svrf
->stable
[afi
][safi
];
621 sprintf(spacing
, "%s%s", (svrf
->vrf
->vrf_id
== VRF_DEFAULT
) ? "" : " ",
625 * Static routes for vrfs not fully inited
627 for (ALL_LIST_ELEMENTS_RO(static_list
, node
, shr
)) {
628 if (shr
->afi
!= afi
|| shr
->safi
!= safi
)
631 if (strcmp(svrf
->vrf
->name
, shr
->vrf_name
) != 0)
634 char dest_str
[PREFIX_STRLEN
];
636 prefix2str(&shr
->dest
, dest_str
, sizeof(dest_str
));
638 vty_out(vty
, "%s ", spacing
);
640 vty_out(vty
, "%s ", dest_str
);
642 vty_out(vty
, "from %s ", shr
->src_str
);
644 vty_out(vty
, "%s ", shr
->gate_str
);
646 vty_out(vty
, "%s ", shr
->ifname
);
648 vty_out(vty
, "%s ", shr
->flag_str
);
650 vty_out(vty
, "tag %s ", shr
->tag_str
);
651 if (shr
->distance_str
)
652 vty_out(vty
, "%s ", shr
->distance_str
);
654 vty_out(vty
, "label %s ", shr
->label_str
);
656 vty_out(vty
, "table %s", shr
->table_str
);
657 if (strcmp(shr
->vrf_name
, shr
->nhvrf_name
) != 0)
658 vty_out(vty
, "nexthop-vrf %s ", shr
->nhvrf_name
);
660 vty_out(vty
, "onlink");
664 for (rn
= route_top(stable
); rn
; rn
= srcdest_route_next(rn
))
665 for (si
= rn
->info
; si
; si
= si
->next
) {
666 vty_out(vty
, "%s %s", spacing
,
667 srcdest_rnode2str(rn
, buf
, sizeof(buf
)));
670 case STATIC_IPV4_GATEWAY
:
671 vty_out(vty
, " %s", inet_ntoa(si
->addr
.ipv4
));
673 case STATIC_IPV6_GATEWAY
:
675 inet_ntop(AF_INET6
, &si
->addr
.ipv6
, buf
,
679 vty_out(vty
, " %s", si
->ifname
);
681 case STATIC_BLACKHOLE
:
682 switch (si
->bh_type
) {
683 case STATIC_BLACKHOLE_DROP
:
684 vty_out(vty
, " blackhole");
686 case STATIC_BLACKHOLE_NULL
:
687 vty_out(vty
, " Null0");
689 case STATIC_BLACKHOLE_REJECT
:
690 vty_out(vty
, " reject");
694 case STATIC_IPV4_GATEWAY_IFNAME
:
695 vty_out(vty
, " %s %s",
696 inet_ntop(AF_INET
, &si
->addr
.ipv4
, buf
,
700 case STATIC_IPV6_GATEWAY_IFNAME
:
701 vty_out(vty
, " %s %s",
702 inet_ntop(AF_INET6
, &si
->addr
.ipv6
, buf
,
709 vty_out(vty
, " tag %" ROUTE_TAG_PRI
, si
->tag
);
711 if (si
->distance
!= ZEBRA_STATIC_DISTANCE_DEFAULT
)
712 vty_out(vty
, " %d", si
->distance
);
714 /* Label information */
715 if (si
->snh_label
.num_labels
)
716 vty_out(vty
, " label %s",
717 mpls_label2str(si
->snh_label
.num_labels
,
718 si
->snh_label
.label
, buf
,
721 if (si
->nh_vrf_id
!= si
->vrf_id
)
722 vty_out(vty
, " nexthop-vrf %s", si
->nh_vrfname
);
725 * table ID from VRF overrides configured
728 svrf
->vrf
->data
.l
.table_id
== RT_TABLE_MAIN
)
729 vty_out(vty
, " table %u", si
->table_id
);
732 vty_out(vty
, " onlink");
741 /* Static unicast routes for multicast RPF lookup. */
742 DEFPY (ip_mroute_dist
,
744 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
747 "Configure static unicast route into MRIB for multicast RPF lookup\n"
748 "IP destination prefix (e.g. 10.0.0.0/8)\n"
750 "Nexthop interface name\n"
753 return static_route(vty
, AFI_IP
, SAFI_MULTICAST
, no
, prefix_str
,
754 NULL
, NULL
, gate_str
, ifname
, NULL
, NULL
,
755 distance_str
, NULL
, NULL
, NULL
);
758 /* Static route configuration. */
759 DEFPY(ip_route_blackhole
,
760 ip_route_blackhole_cmd
,
762 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
763 <reject|blackhole>$flag \
769 |table (1-4294967295) \
772 "Establish static routes\n"
773 "IP destination prefix (e.g. 10.0.0.0/8)\n"
774 "IP destination prefix\n"
775 "IP destination prefix mask\n"
776 "Emit an ICMP unreachable when matched\n"
777 "Silently discard pkts when matched\n"
778 "Set tag for this route\n"
780 "Distance value for this route\n"
783 "Table to configure\n"
784 "The table number to configure\n")
786 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
788 "%% table param only available when running on netns-based vrfs\n");
789 return CMD_WARNING_CONFIG_FAILED
;
792 return static_route(vty
, AFI_IP
, SAFI_UNICAST
, no
, prefix
,
793 mask_str
, NULL
, NULL
, NULL
, flag
, tag_str
,
794 distance_str
, vrf
, label
, table_str
);
797 DEFPY(ip_route_blackhole_vrf
,
798 ip_route_blackhole_vrf_cmd
,
800 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
801 <reject|blackhole>$flag \
806 |table (1-4294967295) \
809 "Establish static routes\n"
810 "IP destination prefix (e.g. 10.0.0.0/8)\n"
811 "IP destination prefix\n"
812 "IP destination prefix mask\n"
813 "Emit an ICMP unreachable when matched\n"
814 "Silently discard pkts when matched\n"
815 "Set tag for this route\n"
817 "Distance value for this route\n"
819 "Table to configure\n"
820 "The table number to configure\n")
822 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
823 struct static_vrf
*svrf
= vrf
->info
;
825 if (table_str
&& !vrf_is_backend_netns()) {
827 "%% table param only available when running on netns-based vrfs\n");
828 return CMD_WARNING_CONFIG_FAILED
;
832 * Coverity is complaining that prefix could
833 * be dereferenced, but we know that prefix will
834 * valid. Add an assert to make it happy
837 return static_route_leak(vty
, svrf
, svrf
, AFI_IP
, SAFI_UNICAST
, no
,
838 prefix
, mask_str
, NULL
, NULL
, NULL
, flag
,
839 tag_str
, distance_str
, label
, table_str
,
843 DEFPY(ip_route_address_interface
,
844 ip_route_address_interface_cmd
,
846 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
848 <INTERFACE|Null0>$ifname \
854 |table (1-4294967295) \
859 "Establish static routes\n"
860 "IP destination prefix (e.g. 10.0.0.0/8)\n"
861 "IP destination prefix\n"
862 "IP destination prefix mask\n"
863 "IP gateway address\n"
864 "IP gateway interface name\n"
866 "Set tag for this route\n"
868 "Distance value for this route\n"
871 "Table to configure\n"
872 "The table number to configure\n"
874 "Treat the nexthop as directly attached to the interface")
876 struct static_vrf
*svrf
;
877 struct static_vrf
*nh_svrf
;
878 const char *flag
= NULL
;
880 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
885 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
887 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
888 return CMD_WARNING_CONFIG_FAILED
;
891 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
893 "%% table param only available when running on netns-based vrfs\n");
894 return CMD_WARNING_CONFIG_FAILED
;
898 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
903 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
904 return CMD_WARNING_CONFIG_FAILED
;
907 return static_route_leak(vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
,
908 prefix
, mask_str
, NULL
, gate_str
, ifname
, flag
,
909 tag_str
, distance_str
, label
, table_str
,
913 DEFPY(ip_route_address_interface_vrf
,
914 ip_route_address_interface_vrf_cmd
,
916 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
918 <INTERFACE|Null0>$ifname \
923 |table (1-4294967295) \
928 "Establish static routes\n"
929 "IP destination prefix (e.g. 10.0.0.0/8)\n"
930 "IP destination prefix\n"
931 "IP destination prefix mask\n"
932 "IP gateway address\n"
933 "IP gateway interface name\n"
935 "Set tag for this route\n"
937 "Distance value for this route\n"
939 "Table to configure\n"
940 "The table number to configure\n"
942 "Treat the nexthop as directly attached to the interface")
944 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
945 const char *flag
= NULL
;
946 struct static_vrf
*svrf
= vrf
->info
;
947 struct static_vrf
*nh_svrf
;
949 if (table_str
&& !vrf_is_backend_netns()) {
951 "%% table param only available when running on netns-based vrfs\n");
952 return CMD_WARNING_CONFIG_FAILED
;
955 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
961 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
966 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
967 return CMD_WARNING_CONFIG_FAILED
;
970 return static_route_leak(vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
,
971 prefix
, mask_str
, NULL
, gate_str
, ifname
, flag
,
972 tag_str
, distance_str
, label
, table_str
,
979 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
980 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
986 |table (1-4294967295) \
990 "Establish static routes\n"
991 "IP destination prefix (e.g. 10.0.0.0/8)\n"
992 "IP destination prefix\n"
993 "IP destination prefix mask\n"
994 "IP gateway address\n"
995 "IP gateway interface name\n"
997 "Set tag for this route\n"
999 "Distance value for this route\n"
1002 "Table to configure\n"
1003 "The table number to configure\n"
1006 struct static_vrf
*svrf
;
1007 struct static_vrf
*nh_svrf
;
1008 const char *flag
= NULL
;
1010 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1012 "%% table param only available when running on netns-based vrfs\n");
1013 return CMD_WARNING_CONFIG_FAILED
;
1016 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1021 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1023 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1024 return CMD_WARNING_CONFIG_FAILED
;
1028 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1033 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1034 return CMD_WARNING_CONFIG_FAILED
;
1037 return static_route_leak(
1038 vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
, prefix
, mask_str
,
1039 NULL
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1046 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
1047 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
1049 tag (1-4294967295) \
1052 |table (1-4294967295) \
1056 "Establish static routes\n"
1057 "IP destination prefix (e.g. 10.0.0.0/8)\n"
1058 "IP destination prefix\n"
1059 "IP destination prefix mask\n"
1060 "IP gateway address\n"
1061 "IP gateway interface name\n"
1063 "Set tag for this route\n"
1065 "Distance value for this route\n"
1067 "Table to configure\n"
1068 "The table number to configure\n"
1071 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1072 struct static_vrf
*svrf
= vrf
->info
;
1073 struct static_vrf
*nh_svrf
;
1074 const char *flag
= NULL
;
1076 if (table_str
&& !vrf_is_backend_netns()) {
1078 "%% table param only available when running on netns-based vrfs\n");
1079 return CMD_WARNING_CONFIG_FAILED
;
1082 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1088 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1093 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1094 return CMD_WARNING_CONFIG_FAILED
;
1097 return static_route_leak(
1098 vty
, svrf
, nh_svrf
, AFI_IP
, SAFI_UNICAST
, no
, prefix
, mask_str
,
1099 NULL
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1103 DEFPY(ipv6_route_blackhole
,
1104 ipv6_route_blackhole_cmd
,
1105 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1106 <reject|blackhole>$flag \
1108 tag (1-4294967295) \
1112 |table (1-4294967295) \
1116 "Establish static routes\n"
1117 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1118 "IPv6 source-dest route\n"
1119 "IPv6 source prefix\n"
1120 "Emit an ICMP unreachable when matched\n"
1121 "Silently discard pkts when matched\n"
1122 "Set tag for this route\n"
1124 "Distance value for this prefix\n"
1127 "Table to configure\n"
1128 "The table number to configure\n")
1130 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1132 "%% table param only available when running on netns-based vrfs\n");
1133 return CMD_WARNING_CONFIG_FAILED
;
1136 return static_route(vty
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
,
1137 NULL
, from_str
, NULL
, NULL
, flag
, tag_str
,
1138 distance_str
, vrf
, label
, table_str
);
1141 DEFPY(ipv6_route_blackhole_vrf
,
1142 ipv6_route_blackhole_vrf_cmd
,
1143 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1144 <reject|blackhole>$flag \
1146 tag (1-4294967295) \
1149 |table (1-4294967295) \
1153 "Establish static routes\n"
1154 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1155 "IPv6 source-dest route\n"
1156 "IPv6 source prefix\n"
1157 "Emit an ICMP unreachable when matched\n"
1158 "Silently discard pkts when matched\n"
1159 "Set tag for this route\n"
1161 "Distance value for this prefix\n"
1163 "Table to configure\n"
1164 "The table number to configure\n")
1166 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1167 struct static_vrf
*svrf
= vrf
->info
;
1169 if (table_str
&& !vrf_is_backend_netns()) {
1171 "%% table param only available when running on netns-based vrfs\n");
1172 return CMD_WARNING_CONFIG_FAILED
;
1176 * Coverity is complaining that prefix could
1177 * be dereferenced, but we know that prefix will
1178 * valid. Add an assert to make it happy
1181 return static_route_leak(
1182 vty
, svrf
, svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1183 from_str
, NULL
, NULL
, flag
, tag_str
, distance_str
, label
,
1187 DEFPY(ipv6_route_address_interface
,
1188 ipv6_route_address_interface_cmd
,
1189 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1191 <INTERFACE|Null0>$ifname \
1193 tag (1-4294967295) \
1197 |table (1-4294967295) \
1203 "Establish static routes\n"
1204 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1205 "IPv6 source-dest route\n"
1206 "IPv6 source prefix\n"
1207 "IPv6 gateway address\n"
1208 "IPv6 gateway interface name\n"
1210 "Set tag for this route\n"
1212 "Distance value for this prefix\n"
1215 "Table to configure\n"
1216 "The table number to configure\n"
1218 "Treat the nexthop as directly attached to the interface")
1220 struct static_vrf
*svrf
;
1221 struct static_vrf
*nh_svrf
;
1222 const char *flag
= NULL
;
1224 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1226 "%% table param only available when running on netns-based vrfs\n");
1227 return CMD_WARNING_CONFIG_FAILED
;
1230 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1232 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1233 return CMD_WARNING_CONFIG_FAILED
;
1237 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1242 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1243 return CMD_WARNING_CONFIG_FAILED
;
1246 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1251 return static_route_leak(
1252 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1253 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1254 table_str
, !!onlink
);
1257 DEFPY(ipv6_route_address_interface_vrf
,
1258 ipv6_route_address_interface_vrf_cmd
,
1259 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1261 <INTERFACE|Null0>$ifname \
1263 tag (1-4294967295) \
1266 |table (1-4294967295) \
1272 "Establish static routes\n"
1273 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1274 "IPv6 source-dest route\n"
1275 "IPv6 source prefix\n"
1276 "IPv6 gateway address\n"
1277 "IPv6 gateway interface name\n"
1279 "Set tag for this route\n"
1281 "Distance value for this prefix\n"
1283 "Table to configure\n"
1284 "The table number to configure\n"
1286 "Treat the nexthop as directly attached to the interface")
1288 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1289 struct static_vrf
*svrf
= vrf
->info
;
1290 struct static_vrf
*nh_svrf
;
1291 const char *flag
= NULL
;
1293 if (table_str
&& !vrf_is_backend_netns()) {
1295 "%% table param only available when running on netns-based vrfs\n");
1296 return CMD_WARNING_CONFIG_FAILED
;
1300 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1305 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1306 return CMD_WARNING_CONFIG_FAILED
;
1309 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1314 return static_route_leak(
1315 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1316 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1317 table_str
, !!onlink
);
1322 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1323 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1325 tag (1-4294967295) \
1329 |table (1-4294967295) \
1334 "Establish static routes\n"
1335 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1336 "IPv6 source-dest route\n"
1337 "IPv6 source prefix\n"
1338 "IPv6 gateway address\n"
1339 "IPv6 gateway interface name\n"
1341 "Set tag for this route\n"
1343 "Distance value for this prefix\n"
1346 "Table to configure\n"
1347 "The table number to configure\n"
1350 struct static_vrf
*svrf
;
1351 struct static_vrf
*nh_svrf
;
1352 const char *flag
= NULL
;
1354 if (table_str
&& vrf
&& !vrf_is_backend_netns()) {
1356 "%% table param only available when running on netns-based vrfs\n");
1357 return CMD_WARNING_CONFIG_FAILED
;
1360 svrf
= static_vty_get_unknown_vrf(vty
, vrf
);
1362 vty_out(vty
, "%% vrf %s is not defined\n", vrf
);
1363 return CMD_WARNING_CONFIG_FAILED
;
1367 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1372 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1373 return CMD_WARNING_CONFIG_FAILED
;
1376 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1381 return static_route_leak(
1382 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1383 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1387 DEFPY(ipv6_route_vrf
,
1389 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1390 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1392 tag (1-4294967295) \
1395 |table (1-4294967295) \
1400 "Establish static routes\n"
1401 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1402 "IPv6 source-dest route\n"
1403 "IPv6 source prefix\n"
1404 "IPv6 gateway address\n"
1405 "IPv6 gateway interface name\n"
1407 "Set tag for this route\n"
1409 "Distance value for this prefix\n"
1411 "Table to configure\n"
1412 "The table number to configure\n"
1415 VTY_DECLVAR_CONTEXT(vrf
, vrf
);
1416 struct static_vrf
*svrf
= vrf
->info
;
1417 struct static_vrf
*nh_svrf
;
1418 const char *flag
= NULL
;
1420 if (table_str
&& !vrf_is_backend_netns()) {
1422 "%% table param only available when running on netns-based vrfs\n");
1423 return CMD_WARNING_CONFIG_FAILED
;
1427 nh_svrf
= static_vty_get_unknown_vrf(vty
, nexthop_vrf
);
1432 vty_out(vty
, "%% nexthop vrf %s is not defined\n", nexthop_vrf
);
1433 return CMD_WARNING_CONFIG_FAILED
;
1436 if (ifname
&& !strncasecmp(ifname
, "Null0", 5)) {
1441 return static_route_leak(
1442 vty
, svrf
, nh_svrf
, AFI_IP6
, SAFI_UNICAST
, no
, prefix_str
, NULL
,
1443 from_str
, gate_str
, ifname
, flag
, tag_str
, distance_str
, label
,
1446 DEFPY(debug_staticd
,
1448 "[no] debug static [{events$events}]",
1454 /* If no specific category, change all */
1455 if (strmatch(argv
[argc
- 1]->text
, "static"))
1456 static_debug_set(vty
->node
, !no
, true);
1458 static_debug_set(vty
->node
, !no
, !!events
);
1463 DEFUN_NOSH (show_debugging_static
,
1464 show_debugging_static_cmd
,
1465 "show debugging [static]",
1468 "Static Information\n")
1470 vty_out(vty
, "Staticd debugging status\n");
1472 static_debug_status_write(vty
);
1477 static struct cmd_node debug_node
= {DEBUG_NODE
, "", 1};
1479 void static_vty_init(void)
1481 install_node(&debug_node
, static_config_write_debug
);
1483 install_element(CONFIG_NODE
, &ip_mroute_dist_cmd
);
1485 install_element(CONFIG_NODE
, &ip_route_blackhole_cmd
);
1486 install_element(VRF_NODE
, &ip_route_blackhole_vrf_cmd
);
1487 install_element(CONFIG_NODE
, &ip_route_address_interface_cmd
);
1488 install_element(VRF_NODE
, &ip_route_address_interface_vrf_cmd
);
1489 install_element(CONFIG_NODE
, &ip_route_cmd
);
1490 install_element(VRF_NODE
, &ip_route_vrf_cmd
);
1492 install_element(CONFIG_NODE
, &ipv6_route_blackhole_cmd
);
1493 install_element(VRF_NODE
, &ipv6_route_blackhole_vrf_cmd
);
1494 install_element(CONFIG_NODE
, &ipv6_route_address_interface_cmd
);
1495 install_element(VRF_NODE
, &ipv6_route_address_interface_vrf_cmd
);
1496 install_element(CONFIG_NODE
, &ipv6_route_cmd
);
1497 install_element(VRF_NODE
, &ipv6_route_vrf_cmd
);
1499 install_element(VIEW_NODE
, &show_debugging_static_cmd
);
1500 install_element(VIEW_NODE
, &debug_staticd_cmd
);
1501 install_element(CONFIG_NODE
, &debug_staticd_cmd
);
1503 static_list
= list_new();
1504 static_list
->cmp
= (int (*)(void *, void *))static_list_compare
;
1505 static_list
->del
= (void (*)(void *))static_list_delete
;