summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--bgpd/bgp_clist.c109
-rw-r--r--bgpd/bgp_debug.c228
-rw-r--r--bgpd/bgp_route.c17
-rw-r--r--bgpd/bgp_vty.c5
-rwxr-xr-xconfigure.ac1
-rw-r--r--debianpkg/control6
-rw-r--r--debianpkg/frr.logrotate2
-rw-r--r--doc/Makefile.am6
-rw-r--r--doc/manpages/common-options.rst1
-rw-r--r--doc/manpages/conf.py1
-rw-r--r--doc/manpages/defines.rst2
-rw-r--r--doc/manpages/index.rst1
-rw-r--r--doc/manpages/staticd.rst38
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/routemap.rst5
-rw-r--r--doc/user/setup.rst2
-rw-r--r--doc/user/static.rst130
-rw-r--r--doc/user/zebra.rst170
-rw-r--r--isisd/isis_lsp.c21
-rw-r--r--isisd/isis_mt.c12
-rw-r--r--isisd/isis_mt.h8
-rw-r--r--isisd/isis_pdu.c9
-rw-r--r--isisd/isis_redist.c105
-rw-r--r--isisd/isis_redist.h7
-rw-r--r--isisd/isis_route.c262
-rw-r--r--isisd/isis_route.h20
-rw-r--r--isisd/isis_spf.c345
-rw-r--r--isisd/isis_spf.h3
-rw-r--r--isisd/isis_tlvs.c20
-rw-r--r--isisd/isis_tlvs.h4
-rw-r--r--isisd/isis_zebra.c30
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c90
-rw-r--r--isisd/isisd.h15
-rw-r--r--lib/command.h1
-rw-r--r--lib/libfrr.c5
-rw-r--r--lib/srcdest_table.c15
-rw-r--r--lib/srcdest_table.h3
-rw-r--r--lib/zebra.h17
-rw-r--r--pimd/pim_nht.c2
-rw-r--r--pimd/pim_rp.c6
-rw-r--r--redhat/daemons2
-rwxr-xr-xredhat/frr.init2
-rw-r--r--redhat/frr.spec.in4
-rw-r--r--staticd/.gitignore2
-rw-r--r--staticd/Makefile10
-rw-r--r--staticd/static_main.c152
-rw-r--r--staticd/static_memory.c28
-rw-r--r--staticd/static_memory.h28
-rw-r--r--staticd/static_nht.c81
-rw-r--r--staticd/static_nht.h25
-rw-r--r--staticd/static_routes.c506
-rw-r--r--staticd/static_routes.h (renamed from zebra/zebra_static.h)68
-rw-r--r--staticd/static_vrf.c196
-rw-r--r--staticd/static_vrf.h38
-rw-r--r--staticd/static_vty.c1414
-rw-r--r--staticd/static_vty.h28
-rw-r--r--staticd/static_zebra.c375
-rw-r--r--staticd/static_zebra.h30
-rw-r--r--staticd/staticd.conf.sample3
-rw-r--r--staticd/subdir.am33
-rw-r--r--tests/isisd/test_fuzz_isis_tlv_tests.h.gzbin262877 -> 233035 bytes
-rw-r--r--tests/isisd/test_isis_vertex_queue.c20
-rwxr-xr-xtools/checkpatch.sh9
-rw-r--r--tools/etc/frr/daemons.conf1
-rwxr-xr-xtools/frr23
-rw-r--r--vtysh/Makefile.am4
-rw-r--r--vtysh/vtysh.c1
-rw-r--r--vtysh/vtysh.h3
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/if_netlink.c4
-rw-r--r--zebra/interface.c14
-rw-r--r--zebra/kernel_socket.c8
-rw-r--r--zebra/redistribute.c2
-rw-r--r--zebra/rib.h8
-rw-r--r--zebra/rt_netlink.c18
-rw-r--r--zebra/rule_netlink.c2
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/zapi_msg.c8
-rw-r--r--zebra/zebra_mpls_vty.c1
-rw-r--r--zebra/zebra_rib.c36
-rw-r--r--zebra/zebra_rnh.c192
-rw-r--r--zebra/zebra_rnh.h23
-rw-r--r--zebra/zebra_static.c852
-rw-r--r--zebra/zebra_vrf.c68
-rw-r--r--zebra/zebra_vrf.h6
-rw-r--r--zebra/zebra_vty.c1417
88 files changed, 4050 insertions, 3428 deletions
diff --git a/Makefile.am b/Makefile.am
index f9fb231962..8c96f39f39 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,7 @@ include eigrpd/subdir.am
include sharpd/subdir.am
include pimd/subdir.am
include pbrd/subdir.am
+include staticd/subdir.am
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
@BGPD@ \
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index fec4397b73..3a93db1ac6 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -332,141 +332,70 @@ community_list_entry_lookup(struct community_list *list, const void *arg,
static char *community_str_get(struct community *com, int i)
{
- int len;
uint32_t comval;
uint16_t as;
uint16_t val;
char *str;
- char *pnt;
memcpy(&comval, com_nthval(com, i), sizeof(uint32_t));
comval = ntohl(comval);
switch (comval) {
case COMMUNITY_INTERNET:
- len = strlen(" internet");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet");
break;
case COMMUNITY_GSHUT:
- len = strlen(" graceful-shutdown");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown");
break;
case COMMUNITY_ACCEPT_OWN:
- len = strlen(" accept-own");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own");
break;
case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
- len = strlen(" route-filter-translated-v4");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR,
+ "route-filter-translated-v4");
break;
case COMMUNITY_ROUTE_FILTER_v4:
- len = strlen(" route-filter-v4");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v4");
break;
case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
- len = strlen(" route-filter-translated-v6");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR,
+ "route-filter-translated-v6");
break;
case COMMUNITY_ROUTE_FILTER_v6:
- len = strlen(" route-filter-v6");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v6");
break;
case COMMUNITY_LLGR_STALE:
- len = strlen(" llgr-stale");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "llgr-stale");
break;
case COMMUNITY_NO_LLGR:
- len = strlen(" no-llgr");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-llgr");
break;
case COMMUNITY_ACCEPT_OWN_NEXTHOP:
- len = strlen(" accept-own-nexthop");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own-nexthop");
break;
case COMMUNITY_BLACKHOLE:
- len = strlen(" blackhole");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "blackhole");
break;
case COMMUNITY_NO_EXPORT:
- len = strlen(" no-export");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-export");
break;
case COMMUNITY_NO_ADVERTISE:
- len = strlen(" no-advertise");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-advertise");
break;
case COMMUNITY_LOCAL_AS:
- len = strlen(" local-AS");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "local-AS");
break;
case COMMUNITY_NO_PEER:
- len = strlen(" no-peer");
- break;
- default:
- len = strlen(" 65536:65535");
- break;
- }
-
- /* Allocate memory. */
- str = pnt = XMALLOC(MTYPE_COMMUNITY_STR, len);
-
- switch (comval) {
- case COMMUNITY_INTERNET:
- strcpy(pnt, "internet");
- pnt += strlen("internet");
- break;
- case COMMUNITY_GSHUT:
- strcpy(pnt, "graceful-shutdown");
- pnt += strlen("graceful-shutdown");
- break;
- case COMMUNITY_ACCEPT_OWN:
- strcpy(pnt, "accept-own");
- pnt += strlen("accept-own");
- break;
- case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
- strcpy(pnt, "route-filter-translated-v4");
- pnt += strlen("route-filter-translated-v4");
- break;
- case COMMUNITY_ROUTE_FILTER_v4:
- strcpy(pnt, "route-filter-v4");
- pnt += strlen("route-filter-v4");
- break;
- case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
- strcpy(pnt, "route-filter-translated-v6");
- pnt += strlen("route-filter-translated-v6");
- break;
- case COMMUNITY_ROUTE_FILTER_v6:
- strcpy(pnt, "route-filter-v6");
- pnt += strlen("route-filter-v6");
- break;
- case COMMUNITY_LLGR_STALE:
- strcpy(pnt, "llgr-stale");
- pnt += strlen("llgr-stale");
- break;
- case COMMUNITY_NO_LLGR:
- strcpy(pnt, "no-llgr");
- pnt += strlen("no-llgr");
- break;
- case COMMUNITY_ACCEPT_OWN_NEXTHOP:
- strcpy(pnt, "accept-own-nexthop");
- pnt += strlen("accept-own-nexthop");
- break;
- case COMMUNITY_BLACKHOLE:
- strcpy(pnt, "blackhole");
- pnt += strlen("blackhole");
- break;
- case COMMUNITY_NO_EXPORT:
- strcpy(pnt, "no-export");
- pnt += strlen("no-export");
- break;
- case COMMUNITY_NO_ADVERTISE:
- strcpy(pnt, "no-advertise");
- pnt += strlen("no-advertise");
- break;
- case COMMUNITY_LOCAL_AS:
- strcpy(pnt, "local-AS");
- pnt += strlen("local-AS");
- break;
- case COMMUNITY_NO_PEER:
- strcpy(pnt, "no-peer");
- pnt += strlen("no-peer");
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-peer");
break;
default:
+ str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
- sprintf(pnt, "%u:%d", as, val);
- pnt += strlen(pnt);
+ snprintf(str, strlen(str), "%u:%d", as, val);
break;
}
- *pnt = '\0';
-
return str;
}
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 268356c7c3..c7c36882af 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -43,6 +43,7 @@
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_private.h"
+#include "bgpd/bgp_evpn_vty.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_flowspec.h"
@@ -217,10 +218,12 @@ static void bgp_debug_list_free(struct list *list)
}
}
-/* Print the desc along with a list of peers/prefixes this debug is
- * enabled for */
+/*
+ * Print the desc along with a list of peers/prefixes this debug is
+ * enabled for
+ */
static void bgp_debug_list_print(struct vty *vty, const char *desc,
- struct list *list, uint8_t evpn_dbg)
+ struct list *list)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
@@ -234,16 +237,11 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc,
if (filter->host)
vty_out(vty, " %s", filter->host);
- if (filter->p) {
- if (!evpn_dbg) {
- vty_out(vty, " %s",
- prefix2str(filter->p, buf,
- sizeof(buf)));
- } else {
- if (filter->p->family == AF_EVPN)
- bgp_debug_print_evpn_prefix(vty,
- "", filter->p);
- }
+ if (filter->p && filter->p->family == AF_EVPN)
+ bgp_debug_print_evpn_prefix(vty, "", filter->p);
+ else if (filter->p) {
+ prefix2str(filter->p, buf, sizeof(buf));
+ vty_out(vty, " %s", buf);
}
}
}
@@ -251,11 +249,12 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc,
vty_out(vty, "\n");
}
-/* Print the command to enable the debug for each peer/prefix this debug is
+/*
+ * Print the command to enable the debug for each peer/prefix this debug is
* enabled for
*/
static int bgp_debug_list_conf_print(struct vty *vty, const char *desc,
- struct list *list, uint8_t evpn_dbg)
+ struct list *list)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
@@ -269,19 +268,14 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc,
write++;
}
-
- if (filter->p) {
- if (!evpn_dbg) {
- vty_out(vty, "%s %s\n", desc,
- prefix2str(filter->p, buf,
- sizeof(buf)));
- write++;
- } else {
- if (filter->p->family == AF_EVPN)
- bgp_debug_print_evpn_prefix(vty,
- desc, filter->p);
- write++;
- }
+ if (filter->p && filter->p->family == AF_EVPN) {
+ bgp_debug_print_evpn_prefix(vty, desc,
+ filter->p);
+ write++;
+ } else if (filter->p) {
+ prefix2str(filter->p, buf, sizeof(buf));
+ vty_out(vty, "%s %s\n", desc, buf);
+ write++;
}
}
}
@@ -614,44 +608,32 @@ static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv,
argv_p = *argv_pp;
- if (argv_find(argv, argc, "type", &type_idx) == 0)
- return CMD_WARNING;
-
- if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
+ if (argv_find(argv, argc, "macip", &type_idx))
evpn_type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
+ else if (argv_find(argv, argc, "multicast", &type_idx))
evpn_type = BGP_EVPN_IMET_ROUTE;
- else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+ else if (argv_find(argv, argc, "prefix", &type_idx))
evpn_type = BGP_EVPN_IP_PREFIX_ROUTE;
else
evpn_type = 0;
if (evpn_type == BGP_EVPN_MAC_IP_ROUTE) {
memset(&ip, 0, sizeof(struct ipaddr));
- /* get the ip if specified */
- if (argv_find(argv, argc, "ip", &ip_idx)) {
- if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) {
- vty_out(vty, "%% Malformed IP address\n");
- return CMD_WARNING;
- }
- }
+
argv_find(argv, argc, "mac", &mac_idx);
- if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) {
- vty_out(vty, "%% Malformed MAC address\n");
- return CMD_WARNING;
- }
+ prefix_str2mac(argv[mac_idx + 1]->arg, &mac);
+
+ argv_find(argv, argc, "ip", &ip_idx);
+ str2ipaddr(argv[ip_idx + 1]->arg, &ip);
build_evpn_type2_prefix((struct prefix_evpn *)argv_p,
&mac, &ip);
} else if (evpn_type == BGP_EVPN_IMET_ROUTE) {
memset(&ip, 0, sizeof(struct ipaddr));
- /* get the ip if specified */
- if (argv_find(argv, argc, "ip", &ip_idx)) {
- if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) {
- vty_out(vty, "%% Malformed IP address\n");
- return CMD_WARNING;
- }
- }
+
+ argv_find(argv, argc, "ip", &ip_idx);
+ str2ipaddr(argv[ip_idx + 1]->arg, &ip);
+
build_evpn_type3_prefix((struct prefix_evpn *)argv_p,
ip.ipaddr_v4);
} else if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
@@ -1398,55 +1380,51 @@ DEFUN (no_debug_bgp_update_direct_peer,
DEFPY (debug_bgp_update_prefix_afi_safi,
debug_bgp_update_prefix_afi_safi_cmd,
- "debug bgp updates prefix <l2vpn>$afi <evpn>$safi type <macip mac WORD [ip WORD]|multicast ip WORD |prefix ip WORD>",
+ "debug bgp updates prefix l2vpn$afi evpn$safi type <macip mac <M:A:C|M:A:C/M> [ip <A.B.C.D|X:X::X:X>]|multicast ip <A.B.C.D|X:X::X:X>|prefix ip <A.B.C.D/M|X:X::X:X/M>>",
DEBUG_STR
BGP_STR
"BGP updates\n"
"Specify a prefix to debug\n"
- "l2vpn\n"
- "evpn\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
"Specify EVPN Route type\n"
"MAC-IP (Type-2) route\n"
- "MAC\n"
- "MAC address (e.g., 00:e0:ec:20:12:62)\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n"
+ MAC_STR MAC_STR MAC_STR
+ IP_STR
+ "IPv4 address\n"
+ "IPv6 address\n"
"Multicast (Type-3) route\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n"
+ IP_STR
+ "IPv4 address\n"
+ "IPv6 address\n"
"Prefix (Type-5) route\n"
- "IP\n"
- "Prefix route\n")
+ IP_STR
+ "IPv4 prefix\n"
+ "IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
struct prefix *argv_p;
int ret = CMD_SUCCESS;
- afi_t afiz;
- safi_t safiz;
+ char buf[PREFIX2STR_BUFFER];
argv_p = prefix_new();
- afiz = bgp_vty_afi_from_str(afi);
- safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST;
-
- /* check for evpn route type */
- if (afiz == AFI_L2VPN && safiz == SAFI_EVPN) {
- ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS)
- goto cleanup;
- } else {
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
+ if (ret != CMD_SUCCESS) {
+ prefix_free(argv_p);
+ return ret;
}
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
+ prefix2str(argv_p, buf, sizeof(buf));
+
if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) {
vty_out(vty,
"BGP updates debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
- goto cleanup;
+ buf);
+ prefix_free(argv_p);
+ return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
@@ -1455,59 +1433,50 @@ DEFPY (debug_bgp_update_prefix_afi_safi,
DEBUG_ON(update, UPDATE_PREFIX);
} else {
TERM_DEBUG_ON(update, UPDATE_PREFIX);
- vty_out(vty, "BGP updates debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP updates debugging is on for %s\n", buf);
}
-cleanup:
prefix_free(argv_p);
- return ret;
+ return CMD_SUCCESS;
}
DEFPY (no_debug_bgp_update_prefix_afi_safi,
no_debug_bgp_update_prefix_afi_safi_cmd,
- "no debug bgp updates prefix <l2vpn>$afi <evpn>$safi type <macip mac WORD [ip WORD]|multicast ip WORD |prefix ip WORD>",
+ "no debug bgp updates prefix l2vpn$afi evpn$safi type <macip mac <M:A:C|M:A:C/M> [ip <A.B.C.D|X:X::X:X>]|multicast ip <A.B.C.D|X:X::X:X>|prefix ip <A.B.C.D/M|X:X::X:X/M>>",
NO_STR
DEBUG_STR
BGP_STR
"BGP updates\n"
"Specify a prefix to debug\n"
- "l2vpn\n"
- "evpn\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
"Specify EVPN Route type\n"
"MAC-IP (Type-2) route\n"
- "MAC\n"
- "MAC address (e.g., 00:e0:ec:20:12:62)\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n"
+ MAC_STR MAC_STR MAC_STR
+ IP_STR
+ "IPv4 address\n"
+ "IPv6 address\n"
"Multicast (Type-3) route\n"
- "IP\n"
- "IP address (IPv4 or IPv6)\n"
+ IP_STR
+ "IPv4 address\n"
+ "IPv6 address\n"
"Prefix (Type-5) route\n"
- "IP\n"
- "Prefix route\n")
+ IP_STR
+ "IPv4 prefix\n"
+ "IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 5;
struct prefix *argv_p;
- int found_prefix = 0;
+ bool found_prefix = false;
int ret = CMD_SUCCESS;
- afi_t afiz;
- safi_t safiz;
+ char buf[PREFIX2STR_BUFFER];
argv_p = prefix_new();
- afiz = bgp_vty_afi_from_str(afi);
- safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST;
-
- /* check for evpn route type */
- if (afiz == AFI_L2VPN && safiz == SAFI_EVPN) {
- ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS)
- goto cleanup;
- } else {
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
+ if (ret != CMD_SUCCESS) {
+ prefix_free(argv_p);
+ return ret;
}
if (bgp_debug_update_prefixes
@@ -1526,14 +1495,14 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi,
}
}
+ prefix2str(argv_p, buf, sizeof(buf));
+
if (found_prefix)
- vty_out(vty, "BGP updates debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP updates debugging is off for %s\n", buf);
else
vty_out(vty, "BGP updates debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ buf);
-cleanup:
prefix_free(argv_p);
return ret;
@@ -2090,16 +2059,16 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(bestpath, BESTPATH))
bgp_debug_list_print(vty, " BGP bestpath debugging is on",
- bgp_debug_bestpath_prefixes, 0);
+ bgp_debug_bestpath_prefixes);
if (BGP_DEBUG(keepalive, KEEPALIVE))
bgp_debug_list_print(vty, " BGP keepalives debugging is on",
- bgp_debug_keepalive_peers, 0);
+ bgp_debug_keepalive_peers);
if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
bgp_debug_list_print(vty,
" BGP neighbor-events debugging is on",
- bgp_debug_neighbor_events_peers, 0);
+ bgp_debug_neighbor_events_peers);
if (BGP_DEBUG(nht, NHT))
vty_out(vty, " BGP next-hop tracking debugging is on\n");
@@ -2109,21 +2078,21 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(update, UPDATE_PREFIX))
bgp_debug_list_print(vty, " BGP updates debugging is on",
- bgp_debug_update_prefixes, 1);
+ bgp_debug_update_prefixes);
if (BGP_DEBUG(update, UPDATE_IN))
bgp_debug_list_print(vty,
" BGP updates debugging is on (inbound)",
- bgp_debug_update_in_peers, 0);
+ bgp_debug_update_in_peers);
if (BGP_DEBUG(update, UPDATE_OUT))
bgp_debug_list_print(vty,
" BGP updates debugging is on (outbound)",
- bgp_debug_update_out_peers, 0);
+ bgp_debug_update_out_peers);
if (BGP_DEBUG(zebra, ZEBRA))
bgp_debug_list_print(vty, " BGP zebra debugging is on",
- bgp_debug_zebra_prefixes, 0);
+ bgp_debug_zebra_prefixes);
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
vty_out(vty, " BGP allow martian next hop debugging is on\n");
@@ -2229,20 +2198,18 @@ static int bgp_config_write_debug(struct vty *vty)
if (CONF_BGP_DEBUG(bestpath, BESTPATH)) {
write += bgp_debug_list_conf_print(vty, "debug bgp bestpath",
- bgp_debug_bestpath_prefixes,
- 0);
+ bgp_debug_bestpath_prefixes);
}
if (CONF_BGP_DEBUG(keepalive, KEEPALIVE)) {
write += bgp_debug_list_conf_print(vty, "debug bgp keepalives",
- bgp_debug_keepalive_peers,
- 0);
+ bgp_debug_keepalive_peers);
}
if (CONF_BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) {
write += bgp_debug_list_conf_print(
vty, "debug bgp neighbor-events",
- bgp_debug_neighbor_events_peers, 0);
+ bgp_debug_neighbor_events_peers);
}
if (CONF_BGP_DEBUG(nht, NHT)) {
@@ -2258,20 +2225,17 @@ static int bgp_config_write_debug(struct vty *vty)
if (CONF_BGP_DEBUG(update, UPDATE_PREFIX)) {
write += bgp_debug_list_conf_print(vty,
"debug bgp updates prefix",
- bgp_debug_update_prefixes,
- 1);
+ bgp_debug_update_prefixes);
}
if (CONF_BGP_DEBUG(update, UPDATE_IN)) {
write += bgp_debug_list_conf_print(vty, "debug bgp updates in",
- bgp_debug_update_in_peers,
- 0);
+ bgp_debug_update_in_peers);
}
if (CONF_BGP_DEBUG(update, UPDATE_OUT)) {
write += bgp_debug_list_conf_print(vty, "debug bgp updates out",
- bgp_debug_update_out_peers,
- 0);
+ bgp_debug_update_out_peers);
}
if (CONF_BGP_DEBUG(zebra, ZEBRA)) {
@@ -2282,7 +2246,7 @@ static int bgp_config_write_debug(struct vty *vty)
} else {
write += bgp_debug_list_conf_print(
vty, "debug bgp zebra prefix",
- bgp_debug_zebra_prefixes, 0);
+ bgp_debug_zebra_prefixes);
}
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e1924f0e9a..b66a913f54 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5201,8 +5201,8 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
if (routermac) {
bgp_static->router_mac =
XCALLOC(MTYPE_ATTR, ETH_ALEN + 1);
- prefix_str2mac(routermac,
- bgp_static->router_mac);
+ (void)prefix_str2mac(routermac,
+ bgp_static->router_mac);
}
if (gwip)
prefix_copy(&bgp_static->gatewayIp, &gw_ip);
@@ -9560,7 +9560,7 @@ ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval)
unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG);
unsigned long res = (newtot * TALLY_SIGFIG) / count;
unsigned long ret = newtot / count;
-
+
if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2))
return ret + 1;
else
@@ -9654,7 +9654,7 @@ static int bgp_table_stats_walker(struct thread *t)
ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops;
ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size;
#if 0
- ts->counts[BGP_STATS_ASPATH_AVGHOPS]
+ ts->counts[BGP_STATS_ASPATH_AVGHOPS]
= ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT],
ts->counts[BGP_STATS_ASPATH_AVGHOPS],
hops);
@@ -10142,9 +10142,9 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
json_scode);
json_object_object_add(json, "bgpOriginCodes",
json_ocode);
- json_object_string_add(json,
- "bgpOriginatingDefaultNetwork",
- "0.0.0.0");
+ json_object_string_add(
+ json, "bgpOriginatingDefaultNetwork",
+ (afi == AFI_IP) ? "0.0.0.0/0" : "::/0");
} else {
vty_out(vty, "BGP table version is %" PRIu64
", local router ID is %s, vrf id ",
@@ -10158,7 +10158,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
vty_out(vty, BGP_SHOW_NCODE_HEADER);
vty_out(vty, BGP_SHOW_OCODE_HEADER);
- vty_out(vty, "Originating default network 0.0.0.0\n\n");
+ vty_out(vty, "Originating default network %s\n\n",
+ (afi == AFI_IP) ? "0.0.0.0/0" : "::/0");
}
header1 = 0;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 1ddc60c20e..e3efbbf252 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9239,8 +9239,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json,
/* BGP Version. */
vty_out(vty, " BGP version 4");
- vty_out(vty, ", remote router ID %s\n",
+ vty_out(vty, ", remote router ID %s",
inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1)));
+ vty_out(vty, ", local router ID %s\n",
+ inet_ntop(AF_INET, &bgp->router_id, buf1,
+ sizeof(buf1)));
/* Confederation */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
diff --git a/configure.ac b/configure.ac
index a155a12ba7..f65b1640d2 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1409,6 +1409,7 @@ AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no")
AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no")
AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no")
AM_CONDITIONAL(SHARPD, test "${enable_sharpd}" = "yes")
+AM_CONDITIONAL(STATICD, test "${enable_staticd}" != "no")
if test "${enable_bgp_announce}" = "no";then
AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra)
diff --git a/debianpkg/control b/debianpkg/control
index 468581045b..71c412a960 100644
--- a/debianpkg/control
+++ b/debianpkg/control
@@ -4,7 +4,7 @@ Priority: optional
Maintainer: Nobody <nobody@frrouting.org>
Uploaders: Nobody <nobody@frrouting.org>
XSBC-Original-Maintainer: <maintainers@frrouting.org>
-Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx, libpython-dev
+Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx, libpython-dev, install-info
Standards-Version: 3.9.6
Homepage: http://www.frrouting.org/
@@ -29,9 +29,9 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version})
Priority: extra
Section: debug
Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols)
- This package provides debugging symbols for all binary packages built
+ This package provides debugging symbols for all binary packages built
from frr source package. It's highly recommended to have this package
- installed before reporting any FRR crashes to either FRR developers or
+ installed before reporting any FRR crashes to either FRR developers or
Debian package maintainers.
Package: frr-doc
diff --git a/debianpkg/frr.logrotate b/debianpkg/frr.logrotate
index 2b4acd89c7..750b9aef13 100644
--- a/debianpkg/frr.logrotate
+++ b/debianpkg/frr.logrotate
@@ -17,7 +17,7 @@
# open, as well as the daemons, so always signal the daemons.
# It's safe, a NOP if (only) syslog is being used.
for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd \
- pimd ripd ripngd zebra ; do
+ pimd ripd ripngd zebra staticd ; do
if [ -e /var/run/frr/$i.pid ] ; then
pids="$pids $(cat /var/run/frr/$i.pid)"
fi
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 19aab63ea3..da8ac3d050 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -86,6 +86,10 @@ if SHARPD
man_MANS += $(MANPAGE_BUILDDIR)/sharpd.8
endif
+if STATICD
+man_MANS += $(MANPAGE_BUILDDIR)/staticd.8
+endif
+
# Automake is particular about manpages. It is aware of them and has some
# special facilities for handling them, but it assumes that manpages are always
# given in groff source and so these facilities are limited to simply
@@ -151,6 +155,7 @@ EXTRA_DIST = frr-sphinx.mk \
manpages/pbrd.rst \
manpages/ripngd.rst \
manpages/sharpd.rst \
+ manpages/staticd.rst \
manpages/vtysh.rst \
manpages/watchfrr.rst \
manpages/zebra.rst \
@@ -224,6 +229,7 @@ EXTRA_DIST = frr-sphinx.mk \
user/sharp.rst \
user/snmp.rst \
user/snmptrap.rst \
+ user/static.rst \
user/Useful_Sysctl_Settings.md \
user/vnc.rst \
user/vtysh.rst \
diff --git a/doc/manpages/common-options.rst b/doc/manpages/common-options.rst
index e9241b7438..1b2eb18dea 100644
--- a/doc/manpages/common-options.rst
+++ b/doc/manpages/common-options.rst
@@ -123,6 +123,7 @@ These following options control the daemon's VTY (interactive command line) inte
ldpd 2612
eigrpd 2613
pbrd 2615
+ staticd 2616
Port 2607 is used for ospfd's Opaque LSA API, while port 2600 is used for the (insecure) TCP-ZEBRA interface.
diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py
index 2b0f7e3893..4d5797f613 100644
--- a/doc/manpages/conf.py
+++ b/doc/manpages/conf.py
@@ -324,6 +324,7 @@ man_pages = [
('pimd', 'pimd', fwfrr.format("a PIM "), [], 8),
('pbrd', 'pbrd', fwfrr.format("a PBR "), [], 8),
('sharpd', 'sharpd', fwfrr.format("a SHARP "), [], 8),
+ ('staticd', 'staticd', fwfrr.format("a static route manager "), [], 8),
('mtracebis', 'mtracebis', "a multicast trace client", [], 8),
('ripd', 'ripd', fwfrr.format("a RIP "), [], 8),
('ripngd', 'ripngd', fwfrr.format("a RIPNG "), [], 8),
diff --git a/doc/manpages/defines.rst b/doc/manpages/defines.rst
index 21c3790afa..e1f7ec4ce8 100644
--- a/doc/manpages/defines.rst
+++ b/doc/manpages/defines.rst
@@ -1,3 +1,3 @@
.. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
.. |synopsis-options-hv| replace:: [-h] [-v]
-.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), mtracebis(8)
+.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8)
diff --git a/doc/manpages/index.rst b/doc/manpages/index.rst
index 6d3f3aae55..e95dd26e84 100644
--- a/doc/manpages/index.rst
+++ b/doc/manpages/index.rst
@@ -20,6 +20,7 @@
ripd
ripngd
sharpd
+ staticd
watchfrr
zebra
vtysh
diff --git a/doc/manpages/staticd.rst b/doc/manpages/staticd.rst
new file mode 100644
index 0000000000..ccbcf32e36
--- /dev/null
+++ b/doc/manpages/staticd.rst
@@ -0,0 +1,38 @@
+*******
+STATICD
+*******
+
+.. include:: defines.rst
+.. |DAEMON| replace:: staticd
+
+SYNOPSIS
+========
+|DAEMON| |synopsis-options-hv|
+
+|DAEMON| |synopsis-options|
+
+DESCRIPTION
+===========
+|DAEMON| is a routing component that works with the FRRouting engine.
+
+OPTIONS
+=======
+OPTIONS available for the |DAEMON| command:
+
+.. include:: common-options.rst
+
+FILES
+=====
+
+|INSTALL_PREFIX_SBIN|/|DAEMON|
+ The default location of the |DAEMON| binary.
+
+|INSTALL_PREFIX_ETC|/|DAEMON|.conf
+ The default location of the |DAEMON| config file.
+
+$(PWD)/|DAEMON|.log
+ If the |DAEMON| process is configured to output logs to a file, then you will find this file in the directory where you started |DAEMON|.
+
+.. include:: epilogue.rst
+
+
diff --git a/doc/user/index.rst b/doc/user/index.rst
index 746cc1c32d..14688e05d8 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -52,6 +52,7 @@ Protocols
ripd
ripngd
sharp
+ static
vnc
########
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 8080e001f1..57b4875e23 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -277,6 +277,11 @@ Route Map Set Command
Set the BGP-4+ link local IPv6 nexthop address.
+.. index:: set origin ORIGIN <egp|igp|incomplete>
+.. clicmd:: set origin ORIGIN <egp|igp|incomplete>
+
+ Set BGP route origin.
+
.. _route-map-call-command:
Route Map Call Command
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index 1bbbe36931..e9fd44a347 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -29,6 +29,7 @@ systemd. The file initially looks like this:
eigrpd=no
babeld=no
sharpd=no
+ staticd=no
pbrd=no
To enable a particular daemon, simply change the corresponding 'no' to 'yes'.
@@ -63,6 +64,7 @@ This file has several parts. Here is an example:
eigrpd_options=" --daemon -A 127.0.0.1"
babeld_options=" --daemon -A 127.0.0.1"
sharpd_options=" --daemon -A 127.0.0.1"
+ staticd_options=" --daemon -A 127.0.0.1"
pbrd_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
diff --git a/doc/user/static.rst b/doc/user/static.rst
new file mode 100644
index 0000000000..6755c809eb
--- /dev/null
+++ b/doc/user/static.rst
@@ -0,0 +1,130 @@
+.. _static:
+
+******
+STATIC
+******
+
+:abbr:`STATIC` is a daemon that handles the installation and deletion
+of static routes.
+
+.. _starting-static:
+
+Starting STATIC
+===============
+
+Default configuration file for *staticd* is :file:`staticd.conf`. The typical
+location of :file:`staticd.conf` is |INSTALL_PREFIX_ETC|/staticd.conf.
+
+If the user is using integrated config, then :file:`staticd.conf` need not be
+present and the :file:`frr.conf` is read instead.
+
+If the user has not fully upgraded to using the staticd.conf and still has
+a non-integrated config with zebra.conf holding the static routes, *staticd*
+will read in the :file:`zebrad.conf` as a backup.
+
+.. program:: staticd
+
+:abbr:`STATIC` supports all the common FRR daemon start options which are
+documented elsewhere.
+
+.. _static-route-commands:
+
+Static Route Commands
+=====================
+
+Static routing is a very fundamental feature of routing technology. It defines
+a static prefix and gateway.
+
+.. index:: ip route NETWORK GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME
+.. clicmd:: ip route NETWORK GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME
+
+.. index:: ipv6 route NETWORK from SRCPREFIX GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME
+.. clicmd:: ipv6 route NETWORK from SRCPREFIX GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME
+
+ NETWORK is destination prefix with a valid v4 or v6 network based upon
+ initial form of the command. GATEWAY is gateway for the prefix it currently
+ must match the v4 or v6 route type specified at the start of the command.
+ GATEWAY can also be treated as an interface name. If the interface name
+ is ``null0`` then zebra installs a blackhole route. TABLENO
+ is an optional parameter for namespaces that allows you to create the
+ route in a specified table associated with the vrf namespace. table will
+ be rejected if you are not using namespace based vrfs. ``nexthop-vrf``
+ allows you to create a leaked route with a nexthop in the specified VRFNAME
+ vrf VRFNAME allows you to create the route in a specified vrf.
+ ``nexthop-vrf`` cannot be currently used with namespace based vrfs
+ currently as well.
+ The v6 variant allows the installation of a static source-specific route
+ with the SRCPREFIX sub command. These routes are currently supported
+ on Linux operating systems only, and perform AND matching on packet's
+ destination and source addresses in the kernel's forwarding path. Note
+ that destination longest-prefix match is "more important" than source
+ LPM, e.g. ``2001:db8:1::/64 from 2001:db8::/48`` will win over
+ ``2001:db8::/48 from 2001:db8:1::/64`` if both match.
+
+.. _multiple-route-command:
+
+Multiple nexthop static route
+=============================
+
+To create multiple nexthops to the same NETWORK, just reenter the same
+network statement with different nexthop information.
+
+.. code-block:: frr
+
+ ip route 10.0.0.1/32 10.0.0.2
+ ip route 10.0.0.1/32 10.0.0.3
+ ip route 10.0.0.1/32 eth0
+
+
+If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0
+is reachable, then the last route is installed into the kernel.
+
+If zebra has been compiled with multipath support, and both 10.0.0.2 and
+10.0.0.3 are reachable, zebra will install a multipath route via both
+nexthops, if the platform supports this.
+
+::
+
+ router> show ip route
+ S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive
+ via 10.0.0.3 inactive
+ * is directly connected, eth0
+
+
+.. code-block:: frr
+
+ ip route 10.0.0.0/8 10.0.0.2
+ ip route 10.0.0.0/8 10.0.0.3
+ ip route 10.0.0.0/8 null0 255
+
+
+This will install a multihop route via the specified next-hops if they are
+reachable, as well as a high-distance blackhole route, which can be useful to
+prevent traffic destined for a prefix to match less-specific routes (e.g.
+default) should the specified gateways not be reachable. E.g.:
+
+::
+
+ router> show ip route 10.0.0.0/8
+ Routing entry for 10.0.0.0/8
+ Known via "static", distance 1, metric 0
+ 10.0.0.2 inactive
+ 10.0.0.3 inactive
+
+ Routing entry for 10.0.0.0/8
+ Known via "static", distance 255, metric 0
+ directly connected, Null0
+
+Also, if the user wants to configure a static route for a specific VRF, then
+a specific VRF configuration mode is available. After entering into that mode
+with :clicmd:`vrf VRF` the user can enter the same route command as before,
+but this time, the route command will apply to the VRF.
+
+.. code-block:: frr
+
+ # case with VRF
+ configure terminal
+ vrf r1-cust1
+ ip route 10.0.0.0/24 10.0.0.2
+ exit-vrf
+
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index a9431b16e3..af8e4b8d47 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -269,125 +269,6 @@ Link Parameters Commands
for InterASv2 link in OSPF (RFC5392). Note that this option is not yet
supported for ISIS (RFC5316).
-.. _static-route-commands:
-
-Static Route Commands
-=====================
-
-Static routing is a very fundamental feature of routing technology. It defines
-static prefix and gateway.
-
-.. index:: ip route NETWORK GATEWAY
-.. clicmd:: ip route NETWORK GATEWAY
-
- NETWORK is destination prefix with format of A.B.C.D/M. GATEWAY is gateway
- for the prefix. When GATEWAY is A.B.C.D format. It is taken as a IPv4
- address gateway. Otherwise it is treated as an interface name. If the
- interface name is ``null0`` then zebra installs a blackhole route.
-
- Some example configuration:
-
- .. code-block:: frr
-
- ip route 10.0.0.0/8 10.0.0.2
- ip route 10.0.0.0/8 ppp0
- ip route 10.0.0.0/8 null0
-
- First example defines 10.0.0.0/8 static route with gateway 10.0.0.2. Second
- one defines the same prefix but with gateway to interface ppp0. The third
- install a blackhole route.
-
-.. index:: ip route NETWORK NETMASK GATEWAY
-.. clicmd:: ip route NETWORK NETMASK GATEWAY
-
- This is alternate version of above command. When NETWORK is A.B.C.D format,
- user must define NETMASK value with A.B.C.D format. GATEWAY is same option
- as above command.
-
- .. code-block:: frr
-
- ip route 10.0.0.0 255.255.255.0 10.0.0.2
- ip route 10.0.0.0 255.255.255.0 ppp0
- ip route 10.0.0.0 255.255.255.0 null0
-
-
- These statements are equivalent to those in the previous example.
-
-.. index:: ip route NETWORK GATEWAY DISTANCE
-.. clicmd:: ip route NETWORK GATEWAY DISTANCE
-
- Installs the route with the specified distance.
-
-Multiple nexthop static route:
-
-.. code-block:: frr
-
- ip route 10.0.0.1/32 10.0.0.2
- ip route 10.0.0.1/32 10.0.0.3
- ip route 10.0.0.1/32 eth0
-
-
-If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0
-is reachable, then the last route is installed into the kernel.
-
-If zebra has been compiled with multipath support, and both 10.0.0.2 and
-10.0.0.3 are reachable, zebra will install a multipath route via both
-nexthops, if the platform supports this.
-
-::
-
- zebra> show ip route
- S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive
- via 10.0.0.3 inactive
- * is directly connected, eth0
-
-
-.. code-block:: frr
-
- ip route 10.0.0.0/8 10.0.0.2
- ip route 10.0.0.0/8 10.0.0.3
- ip route 10.0.0.0/8 null0 255
-
-
-This will install a multihop route via the specified next-hops if they are
-reachable, as well as a high-metric blackhole route, which can be useful to
-prevent traffic destined for a prefix to match less-specific routes (e.g.
-default) should the specified gateways not be reachable. E.g.:
-
-::
-
- zebra> show ip route 10.0.0.0/8
- Routing entry for 10.0.0.0/8
- Known via "static", distance 1, metric 0
- 10.0.0.2 inactive
- 10.0.0.3 inactive
-
- Routing entry for 10.0.0.0/8
- Known via "static", distance 255, metric 0
- directly connected, Null0
-
-
-.. index:: ipv6 route NETWORK GATEWAY
-.. clicmd:: ipv6 route NETWORK GATEWAY
-
-.. index:: ipv6 route NETWORK GATEWAY DISTANCE
-.. clicmd:: ipv6 route NETWORK GATEWAY DISTANCE
-
- These behave similarly to their ipv4 counterparts.
-
-.. index:: ipv6 route NETWORK from SRCPREFIX GATEWAY
-.. clicmd:: ipv6 route NETWORK from SRCPREFIX GATEWAY
-
-.. index:: ipv6 route NETWORK from SRCPREFIX GATEWAY DISTANCE
-.. clicmd:: ipv6 route NETWORK from SRCPREFIX GATEWAY DISTANCE
-
- Install a static source-specific route. These routes are currently supported
- on Linux operating systems only, and perform AND matching on packet's
- destination and source addresses in the kernel's forwarding path. Note that
- destination longest-prefix match is "more important" than source LPM, e.g.
- ``2001:db8:1::/64 from 2001:db8::/48`` will win over
- ``2001:db8::/48 from 2001:db8:1::/64`` if both match.
-
.. index:: table TABLENO
.. clicmd:: table TABLENO
@@ -415,31 +296,9 @@ for each VRF.
This conceptual view introduces the *Default VRF* case. If the user does not
configure any specific VRF, then by default, FRR uses the *Default VRF*.
-In the context of *Zebra*, this is done automatically when configuring a static
-route with, for example, :clicmd:`ip route NETWORK GATEWAY`:
-
-.. code-block:: frr
-
- # case without VRF
- configure terminal
- ip route 10.0.0.0 255.255.255.0 10.0.0.2
- exit
-
Configuring VRF networking contexts can be done in various ways on FRR. The VRF
interfaces can be configured by entering in interface configuration mode
-:clicmd:`interface IFNAME vrf VRF`. Also, if the user wants to configure a
-static route for a specific VRF, then a specific VRF configuration mode is
-available. After entering into that mode with :clicmd:`vrf VRF` the user can
-enter the same route command as before, but this time, the route command will
-apply to the VRF.
-
-.. code-block:: frr
-
- # case with VRF
- configure terminal
- vrf r1-cust1
- ip route 10.0.0.0 255.255.255.0 10.0.0.2
- exit-vrf
+:clicmd:`interface IFNAME vrf VRF`.
A VRF backend mode is chosen when running *Zebra*.
@@ -479,25 +338,6 @@ commands in relationship to VRF. Here is an extract of some of those commands:
decide to provision this command in configuration file to provide more clarity
about the intended configuration.
-.. index:: ip route NETWORK NETMASK GATEWAY NEXTHOPVRF
-.. clicmd:: ip route NETWORK NETMASK GATEWAY NEXTHOPVRF
-
- This command is based on VRF configuration mode or in configuration mode. If
- on configuration mode, this applies to default VRF. Otherwise, this command
- applies to the VRF of the vrf configuration mode. This command is used to
- configure a vrf route leak across 2 VRFs. This command is only available
- when *Zebra* is launched without :option:`-n` option.
-
-.. index:: ip route NETWORK NETMASK GATEWAY table TABLENO
-.. clicmd:: ip route NETWORK NETMASK GATEWAY table TABLENO
-
- This command is based on configuration mode. There, for default VRF, this
- command is available for all modes. The ``TABLENO`` configured is one of the
- tables from Default *Linux network namespace*. This command is also available
- on vrf configuration mode, provided that *Zebra* is run with :option:`-n`
- option. In that case, this command configures a network route in the given
- ``TABLENO`` of the *Linux network namespace* of the relevant VRF.
-
.. index:: show ip route vrf VRF
.. clicmd:: show ip route vrf VRF
@@ -515,14 +355,6 @@ commands in relationship to VRF. Here is an extract of some of those commands:
will dump the routing table ``TABLENO`` of the *Linux network namespace*
``VRF``.
-The usual static route commands are also available in the VRF context. When
-entered within the VRF context the static routes are created in the VRF.
-
-.. code-block:: frr
-
- ip route 10.0.0.0 255.255.255.0 10.0.0.2 vrf r1-cust1 table 43
- show ip table vrf r1-cust1 table 43
-
.. _zebra-mpls:
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index c8ef829064..37651163f5 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -37,6 +37,7 @@
#include "checksum.h"
#include "md5.h"
#include "table.h"
+#include "srcdest_table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -765,18 +766,28 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
return;
for (struct route_node *rn = route_top(er_table); rn;
- rn = route_next(rn)) {
+ rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
-
- struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p;
struct isis_ext_info *info = rn->info;
+ struct prefix_ipv6 *p, *src_p;
+ srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
+ (const struct prefix **)&src_p);
+
uint32_t metric = info->metric;
if (info->metric > MAX_WIDE_PATH_METRIC)
metric = MAX_WIDE_PATH_METRIC;
- isis_tlvs_add_ipv6_reach(
- lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric);
+
+ if (!src_p || !src_p->prefixlen) {
+ isis_tlvs_add_ipv6_reach(lsp->tlvs,
+ isis_area_ipv6_topology(area),
+ p, metric);
+ } else if (isis_area_ipv6_dstsrc_enabled(area)) {
+ isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
+ ISIS_MT_IPV6_DSTSRC,
+ p, src_p, metric);
+ }
}
}
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index d13f2a13f3..2155bf584e 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -33,6 +33,14 @@ DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area)
+{
+ struct isis_area_mt_setting *area_mt_setting;
+ area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_DSTSRC);
+
+ return (area_mt_setting && area_mt_setting->enabled);
+}
+
uint16_t isis_area_ipv6_topology(struct isis_area *area)
{
struct isis_area_mt_setting *area_mt_setting;
@@ -61,6 +69,8 @@ const char *isis_mtid2str(uint16_t mtid)
return "ipv6-multicast";
case ISIS_MT_IPV6_MGMT:
return "ipv6-mgmt";
+ case ISIS_MT_IPV6_DSTSRC:
+ return "ipv6-dstsrc";
default:
snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
return buf;
@@ -81,6 +91,8 @@ uint16_t isis_str2mtid(const char *name)
return ISIS_MT_IPV6_MULTICAST;
if (!strcmp(name, "ipv6-mgmt"))
return ISIS_MT_IPV6_MGMT;
+ if (!strcmp(name, "ipv6-dstsrc"))
+ return ISIS_MT_IPV6_DSTSRC;
return -1;
}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index 95aa99dba0..8c57d24afa 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -32,6 +32,7 @@
#define ISIS_MT_IPV4_MULTICAST 3
#define ISIS_MT_IPV6_MULTICAST 4
#define ISIS_MT_IPV6_MGMT 5
+#define ISIS_MT_IPV6_DSTSRC 3996 /* FIXME: IANA */
#define ISIS_MT_NAMES \
"<ipv4-unicast" \
@@ -40,6 +41,7 @@
"|ipv4-multicast" \
"|ipv6-multicast" \
"|ipv6-mgmt" \
+ "|ipv6-dstsrc" \
">"
#define ISIS_MT_DESCRIPTIONS \
@@ -48,7 +50,9 @@
"IPv6 unicast topology\n" \
"IPv4 multicast topology\n" \
"IPv6 multicast topology\n" \
- "IPv6 management topology\n"
+ "IPv6 management topology\n" \
+ "IPv6 dst-src topology\n" \
+ ""
#define ISIS_MT_INFO_FIELDS uint16_t mtid;
@@ -75,6 +79,8 @@ struct tlvs;
struct te_is_neigh;
struct isis_tlvs;
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area);
+
uint16_t isis_area_ipv6_topology(struct isis_area *area);
struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 7a6c4dd2dc..8e2a7f13a5 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -673,8 +673,15 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link)
&& iih.tlvs->ipv6_address.count);
- if (!iih.v4_usable && !iih.v6_usable)
+ if (!iih.v4_usable && !iih.v6_usable) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_warn(
+ "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH",
+ circuit->area->area_tag);
+ }
+
goto out;
+ }
retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih);
out:
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index e903dc8c7f..cd3ca44379 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -30,6 +30,7 @@
#include "stream.h"
#include "table.h"
#include "vty.h"
+#include "srcdest_table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -86,33 +87,13 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level)
return area->ext_reach[protocol][level - 1];
}
-static struct route_node *
-isis_redist_route_node_create(route_table_delegate_t *delegate,
- struct route_table *table)
-{
- struct route_node *node;
- node = XCALLOC(MTYPE_ISIS_EXT_ROUTE, sizeof(*node));
- return node;
-}
-
-static void isis_redist_route_node_destroy(route_table_delegate_t *delegate,
- struct route_table *table,
- struct route_node *node)
-{
- if (node->info)
- XFREE(MTYPE_ISIS_EXT_INFO, node->info);
- XFREE(MTYPE_ISIS_EXT_ROUTE, node);
-}
-
-static route_table_delegate_t isis_redist_rt_delegate = {
- .create_node = isis_redist_route_node_create,
- .destroy_node = isis_redist_route_node_destroy};
-
/* Install external reachability information into a
* specific area for a specific level.
* Schedule an lsp regenerate if necessary */
static void isis_redist_install(struct isis_area *area, int level,
- struct prefix *p, struct isis_ext_info *info)
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
+ struct isis_ext_info *info)
{
int family = p->family;
struct route_table *er_table = get_ext_reach(area, family, level);
@@ -126,7 +107,7 @@ static void isis_redist_install(struct isis_area *area, int level,
return;
}
- er_node = route_node_get(er_table, p);
+ er_node = srcdest_rnode_get(er_table, p, src_p);
if (er_node->info) {
route_unlock_node(er_node);
@@ -145,7 +126,8 @@ static void isis_redist_install(struct isis_area *area, int level,
* specific area for a specific level.
* Schedule an lsp regenerate if necessary. */
static void isis_redist_uninstall(struct isis_area *area, int level,
- struct prefix *p)
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p)
{
int family = p->family;
struct route_table *er_table = get_ext_reach(area, family, level);
@@ -159,7 +141,7 @@ static void isis_redist_uninstall(struct isis_area *area, int level,
return;
}
- er_node = route_node_lookup(er_table, p);
+ er_node = srcdest_rnode_lookup(er_table, p, src_p);
if (!er_node)
return;
else
@@ -177,7 +159,8 @@ static void isis_redist_uninstall(struct isis_area *area, int level,
* and prefix, using the given redistribution settings. */
static void isis_redist_update_ext_reach(struct isis_area *area, int level,
struct isis_redist *redist,
- struct prefix *p,
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
struct isis_ext_info *info)
{
struct isis_ext_info area_info;
@@ -188,7 +171,8 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
if (redist->map_name) {
map_ret =
- route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
+ route_map_apply(redist->map, (struct prefix *)p,
+ RMAP_ISIS, &area_info);
if (map_ret == RMAP_DENYMATCH)
area_info.distance = 255;
}
@@ -199,9 +183,9 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
area_info.distance = 255;
if (area_info.distance < 255)
- isis_redist_install(area, level, p, &area_info);
+ isis_redist_install(area, level, p, src_p, &area_info);
else
- isis_redist_uninstall(area, level, p);
+ isis_redist_uninstall(area, level, p, src_p);
}
static void isis_redist_ensure_default(struct isis *isis, int family)
@@ -222,7 +206,7 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
} else
assert(!"Unknown family!");
- ei_node = route_node_get(ei_table, &p);
+ ei_node = srcdest_rnode_get(ei_table, &p, NULL);
if (ei_node->info) {
route_unlock_node(ei_node);
return;
@@ -238,8 +222,8 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
}
/* Handle notification about route being added */
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
- uint32_t metric)
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+ uint8_t distance, uint32_t metric)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -262,7 +246,7 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
return;
}
- ei_node = route_node_get(ei_table, p);
+ ei_node = srcdest_rnode_get(ei_table, p, src_p);
if (ei_node->info)
route_unlock_node(ei_node);
else
@@ -274,8 +258,10 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
info->distance = distance;
info->metric = metric;
- if (is_default_prefix(p))
+ if (is_default_prefix(p)
+ && (!src_p || !src_p->prefixlen)) {
type = DEFAULT_ROUTE;
+ }
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
for (level = 1; level <= ISIS_LEVELS; level++) {
@@ -284,11 +270,11 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
continue;
isis_redist_update_ext_reach(area, level, redist, p,
- info);
+ src_p, info);
}
}
-void isis_redist_delete(int type, struct prefix *p)
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -304,12 +290,14 @@ void isis_redist_delete(int type, struct prefix *p)
zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
zebra_route_string(type));
- if (is_default_prefix(p)) {
+ if (is_default_prefix(p)
+ && (!src_p || !src_p->prefixlen)) {
/* Don't remove default route but add synthetic route for use
* by "default-information originate always". Areas without the
* "always" setting will ignore routes with origin
* DEFAULT_ROUTE. */
- isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC);
+ isis_redist_add(DEFAULT_ROUTE, p, NULL,
+ 254, MAX_WIDE_PATH_METRIC);
return;
}
@@ -319,7 +307,7 @@ void isis_redist_delete(int type, struct prefix *p)
return;
}
- ei_node = route_node_lookup(ei_table, p);
+ ei_node = srcdest_rnode_lookup(ei_table, p, src_p);
if (!ei_node || !ei_node->info) {
char buf[BUFSIZ];
prefix2str(p, buf, sizeof(buf));
@@ -334,12 +322,12 @@ void isis_redist_delete(int type, struct prefix *p)
route_unlock_node(ei_node);
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
- for (level = 1; level < ISIS_LEVELS; level++) {
+ for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
redist = get_redist_settings(area, family, type, level);
if (!redist->redist)
continue;
- isis_redist_uninstall(area, level, p);
+ isis_redist_uninstall(area, level, p, src_p);
}
XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info);
@@ -418,17 +406,14 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
isis_redist_routemap_set(redist, routemap);
if (!area->ext_reach[protocol][level - 1]) {
- area->ext_reach[protocol][level - 1] =
- route_table_init_with_delegate(
- &isis_redist_rt_delegate);
+ area->ext_reach[protocol][level - 1] = srcdest_table_init();
}
- for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
+ for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) {
if (!area->isis->ext_info[i]) {
- area->isis->ext_info[i] =
- route_table_init_with_delegate(
- &isis_redist_rt_delegate);
+ area->isis->ext_info[i] = srcdest_table_init();
}
+ }
isis_redist_update_zebra_subscriptions(area->isis);
@@ -436,20 +421,27 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
isis_redist_ensure_default(area->isis, family);
ei_table = get_ext_info(area->isis, family);
- for (rn = route_top(ei_table); rn; rn = route_next(rn)) {
+ for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
info = rn->info;
+ const struct prefix *p, *src_p;
+
+ srcdest_rnode_prefixes(rn, &p, &src_p);
+
if (type == DEFAULT_ROUTE) {
- if (!is_default_prefix(&rn->p))
+ if (!is_default_prefix(p)
+ || (src_p && src_p->prefixlen)) {
continue;
+ }
} else {
if (info->origin != type)
continue;
}
- isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
+ isis_redist_update_ext_reach(area, level, redist, p,
+ (struct prefix_ipv6 *)src_p, info);
}
}
@@ -472,14 +464,19 @@ static void isis_redist_unset(struct isis_area *area, int level, int family,
return;
}
- for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+ for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
info = rn->info;
+ const struct prefix *p, *src_p;
+ srcdest_rnode_prefixes(rn, &p, &src_p);
+
if (type == DEFAULT_ROUTE) {
- if (!is_default_prefix(&rn->p))
+ if (!is_default_prefix(p)
+ || (src_p && src_p->prefixlen)) {
continue;
+ }
} else {
if (info->origin != type)
continue;
diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h
index c12363d508..95f06f71ec 100644
--- a/isisd/isis_redist.h
+++ b/isisd/isis_redist.h
@@ -42,13 +42,14 @@ struct isis_redist {
struct isis_area;
struct prefix;
+struct prefix_ipv6;
struct vty;
struct route_table *get_ext_reach(struct isis_area *area, int family,
int level);
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
- uint32_t metric);
-void isis_redist_delete(int type, struct prefix *p);
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+ uint8_t distance, uint32_t metric);
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p);
int isis_redist_config_write(struct vty *vty, struct isis_area *area,
int family);
void isis_redist_init(void);
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index c98e16e2bd..b1225ae547 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -33,6 +33,7 @@
#include "hash.h"
#include "if.h"
#include "table.h"
+#include "srcdest_table.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -199,6 +200,7 @@ static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
}
static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
uint32_t cost,
uint32_t depth,
struct list *adjacencies)
@@ -232,8 +234,10 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
SET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
/* update neighbor router address */
- if (depth == 2 && prefix->prefixlen == 128)
+ if (depth == 2 && prefix->prefixlen == 128
+ && (!src_p || !src_p->prefixlen)) {
adj->router_address6 = prefix->u.prefix6;
+ }
adjinfo2nexthop6(rinfo->nexthops6, adj);
}
}
@@ -317,10 +321,13 @@ static int isis_route_info_same(struct isis_route_info *new,
return 1;
}
-struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
+struct isis_route_info *isis_route_create(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
+ uint32_t cost,
uint32_t depth,
struct list *adjacencies,
- struct isis_area *area, int level)
+ struct isis_area *area,
+ struct route_table *table)
{
struct route_node *route_node;
struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
@@ -331,18 +338,12 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
/* for debugs */
prefix2str(prefix, buff, sizeof(buff));
- rinfo_new = isis_route_info_new(prefix, cost, depth, adjacencies);
-
- if (family == AF_INET)
- route_node =
- route_node_get(area->route_table[level - 1], prefix);
- else if (family == AF_INET6)
- route_node =
- route_node_get(area->route_table6[level - 1], prefix);
- else {
- isis_route_info_delete(rinfo_new);
+ if (!table)
return NULL;
- }
+
+ rinfo_new = isis_route_info_new(prefix, src_p, cost,
+ depth, adjacencies);
+ route_node = srcdest_rnode_get(table, prefix, src_p);
rinfo_old = route_node->info;
if (!rinfo_old) {
@@ -352,6 +353,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
route_info = rinfo_new;
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else {
+ route_unlock_node(route_node);
if (isis->debugs & DEBUG_RTE_EVENTS)
zlog_debug("ISIS-Rte (%s) route already exists: %s",
area->area_tag, buff);
@@ -378,19 +380,21 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
return route_info;
}
-static void isis_route_delete(struct prefix *prefix, struct route_table *table)
+static void isis_route_delete(struct route_node *rode,
+ struct route_table *table)
{
- struct route_node *rode;
struct isis_route_info *rinfo;
- char buff[PREFIX2STR_BUFFER];
+ char buff[SRCDEST2STR_BUFFER];
+ struct prefix *prefix;
+ struct prefix_ipv6 *src_p;
/* for log */
- prefix2str(prefix, buff, sizeof(buff));
+ srcdest_rnode2str(rode, buff, sizeof(buff));
+ srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
+ (const struct prefix **)&src_p);
- rode = route_node_get(table, prefix);
rinfo = rode->info;
-
if (rinfo == NULL) {
if (isis->debugs & DEBUG_RTE_EVENTS)
zlog_debug(
@@ -403,29 +407,36 @@ static void isis_route_delete(struct prefix *prefix, struct route_table *table)
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
if (isis->debugs & DEBUG_RTE_EVENTS)
zlog_debug("ISIS-Rte: route delete %s", buff);
- isis_zebra_route_update(prefix, rinfo);
+ isis_zebra_route_update(prefix, src_p, rinfo);
}
isis_route_info_delete(rinfo);
rode->info = NULL;
-
- return;
+ route_unlock_node(rode);
}
-/* Validating routes in particular table. */
-static void isis_route_validate_table(struct isis_area *area,
- struct route_table *table)
+static void _isis_route_verify_table(struct isis_area *area,
+ struct route_table *table,
+ struct route_table **tables)
{
struct route_node *rnode, *drnode;
struct isis_route_info *rinfo;
- char buff[PREFIX2STR_BUFFER];
+ char buff[SRCDEST2STR_BUFFER];
- for (rnode = route_top(table); rnode; rnode = route_next(rnode)) {
+ for (rnode = route_top(table); rnode;
+ rnode = srcdest_route_next(rnode)) {
if (rnode->info == NULL)
continue;
rinfo = rnode->info;
+ struct prefix *dst_p;
+ struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rnode,
+ (const struct prefix **)&dst_p,
+ (const struct prefix **)&src_p);
+
if (isis->debugs & DEBUG_RTE_EVENTS) {
- prefix2str(&rnode->p, buff, sizeof(buff));
+ srcdest2str(dst_p, src_p, buff, sizeof(buff));
zlog_debug(
"ISIS-Rte (%s): route validate: %s %s %s %s",
area->area_tag,
@@ -443,50 +454,47 @@ static void isis_route_validate_table(struct isis_area *area,
buff);
}
- isis_zebra_route_update(&rnode->p, rinfo);
- if (!CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
- /* Area is either L1 or L2 => we use level route tables
- * directly for
- * validating => no problems with deleting routes. */
- if (area->is_type != IS_LEVEL_1_AND_2) {
- isis_route_delete(&rnode->p, table);
+ isis_zebra_route_update(dst_p, src_p, rinfo);
+
+ if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
+ continue;
+
+ /* Area is either L1 or L2 => we use level route tables
+ * directly for
+ * validating => no problems with deleting routes. */
+ if (!tables) {
+ isis_route_delete(rnode, table);
+ continue;
+ }
+
+ /* If area is L1L2, we work with merge table and
+ * therefore must
+ * delete node from level tables as well before deleting
+ * route info. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ drnode = srcdest_rnode_lookup(tables[level - 1],
+ dst_p, src_p);
+ if (!drnode)
continue;
- }
- /* If area is L1L2, we work with merge table and
- * therefore must
- * delete node from level tables as well before deleting
- * route info.
- * FIXME: Is it performance problem? There has to be the
- * better way.
- * Like not to deal with it here at all (see the next
- * comment)? */
- if (rnode->p.family == AF_INET) {
- drnode = route_node_get(area->route_table[0],
- &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- drnode = route_node_get(area->route_table[1],
- &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- }
- if (rnode->p.family == AF_INET6) {
- drnode = route_node_get(area->route_table6[0],
- &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- drnode = route_node_get(area->route_table6[1],
- &rnode->p);
- if (drnode->info == rnode->info)
- drnode->info = NULL;
- }
+ route_unlock_node(drnode);
+
+ if (drnode->info != rnode->info)
+ continue;
- isis_route_delete(&rnode->p, table);
+ drnode->info = NULL;
+ route_unlock_node(drnode);
}
+
+ isis_route_delete(rnode, table);
}
}
+void isis_route_verify_table(struct isis_area *area, struct route_table *table)
+{
+ return _isis_route_verify_table(area, table, NULL);
+}
+
/* Function to validate route tables for L1L2 areas. In this case we can't use
* level route tables directly, we have to merge them at first. L1 routes are
* preferred over the L2 ones.
@@ -497,87 +505,71 @@ static void isis_route_validate_table(struct isis_area *area,
*
* FIXME: Is it right place to do it at all? Maybe we should push both levels
* to the RIB with different zebra route types and let RIB handle this? */
-static void isis_route_validate_merge(struct isis_area *area, int family)
+void isis_route_verify_merge(struct isis_area *area,
+ struct route_table *level1_table,
+ struct route_table *level2_table)
{
- struct route_table *table = NULL;
+ struct route_table *tables[] = { level1_table, level2_table };
struct route_table *merge;
struct route_node *rnode, *mrnode;
- merge = route_table_init();
+ merge = srcdest_table_init();
- if (family == AF_INET)
- table = area->route_table[0];
- else if (family == AF_INET6)
- table = area->route_table6[0];
- else {
- zlog_warn("ISIS-Rte (%s) %s called for unknown family %d",
- area->area_tag, __func__, family);
- route_table_finish(merge);
- return;
- }
-
- for (rnode = route_top(table); rnode; rnode = route_next(rnode)) {
- if (rnode->info == NULL)
- continue;
- mrnode = route_node_get(merge, &rnode->p);
- mrnode->info = rnode->info;
- }
-
- if (family == AF_INET)
- table = area->route_table[1];
- else if (family == AF_INET6)
- table = area->route_table6[1];
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ for (rnode = route_top(tables[level - 1]); rnode;
+ rnode = srcdest_route_next(rnode)) {
+ struct isis_route_info *rinfo = rnode->info;
+ if (!rinfo)
+ continue;
- for (rnode = route_top(table); rnode; rnode = route_next(rnode)) {
- if (rnode->info == NULL)
- continue;
- mrnode = route_node_get(merge, &rnode->p);
- if (mrnode->info != NULL)
- continue;
- mrnode->info = rnode->info;
+ struct prefix *prefix;
+ struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rnode,
+ (const struct prefix **)&prefix,
+ (const struct prefix **)&src_p);
+ mrnode = srcdest_rnode_get(merge, prefix, src_p);
+ struct isis_route_info *mrinfo = mrnode->info;
+ if (mrinfo) {
+ route_unlock_node(mrnode);
+ if (CHECK_FLAG(mrinfo->flag,
+ ISIS_ROUTE_FLAG_ACTIVE)) {
+ /* Clear the ZEBRA_SYNCED flag on the
+ * L2 route when L1 wins, otherwise L2
+ * won't get reinstalled when L1
+ * disappears.
+ */
+ UNSET_FLAG(
+ rinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED
+ );
+ continue;
+ } else {
+ /* Clear the ZEBRA_SYNCED flag on the L1
+ * route when L2 wins, otherwise L1
+ * won't get reinstalled when it
+ * reappears.
+ */
+ UNSET_FLAG(
+ mrinfo->flag,
+ ISIS_ROUTE_FLAG_ZEBRA_SYNCED
+ );
+ }
+ }
+ mrnode->info = rnode->info;
+ }
}
- isis_route_validate_table(area, merge);
+ _isis_route_verify_table(area, merge, tables);
route_table_finish(merge);
}
-/* Walk through route tables and propagate necessary changes into RIB. In case
- * of L1L2 area, level tables have to be merged at first. */
-void isis_route_validate(struct isis_area *area)
-{
- struct listnode *node;
- struct isis_circuit *circuit;
-
- if (area->is_type == IS_LEVEL_1)
- isis_route_validate_table(area, area->route_table[0]);
- else if (area->is_type == IS_LEVEL_2)
- isis_route_validate_table(area, area->route_table[1]);
- else
- isis_route_validate_merge(area, AF_INET);
-
- if (area->is_type == IS_LEVEL_1)
- isis_route_validate_table(area, area->route_table6[0]);
- else if (area->is_type == IS_LEVEL_2)
- isis_route_validate_table(area, area->route_table6[1]);
- else
- isis_route_validate_merge(area, AF_INET6);
-
- if (!area->circuit_list) {
- return;
- }
- /* walk all circuits and reset any spf specific flags */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
- UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
-
- return;
-}
-
void isis_route_invalidate_table(struct isis_area *area,
struct route_table *table)
{
struct route_node *rode;
struct isis_route_info *rinfo;
- for (rode = route_top(table); rode; rode = route_next(rode)) {
+ for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
if (rode->info == NULL)
continue;
rinfo = rode->info;
@@ -585,11 +577,3 @@ void isis_route_invalidate_table(struct isis_area *area,
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
}
}
-
-void isis_route_invalidate(struct isis_area *area)
-{
- if (area->is_type & IS_LEVEL_1)
- isis_route_invalidate_table(area, area->route_table[0]);
- if (area->is_type & IS_LEVEL_2)
- isis_route_invalidate_table(area, area->route_table[1]);
-}
diff --git a/isisd/isis_route.h b/isisd/isis_route.h
index 82f37c29f2..9d6858586b 100644
--- a/isisd/isis_route.h
+++ b/isisd/isis_route.h
@@ -50,14 +50,26 @@ struct isis_route_info {
struct list *nexthops6;
};
-struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,
+struct isis_route_info *isis_route_create(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
+ uint32_t cost,
uint32_t depth,
struct list *adjacencies,
- struct isis_area *area, int level);
+ struct isis_area *area,
+ struct route_table *table);
-void isis_route_validate(struct isis_area *area);
+/* Walk the given table and install new routes to zebra and remove old ones.
+ * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
+void isis_route_verify_table(struct isis_area *area,
+ struct route_table *table);
+
+/* Same as isis_route_verify_table, but merge L1 and L2 routes before */
+void isis_route_verify_merge(struct isis_area *area,
+ struct route_table *level1_table,
+ struct route_table *level2_table);
+
+/* Unset ISIS_ROUTE_FLAG_ACTIVE on all routes. Used before running spf. */
void isis_route_invalidate_table(struct isis_area *area,
struct route_table *table);
-void isis_route_invalidate(struct isis_area *area);
#endif /* _ZEBRA_ISIS_ROUTE_H */
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 556f2890cf..0a8b0e927e 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -37,6 +37,7 @@
#include "spf_backoff.h"
#include "jhash.h"
#include "skiplist.h"
+#include "srcdest_table.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -74,12 +75,17 @@ enum vertextype {
#define VTYPE_ES(t) ((t) == VTYPE_ES)
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
+struct prefix_pair {
+ struct prefix dest;
+ struct prefix_ipv6 src;
+};
+
/*
* Triple <N, d(N), {Adj(N)}>
*/
union isis_N {
uint8_t id[ISIS_SYS_ID_LEN + 1];
- struct prefix prefix;
+ struct prefix_pair ip;
};
struct isis_vertex {
enum vertextype type;
@@ -106,8 +112,13 @@ static unsigned isis_vertex_queue_hash_key(void *vp)
{
struct isis_vertex *vertex = vp;
- if (VTYPE_IP(vertex->type))
- return prefix_hash_key(&vertex->N.prefix);
+ if (VTYPE_IP(vertex->type)) {
+ uint32_t key;
+
+ key = prefix_hash_key(&vertex->N.ip.dest);
+ key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key);
+ return key;
+ }
return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
}
@@ -119,8 +130,13 @@ static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
if (va->type != vb->type)
return 0;
- if (VTYPE_IP(va->type))
- return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0;
+ if (VTYPE_IP(va->type)) {
+ if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest))
+ return 0;
+
+ return prefix_cmp((struct prefix *)&va->N.ip.src,
+ (struct prefix *)&vb->N.ip.src) == 0;
+ }
return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
}
@@ -275,6 +291,7 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
struct isis_spftree {
struct isis_vertex_queue paths; /* the SPT */
struct isis_vertex_queue tents; /* TENT */
+ struct route_table *route_table;
struct isis_area *area; /* back pointer to area */
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp as wall time for display */
@@ -284,6 +301,7 @@ struct isis_spftree {
uint16_t mtid;
int family;
int level;
+ enum spf_tree_id tree_id;
};
@@ -392,6 +410,7 @@ static const char *vtype2string(enum vertextype vtype)
return NULL; /* Not reached */
}
+#define VID2STR_BUFFER SRCDEST2STR_BUFFER
static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
{
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
@@ -399,7 +418,9 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
}
if (VTYPE_IP(vertex->type)) {
- prefix2str((struct prefix *)&vertex->N.prefix, buff, size);
+ srcdest2str(&vertex->N.ip.dest,
+ &vertex->N.ip.src,
+ buff, size);
return buff;
}
@@ -414,7 +435,7 @@ static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1);
} else if (VTYPE_IP(vtype)) {
- memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix));
+ memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip));
} else {
zlog_err("WTF!");
}
@@ -472,6 +493,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
+ tree->route_table = srcdest_table_init();
tree->area = area;
tree->last_run_timestamp = 0;
tree->last_run_monotime = 0;
@@ -484,8 +506,10 @@ void isis_spftree_del(struct isis_spftree *spftree)
{
isis_vertex_queue_free(&spftree->tents);
isis_vertex_queue_free(&spftree->paths);
- XFREE(MTYPE_ISIS_SPFTREE, spftree);
+ route_table_finish(spftree->route_table);
+ spftree->route_table = NULL;
+ XFREE(MTYPE_ISIS_SPFTREE, spftree);
return;
}
@@ -504,67 +528,44 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree,
void spftree_area_init(struct isis_area *area)
{
- if (area->is_type & IS_LEVEL_1) {
- if (area->spftree[0] == NULL)
- area->spftree[0] = isis_spftree_new(area);
- if (area->spftree6[0] == NULL)
- area->spftree6[0] = isis_spftree_new(area);
- }
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ if (!(area->is_type & level))
+ continue;
+ if (area->spftree[tree][level - 1])
+ continue;
- if (area->is_type & IS_LEVEL_2) {
- if (area->spftree[1] == NULL)
- area->spftree[1] = isis_spftree_new(area);
- if (area->spftree6[1] == NULL)
- area->spftree6[1] = isis_spftree_new(area);
+ area->spftree[tree][level - 1] = isis_spftree_new(area);
+ }
}
-
- return;
}
void spftree_area_del(struct isis_area *area)
{
- if (area->is_type & IS_LEVEL_1) {
- if (area->spftree[0] != NULL) {
- isis_spftree_del(area->spftree[0]);
- area->spftree[0] = NULL;
- }
- if (area->spftree6[0]) {
- isis_spftree_del(area->spftree6[0]);
- area->spftree6[0] = NULL;
- }
- }
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ if (!(area->is_type & level))
+ continue;
+ if (!area->spftree[tree][level - 1])
+ continue;
- if (area->is_type & IS_LEVEL_2) {
- if (area->spftree[1] != NULL) {
- isis_spftree_del(area->spftree[1]);
- area->spftree[1] = NULL;
- }
- if (area->spftree6[1] != NULL) {
- isis_spftree_del(area->spftree6[1]);
- area->spftree6[1] = NULL;
+ isis_spftree_del(area->spftree[tree][level - 1]);
}
}
-
- return;
}
void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
{
- if (area->is_type & IS_LEVEL_1) {
- if (area->spftree[0] != NULL)
- isis_spftree_adj_del(area->spftree[0], adj);
- if (area->spftree6[0] != NULL)
- isis_spftree_adj_del(area->spftree6[0], adj);
- }
-
- if (area->is_type & IS_LEVEL_2) {
- if (area->spftree[1] != NULL)
- isis_spftree_adj_del(area->spftree[1], adj);
- if (area->spftree6[1] != NULL)
- isis_spftree_adj_del(area->spftree6[1], adj);
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ if (!(area->is_type & level))
+ continue;
+ if (!area->spftree[tree][level - 1])
+ continue;
+ isis_spftree_adj_del(area->spftree[tree][level - 1],
+ adj);
+ }
}
-
- return;
}
/*
@@ -595,7 +596,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
struct isis_vertex *vertex;
struct isis_lsp *lsp;
#ifdef EXTREME_DEBUG
- char buff[PREFIX2STR_BUFFER];
+ char buff[VID2STR_BUFFER];
#endif /* EXTREME_DEBUG */
union isis_N n;
@@ -646,7 +647,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
struct listnode *node;
struct isis_adjacency *parent_adj;
#ifdef EXTREME_DEBUG
- char buff[PREFIX2STR_BUFFER];
+ char buff[VID2STR_BUFFER];
#endif
assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL);
@@ -719,15 +720,16 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
{
struct isis_vertex *vertex;
#ifdef EXTREME_DEBUG
- char buff[PREFIX2STR_BUFFER];
+ char buff[VID2STR_BUFFER];
#endif
assert(spftree && parent);
- struct prefix p;
+ struct prefix_pair p;
if (vtype >= VTYPE_IPREACH_INTERNAL) {
- prefix_copy(&p, id);
- apply_mask(&p);
+ memcpy(&p, id, sizeof(p));
+ apply_mask(&p.dest);
+ apply_mask((struct prefix *)&p.src);
id = &p;
}
@@ -814,6 +816,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
enum vertextype vtype;
static const uint8_t null_sysid[ISIS_SYS_ID_LEN];
struct isis_mt_router_info *mt_router_info = NULL;
+ struct prefix_pair ip_info;
if (!lsp->tlvs)
return ISIS_OK;
@@ -907,12 +910,17 @@ lspfragloop:
vtype = i ? VTYPE_IPREACH_EXTERNAL
: VTYPE_IPREACH_INTERNAL;
+ memset(&ip_info, 0, sizeof(ip_info));
+ ip_info.dest.family = AF_INET;
+
struct isis_oldstyle_ip_reach *r;
for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
->head;
r; r = r->next) {
dist = cost + r->metric;
- process_N(spftree, vtype, (void *)&r->prefix,
+ ip_info.dest.u.prefix4 = r->prefix.prefix;
+ ip_info.dest.prefixlen = r->prefix.prefixlen;
+ process_N(spftree, vtype, &ip_info,
dist, depth + 1, parent);
}
}
@@ -926,6 +934,9 @@ lspfragloop:
ipv4_reachs = isis_lookup_mt_items(
&lsp->tlvs->mt_ip_reach, spftree->mtid);
+ memset(&ip_info, 0, sizeof(ip_info));
+ ip_info.dest.family = AF_INET;
+
struct isis_extended_ip_reach *r;
for (r = ipv4_reachs
? (struct isis_extended_ip_reach *)
@@ -933,7 +944,9 @@ lspfragloop:
: NULL;
r; r = r->next) {
dist = cost + r->metric;
- process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix,
+ ip_info.dest.u.prefix4 = r->prefix.prefix;
+ ip_info.dest.prefixlen = r->prefix.prefixlen;
+ process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
dist, depth + 1, parent);
}
}
@@ -954,7 +967,28 @@ lspfragloop:
dist = cost + r->metric;
vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
: VTYPE_IP6REACH_INTERNAL;
- process_N(spftree, vtype, (void *)&r->prefix, dist,
+ memset(&ip_info, 0, sizeof(ip_info));
+ ip_info.dest.family = AF_INET6;
+ ip_info.dest.u.prefix6 = r->prefix.prefix;
+ ip_info.dest.prefixlen = r->prefix.prefixlen;
+
+ if (r->subtlvs
+ && r->subtlvs->source_prefix
+ && r->subtlvs->source_prefix->prefixlen) {
+ if (spftree->tree_id != SPFTREE_DSTSRC) {
+ char buff[VID2STR_BUFFER];
+ zlog_warn("Ignoring dest-src route %s in non dest-src topology",
+ srcdest2str(
+ &ip_info.dest,
+ r->subtlvs->source_prefix,
+ buff, sizeof(buff)
+ )
+ );
+ continue;
+ }
+ ip_info.src = *r->subtlvs->source_prefix;
+ }
+ process_N(spftree, vtype, &ip_info, dist,
depth + 1, parent);
}
}
@@ -983,7 +1017,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
struct list *adj_list;
struct list *adjdb;
struct prefix_ipv4 *ipv4;
- struct prefix prefix;
+ struct prefix_pair ip_info;
int retval = ISIS_OK;
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2];
@@ -1007,27 +1041,29 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
* Add IP(v6) addresses of this circuit
*/
if (spftree->family == AF_INET) {
- prefix.family = AF_INET;
+ memset(&ip_info, 0, sizeof(ip_info));
+ ip_info.dest.family = AF_INET;
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
ipv4)) {
- prefix.u.prefix4 = ipv4->prefix;
- prefix.prefixlen = ipv4->prefixlen;
- apply_mask(&prefix);
+ ip_info.dest.u.prefix4 = ipv4->prefix;
+ ip_info.dest.prefixlen = ipv4->prefixlen;
+ apply_mask(&ip_info.dest);
isis_spf_add_local(spftree,
VTYPE_IPREACH_INTERNAL,
- &prefix, NULL, 0, parent);
+ &ip_info, NULL, 0, parent);
}
}
if (spftree->family == AF_INET6) {
- prefix.family = AF_INET6;
+ memset(&ip_info, 0, sizeof(ip_info));
+ ip_info.dest.family = AF_INET6;
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
ipnode, ipv6)) {
- prefix.prefixlen = ipv6->prefixlen;
- prefix.u.prefix6 = ipv6->prefix;
- apply_mask(&prefix);
+ ip_info.dest.u.prefix6 = ipv6->prefix;
+ ip_info.dest.prefixlen = ipv6->prefixlen;
+ apply_mask(&ip_info.dest);
isis_spf_add_local(spftree,
VTYPE_IP6REACH_INTERNAL,
- &prefix, NULL, 0, parent);
+ &ip_info, NULL, 0, parent);
}
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
@@ -1210,7 +1246,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
static void add_to_paths(struct isis_spftree *spftree,
struct isis_vertex *vertex)
{
- char buff[PREFIX2STR_BUFFER];
+ char buff[VID2STR_BUFFER];
if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
return;
@@ -1225,10 +1261,11 @@ static void add_to_paths(struct isis_spftree *spftree,
if (VTYPE_IP(vertex->type)) {
if (listcount(vertex->Adj_N) > 0)
- isis_route_create((struct prefix *)&vertex->N.prefix,
+ isis_route_create(&vertex->N.ip.dest,
+ &vertex->N.ip.src,
vertex->d_N, vertex->depth,
vertex->Adj_N, spftree->area,
- spftree->level);
+ spftree->route_table);
else if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug(
"ISIS-Spf: no adjacencies do not install route for "
@@ -1241,7 +1278,7 @@ static void add_to_paths(struct isis_spftree *spftree,
}
static void init_spt(struct isis_spftree *spftree, int mtid, int level,
- int family)
+ int family, enum spf_tree_id tree_id)
{
isis_vertex_queue_clear(&spftree->tents);
isis_vertex_queue_clear(&spftree->paths);
@@ -1249,53 +1286,54 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
spftree->mtid = mtid;
spftree->level = level;
spftree->family = family;
+ spftree->tree_id = tree_id;
return;
}
-static int isis_run_spf(struct isis_area *area, int level, int family,
+static int isis_run_spf(struct isis_area *area, int level,
+ enum spf_tree_id tree_id,
uint8_t *sysid, struct timeval *nowtv)
{
int retval = ISIS_OK;
struct isis_vertex *vertex;
struct isis_vertex *root_vertex;
- struct isis_spftree *spftree = NULL;
+ struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
struct isis_lsp *lsp;
- struct route_table *table = NULL;
struct timeval time_now;
unsigned long long start_time, end_time;
- uint16_t mtid;
+ uint16_t mtid = 0;
/* Get time that can't roll backwards. */
start_time = nowtv->tv_sec;
start_time = (start_time * 1000000) + nowtv->tv_usec;
- if (family == AF_INET)
- spftree = area->spftree[level - 1];
- else if (family == AF_INET6)
- spftree = area->spftree6[level - 1];
+ int family = -1;
+ switch (tree_id) {
+ case SPFTREE_IPV4:
+ family = AF_INET;
+ mtid = ISIS_MT_IPV4_UNICAST;
+ break;
+ case SPFTREE_IPV6:
+ family = AF_INET6;
+ mtid = isis_area_ipv6_topology(area);
+ break;
+ case SPFTREE_DSTSRC:
+ family = AF_INET6;
+ mtid = ISIS_MT_IPV6_DSTSRC;
+ break;
+ case SPFTREE_COUNT:
+ assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!");
+ return ISIS_WARNING;
+ }
+
assert(spftree);
assert(sysid);
- /* Make all routes in current route table inactive. */
- if (family == AF_INET)
- table = area->route_table[level - 1];
- else if (family == AF_INET6)
- table = area->route_table6[level - 1];
-
- isis_route_invalidate_table(area, table);
-
- /* We only support ipv4-unicast and ipv6-unicast as topologies for now
- */
- if (family == AF_INET6)
- mtid = isis_area_ipv6_topology(area);
- else
- mtid = ISIS_MT_IPV4_UNICAST;
-
/*
* C.2.5 Step 0
*/
- init_spt(spftree, mtid, level, family);
+ init_spt(spftree, mtid, level, family, tree_id);
/* a) */
root_vertex = isis_spf_add_root(spftree, sysid);
/* b) */
@@ -1342,7 +1380,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
}
out:
- isis_route_validate(area);
spftree->runcount++;
spftree->last_run_timestamp = time(NULL);
spftree->last_run_monotime = monotime(&time_now);
@@ -1353,6 +1390,23 @@ out:
return retval;
}
+void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
+{
+ if (area->is_type == IS_LEVEL_1) {
+ isis_route_verify_table(area, trees[0]->route_table);
+ } else if (area->is_type == IS_LEVEL_2) {
+ isis_route_verify_table(area, trees[1]->route_table);
+ } else {
+ isis_route_verify_merge(area, trees[0]->route_table,
+ trees[1]->route_table);
+ }
+}
+
+void isis_spf_invalidate_routes(struct isis_spftree *tree)
+{
+ isis_route_invalidate_table(tree->area, tree->route_table);
+}
+
static int isis_run_spf_cb(struct thread *thread)
{
struct isis_spf_run *run = THREAD_ARG(thread);
@@ -1370,17 +1424,31 @@ static int isis_run_spf_cb(struct thread *thread)
return ISIS_WARNING;
}
+ isis_area_invalidate_routes(area, level);
+
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
area->area_tag, level);
if (area->ip_circuits)
- retval = isis_run_spf(area, level, AF_INET, isis->sysid,
+ retval = isis_run_spf(area, level, SPFTREE_IPV4, isis->sysid,
&thread->real);
if (area->ipv6_circuits)
- retval = isis_run_spf(area, level, AF_INET6, isis->sysid,
+ retval = isis_run_spf(area, level, SPFTREE_IPV6, isis->sysid,
+ &thread->real);
+ if (area->ipv6_circuits
+ && isis_area_ipv6_dstsrc_enabled(area))
+ retval = isis_run_spf(area, level, SPFTREE_DSTSRC, isis->sysid,
&thread->real);
+ isis_area_verify_routes(area);
+
+ /* walk all circuits and reset any spf specific flags */
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+
return retval;
}
@@ -1396,7 +1464,7 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
int isis_spf_schedule(struct isis_area *area, int level)
{
- struct isis_spftree *spftree = area->spftree[level - 1];
+ struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
time_t now = monotime(NULL);
int diff = now - spftree->last_run_monotime;
@@ -1451,7 +1519,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
{
struct listnode *node;
struct isis_vertex *vertex;
- char buff[PREFIX2STR_BUFFER];
+ char buff[VID2STR_BUFFER];
vty_out(vty,
"Vertex Type Metric Next-Hop Interface Parent\n");
@@ -1517,6 +1585,39 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
}
}
+static void isis_print_spftree(struct vty *vty, int level,
+ struct isis_area *area,
+ enum spf_tree_id tree_id)
+{
+ const char *tree_id_text = NULL;
+
+ switch (tree_id) {
+ case SPFTREE_IPV4:
+ tree_id_text = "that speak IP";
+ break;
+ case SPFTREE_IPV6:
+ tree_id_text = "that speak IPv6";
+ break;
+ case SPFTREE_DSTSRC:
+ tree_id_text = "that support IPv6 dst-src routing";
+ break;
+ case SPFTREE_COUNT:
+ assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type");
+ return;
+ }
+
+ if (!area->spftree[tree_id][level - 1]
+ || !isis_vertex_queue_count(
+ &area->spftree[tree_id][level - 1]->paths))
+ return;
+
+ vty_out(vty, "IS-IS paths to level-%d routers %s\n",
+ level, tree_id_text);
+ isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths,
+ isis->sysid);
+ vty_out(vty, "\n");
+}
+
DEFUN (show_isis_topology,
show_isis_topology_cmd,
"show isis topology [<level-1|level-2>]",
@@ -1548,25 +1649,17 @@ DEFUN (show_isis_topology,
if ((level & levels) == 0)
continue;
- if (area->ip_circuits > 0 && area->spftree[level - 1]
- && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
- vty_out(vty,
- "IS-IS paths to level-%d routers that speak IP\n",
- level);
- isis_print_paths(
- vty, &area->spftree[level - 1]->paths,
- isis->sysid);
- vty_out(vty, "\n");
+ if (area->ip_circuits > 0) {
+ isis_print_spftree(vty, level, area,
+ SPFTREE_IPV4);
}
- if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
- && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
- vty_out(vty,
- "IS-IS paths to level-%d routers that speak IPv6\n",
- level);
- isis_print_paths(
- vty, &area->spftree6[level - 1]->paths,
- isis->sysid);
- vty_out(vty, "\n");
+ if (area->ipv6_circuits > 0) {
+ isis_print_spftree(vty, level, area,
+ SPFTREE_IPV6);
+ }
+ if (isis_area_ipv6_dstsrc_enabled(area)) {
+ isis_print_spftree(vty, level, area,
+ SPFTREE_DSTSRC);
}
}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index 84e07861d2..9a73ca8783 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -27,6 +27,9 @@
struct isis_spftree;
struct isis_spftree *isis_spftree_new(struct isis_area *area);
+void isis_spf_invalidate_routes(struct isis_spftree *tree);
+void isis_spf_verify_routes(struct isis_area *area,
+ struct isis_spftree **trees);
void isis_spftree_del(struct isis_spftree *spftree);
void spftree_area_init(struct isis_area *area);
void spftree_area_del(struct isis_area *area);
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 9b2aa7470b..a433fcdb41 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -1912,6 +1912,11 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item)
dest->count++;
}
+static struct isis_item *last_item(struct isis_item_list *list)
+{
+ return container_of(list->tail, struct isis_item, next);
+}
+
static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
uint8_t tlv_type, uint8_t len, struct stream *s,
struct sbuf *log, void *dest, int indent)
@@ -3168,6 +3173,21 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
append_item(l, (struct isis_item *)r);
}
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+ struct prefix_ipv6 *dest,
+ struct prefix_ipv6 *src,
+ uint32_t metric)
+{
+ isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
+ struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
+ mtid);
+
+ struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
+ r->subtlvs = isis_alloc_subtlvs();
+ r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
+ memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
+}
+
void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
uint8_t metric)
{
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 98edbf14e7..bd1fa3e676 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -313,6 +313,10 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint32_t metric);
void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
struct prefix_ipv6 *dest, uint32_t metric);
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+ struct prefix_ipv6 *dest,
+ struct prefix_ipv6 *src,
+ uint32_t metric);
void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
uint8_t metric);
void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index ac640c5e49..9bc0f2ef35 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -247,6 +247,7 @@ static int isis_zebra_link_params(int command, struct zclient *zclient,
}
static void isis_zebra_route_add_route(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
struct zapi_route api;
@@ -264,6 +265,10 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
api.type = ZEBRA_ROUTE_ISIS;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
+ if (src_p && src_p->prefixlen) {
+ api.src_prefix = *src_p;
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+ }
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = route_info->cost;
@@ -322,6 +327,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
}
static void isis_zebra_route_del_route(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
struct zapi_route api;
@@ -334,21 +340,26 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
api.type = ZEBRA_ROUTE_ISIS;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
+ if (src_p && src_p->prefixlen) {
+ api.src_prefix = *src_p;
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+ }
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
void isis_zebra_route_update(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
if (zclient->sock < 0)
return;
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE))
- isis_zebra_route_add_route(prefix, route_info);
+ isis_zebra_route_add_route(prefix, src_p, route_info);
else
- isis_zebra_route_del_route(prefix, route_info);
+ isis_zebra_route_del_route(prefix, src_p, route_info);
}
static int isis_zebra_read(int command, struct zclient *zclient,
@@ -359,24 +370,23 @@ static int isis_zebra_read(int command, struct zclient *zclient,
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
- /* we completely ignore srcdest routes for now. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
- return 0;
-
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
* into IS-IS causing us to start advertising default reachabity
* without this check)
*/
- if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
+ if (api.prefix.prefixlen == 0
+ && api.src_prefix.prefixlen == 0
+ && api.type == ZEBRA_ROUTE_ISIS) {
command = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
+ }
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
- isis_redist_add(api.type, &api.prefix, api.distance,
- api.metric);
+ isis_redist_add(api.type, &api.prefix, &api.src_prefix,
+ api.distance, api.metric);
else
- isis_redist_delete(api.type, &api.prefix);
+ isis_redist_delete(api.type, &api.prefix, &api.src_prefix);
return 0;
}
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index bd7bf2b5c5..4fbcf87217 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -28,6 +28,7 @@ void isis_zebra_init(struct thread_master *);
void isis_zebra_stop(void);
void isis_zebra_route_update(struct prefix *prefix,
+ struct prefix_ipv6 *src_p,
struct isis_route_info *route_info);
int isis_distribute_list_update(int routetype);
void isis_zebra_redistribute_set(afi_t afi, int type);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index cecaa0693d..a19f287453 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -118,13 +118,9 @@ struct isis_area *isis_area_create(const char *area_tag)
*/
if (area->is_type & IS_LEVEL_1) {
area->lspdb[0] = lsp_db_init();
- area->route_table[0] = route_table_init();
- area->route_table6[0] = route_table_init();
}
if (area->is_type & IS_LEVEL_2) {
area->lspdb[1] = lsp_db_init();
- area->route_table[1] = route_table_init();
- area->route_table6[1] = route_table_init();
}
spftree_area_init(area);
@@ -232,6 +228,10 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
area->lspdb[1] = NULL;
}
+ /* invalidate and verify to delete all routes from zebra */
+ isis_area_invalidate_routes(area, ISIS_LEVEL1 & ISIS_LEVEL2);
+ isis_area_verify_routes(area);
+
spftree_area_del(area);
THREAD_TIMER_OFF(area->spf_timer[0]);
@@ -240,27 +240,6 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
spf_backoff_free(area->spf_delay_ietf[0]);
spf_backoff_free(area->spf_delay_ietf[1]);
- /* invalidate and validate would delete all routes from zebra */
- isis_route_invalidate(area);
- isis_route_validate(area);
-
- if (area->route_table[0]) {
- route_table_finish(area->route_table[0]);
- area->route_table[0] = NULL;
- }
- if (area->route_table[1]) {
- route_table_finish(area->route_table[1]);
- area->route_table[1] = NULL;
- }
- if (area->route_table6[0]) {
- route_table_finish(area->route_table6[0]);
- area->route_table6[0] = NULL;
- }
- if (area->route_table6[1]) {
- route_table_finish(area->route_table6[1]);
- area->route_table6[1] = NULL;
- }
-
isis_redist_area_finish(area);
for (ALL_LIST_ELEMENTS(area->area_addrs, node, nnode, addr)) {
@@ -1340,10 +1319,16 @@ DEFUN (show_isis_summary,
vty_out(vty, "\n");
vty_out(vty, " IPv4 route computation:\n");
- isis_spf_print(area->spftree[level - 1], vty);
+ isis_spf_print(area->spftree[SPFTREE_IPV4][level - 1],
+ vty);
vty_out(vty, " IPv6 route computation:\n");
- isis_spf_print(area->spftree6[level - 1], vty);
+ isis_spf_print(area->spftree[SPFTREE_IPV6][level - 1],
+ vty);
+
+ vty_out(vty, " IPv6 dst-src route computation:\n");
+ isis_spf_print(area->spftree[SPFTREE_DSTSRC][level-1],
+ vty);
}
}
vty_out(vty, "\n");
@@ -1680,29 +1665,42 @@ int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
passwd, snp_auth);
}
+void isis_area_invalidate_routes(struct isis_area *area, int levels)
+{
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ if (!(level & levels))
+ continue;
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ isis_spf_invalidate_routes(
+ area->spftree[tree][level - 1]);
+ }
+ }
+}
+
+void isis_area_verify_routes(struct isis_area *area)
+{
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++)
+ isis_spf_verify_routes(area, area->spftree[tree]);
+}
+
static void area_resign_level(struct isis_area *area, int level)
{
+ isis_area_invalidate_routes(area, level);
+ isis_area_verify_routes(area);
+
if (area->lspdb[level - 1]) {
lsp_db_destroy(area->lspdb[level - 1]);
area->lspdb[level - 1] = NULL;
}
- if (area->spftree[level - 1]) {
- isis_spftree_del(area->spftree[level - 1]);
- area->spftree[level - 1] = NULL;
- }
- if (area->spftree6[level - 1]) {
- isis_spftree_del(area->spftree6[level - 1]);
- area->spftree6[level - 1] = NULL;
+
+ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ if (area->spftree[tree][level - 1]) {
+ isis_spftree_del(area->spftree[tree][level - 1]);
+ area->spftree[tree][level - 1] = NULL;
+ }
}
+
THREAD_TIMER_OFF(area->spf_timer[level - 1]);
- if (area->route_table[level - 1]) {
- route_table_finish(area->route_table[level - 1]);
- area->route_table[level - 1] = NULL;
- }
- if (area->route_table6[level - 1]) {
- route_table_finish(area->route_table6[level - 1]);
- area->route_table6[level - 1] = NULL;
- }
sched_debug(
"ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.",
@@ -1731,10 +1729,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)
if (area->lspdb[1] == NULL)
area->lspdb[1] = lsp_db_init();
- if (area->route_table[1] == NULL)
- area->route_table[1] = route_table_init();
- if (area->route_table6[1] == NULL)
- area->route_table6[1] = route_table_init();
break;
case IS_LEVEL_1_AND_2:
@@ -1750,10 +1744,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)
if (area->lspdb[0] == NULL)
area->lspdb[0] = lsp_db_init();
- if (area->route_table[0] == NULL)
- area->route_table[0] = route_table_init();
- if (area->route_table6[0] == NULL)
- area->route_table6[0] = route_table_init();
break;
default:
diff --git a/isisd/isisd.h b/isisd/isisd.h
index d1ad9f3b8e..ce602e4402 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -63,13 +63,17 @@ struct isis {
extern struct isis *isis;
DECLARE_QOBJ_TYPE(isis_area)
+enum spf_tree_id {
+ SPFTREE_IPV4 = 0,
+ SPFTREE_IPV6,
+ SPFTREE_DSTSRC,
+ SPFTREE_COUNT
+};
+
struct isis_area {
struct isis *isis; /* back pointer */
dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */
- struct isis_spftree *spftree[ISIS_LEVELS]; /* The v4 SPTs */
- struct route_table *route_table[ISIS_LEVELS]; /* IPv4 routes */
- struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v6 SPTs */
- struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */
+ struct isis_spftree *spftree[SPFTREE_COUNT][ISIS_LEVELS];
#define DEFAULT_LSP_MTU 1497
unsigned int lsp_mtu; /* Size of LSPs to generate */
struct list *circuit_list; /* IS-IS circuits */
@@ -144,6 +148,9 @@ struct isis_area *isis_area_lookup(const char *);
int isis_area_get(struct vty *vty, const char *area_tag);
void print_debug(struct vty *, int, int);
+void isis_area_invalidate_routes(struct isis_area *area, int levels);
+void isis_area_verify_routes(struct isis_area *area);
+
void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit);
void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname);
diff --git a/lib/command.h b/lib/command.h
index 2d333b098a..a001a90e2e 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -338,6 +338,7 @@ struct cmd_node {
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
#define ROUTER_STR "Enable a routing process\n"
#define AS_STR "AS number\n"
+#define MAC_STR "MAC address\n"
#define MBGP_STR "MBGP information\n"
#define MATCH_STR "Match values from routing table\n"
#define SET_STR "Set values in destination routing protocol\n"
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 9ea5e985cd..86a5bd29f8 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -745,9 +745,14 @@ static int frr_config_read_in(struct thread *t)
{
if (!vty_read_config(di->config_file, config_default) &&
di->backup_config_file) {
+ char *orig = XSTRDUP(MTYPE_TMP, host_config_get());
+
zlog_info("Attempting to read backup config file: %s specified",
di->backup_config_file);
vty_read_config(di->backup_config_file, config_default);
+
+ host_config_set(orig);
+ XFREE(MTYPE_TMP, orig);
}
return 0;
}
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index 32f8e8ca5b..4497faf6fc 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -281,13 +281,12 @@ void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p,
}
}
-const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
+const char *srcdest2str(const struct prefix *dst_p,
+ const struct prefix_ipv6 *src_p,
+ char *str, int size)
{
- const struct prefix *dst_p, *src_p;
char dst_buf[PREFIX_STRLEN], src_buf[PREFIX_STRLEN];
- srcdest_rnode_prefixes(rn, &dst_p, &src_p);
-
snprintf(str, size, "%s%s%s",
prefix2str(dst_p, dst_buf, sizeof(dst_buf)),
(src_p && src_p->prefixlen) ? " from " : "",
@@ -296,3 +295,11 @@ const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
: "");
return str;
}
+
+const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
+{
+ const struct prefix *dst_p, *src_p;
+
+ srcdest_rnode_prefixes(rn, &dst_p, &src_p);
+ return srcdest2str(dst_p, (struct prefix_ipv6*)src_p, str, size);
+}
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 5f97f02bac..9ceb876f81 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -64,6 +64,9 @@ extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
extern void srcdest_rnode_prefixes(struct route_node *rn,
const struct prefix **p,
const struct prefix **src_p);
+extern const char *srcdest2str(const struct prefix *dst_p,
+ const struct prefix_ipv6 *src_p,
+ char *str, int size);
extern const char *srcdest_rnode2str(struct route_node *rn, char *str,
int size);
extern struct route_node *srcdest_route_next(struct route_node *rn);
diff --git a/lib/zebra.h b/lib/zebra.h
index 98428eaab2..c2d135bbeb 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -365,6 +365,22 @@ struct in_pktinfo {
_a < _b ? _a : _b; \
})
+#ifndef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+#endif
+
#define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0]))
/* For old definition. */
@@ -414,6 +430,7 @@ extern const char *zserv_command_string(unsigned int command);
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
#define ZEBRA_FLAG_EVPN_ROUTE 0x400
+#define ZEBRA_FLAG_RR_USE_DISTANCE 0x800
/* ZEBRA_FLAG_BLACKHOLE was 0x04 */
/* ZEBRA_FLAG_REJECT was 0x80 */
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 74dfed0455..0a64c8db3d 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -352,7 +352,7 @@ int pim_ecmp_nexthop_search(struct pim_instance *pim,
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed)
{
- struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr;
+ struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL;
struct interface *ifps[MULTIPATH_NUM];
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 5007d6c174..783f931752 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -854,9 +854,9 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
__PRETTY_FUNCTION__, buf, buf1);
}
pim_rpf_set_refresh_time(pim);
- pim_ecmp_nexthop_lookup(pim,
- &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1);
+ (void)pim_ecmp_nexthop_lookup(
+ pim, &rp_info->rp.source_nexthop, &nht_p,
+ &rp_info->group, 1);
}
return (&rp_info->rp);
}
diff --git a/redhat/daemons b/redhat/daemons
index b674d738b8..f9dbffea4d 100644
--- a/redhat/daemons
+++ b/redhat/daemons
@@ -51,6 +51,7 @@ eigrpd=no
babeld=no
sharpd=no
pbrd=no
+staticd=no
#
# Command line options for the daemons
#
@@ -68,6 +69,7 @@ eigrpd_options=("-A 127.0.0.1")
babeld_options=("-A 127.0.0.1")
sharpd_options=("-A 127.0.0.1")
pbrd_options=("-A 127.0.0.1")
+staticd_options=("-A 127.0.0.1")
#
# If the vtysh_enable is yes, then the unified config is read
diff --git a/redhat/frr.init b/redhat/frr.init
index 19b282fe1a..740aa5b64d 100755
--- a/redhat/frr.init
+++ b/redhat/frr.init
@@ -33,7 +33,7 @@ V_PATH=/var/run/frr
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd"
MAX_INSTANCES=5
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 85fb309048..f5b116978e 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -85,7 +85,7 @@
%{!?frr_gid: %global frr_gid 92 }
%{!?vty_gid: %global vty_gid 85 }
-%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
+%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd
%if %{with_ldpd}
%define daemon_ldpd ldpd
@@ -416,6 +416,7 @@ zebra_spec_add_service ()
zebra_spec_add_service zebrasrv 2600/tcp "zebra service"
zebra_spec_add_service zebra 2601/tcp "zebra vty"
+zebra_spec_add_service staticd 2616/tcp "staticd vty"
zebra_spec_add_service ripd 2602/tcp "RIPd vty"
zebra_spec_add_service ripngd 2603/tcp "RIPngd vty"
zebra_spec_add_service ospfd 2604/tcp "OSPFd vty"
@@ -561,6 +562,7 @@ fi
%{_infodir}/frr.info.gz
%{_mandir}/man*/*
%{_sbindir}/zebra
+%{_sbindir}/staticd
%{_sbindir}/ospfd
%{_sbindir}/ripd
%{_sbindir}/bgpd
diff --git a/staticd/.gitignore b/staticd/.gitignore
new file mode 100644
index 0000000000..af895301ad
--- /dev/null
+++ b/staticd/.gitignore
@@ -0,0 +1,2 @@
+libstatic.a
+staticd
diff --git a/staticd/Makefile b/staticd/Makefile
new file mode 100644
index 0000000000..ecd33df68c
--- /dev/null
+++ b/staticd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. staticd/staticd
+%: ALWAYS
+ @$(MAKE) -s -C .. staticd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/staticd/static_main.c b/staticd/static_main.c
new file mode 100644
index 0000000000..82d52a17d6
--- /dev/null
+++ b/staticd/static_main.c
@@ -0,0 +1,152 @@
+/*
+ * STATICd - main code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include <lib/version.h>
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "libfrr.h"
+#include "vrf.h"
+#include "nexthop.h"
+
+#include "static_vrf.h"
+#include "static_vty.h"
+#include "static_routes.h"
+#include "static_zebra.h"
+
+char backup_config_file[256];
+
+bool mpls_enabled;
+
+zebra_capabilities_t _caps_p[] = {
+};
+
+struct zebra_privs_t static_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0};
+
+struct option longopts[] = { { 0 } };
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* SIGHUP handler. */
+static void sighup(void)
+{
+ zlog_info("SIGHUP received");
+}
+
+/* SIGINT / SIGTERM handler. */
+static void sigint(void)
+{
+ zlog_notice("Terminating on signal");
+
+ exit(0);
+}
+
+/* SIGUSR1 handler. */
+static void sigusr1(void)
+{
+ zlog_rotate();
+}
+
+struct quagga_signal_t static_signals[] = {
+ {
+ .signal = SIGHUP,
+ .handler = &sighup,
+ },
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
+
+#define STATIC_VTY_PORT 2616
+
+FRR_DAEMON_INFO(staticd, STATIC, .vty_port = STATIC_VTY_PORT,
+
+ .proghelp = "Implementation of STATIC.",
+
+ .signals = static_signals,
+ .n_signals = array_size(static_signals),
+
+ .privs = &static_privs,
+)
+
+int main(int argc, char **argv, char **envp)
+{
+ frr_preinit(&staticd_di, argc, argv);
+ frr_opt_add("", longopts, "");
+
+ while (1) {
+ int opt;
+
+ opt = frr_getopt(argc, argv, NULL);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case 0:
+ break;
+ default:
+ frr_help_exit(1);
+ break;
+ }
+ }
+
+ master = frr_init();
+
+ static_vrf_init();
+
+ static_zebra_init();
+ static_vty_init();
+
+ snprintf(backup_config_file, sizeof(backup_config_file),
+ "%s/zebra.conf", frr_sysconfdir);
+ staticd_di.backup_config_file = backup_config_file;
+
+ frr_config_fork();
+ frr_run(master);
+
+ /* Not reached. */
+ return 0;
+}
diff --git a/staticd/static_memory.c b/staticd/static_memory.c
new file mode 100644
index 0000000000..77ca4a3439
--- /dev/null
+++ b/staticd/static_memory.c
@@ -0,0 +1,28 @@
+/*
+ * static memory code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include <memory.h>
+
+#include "staticd/static_memory.h"
+
+DEFINE_MGROUP(STATIC, "staticd")
+
+DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route");
diff --git a/staticd/static_memory.h b/staticd/static_memory.h
new file mode 100644
index 0000000000..77a0db3b12
--- /dev/null
+++ b/staticd/static_memory.h
@@ -0,0 +1,28 @@
+/*
+ * static memory code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __STATIC_MEMORY_H__
+
+#include "memory.h"
+
+DECLARE_MGROUP(STATIC)
+
+DECLARE_MTYPE(STATIC_ROUTE);
+
+#endif
diff --git a/staticd/static_nht.c b/staticd/static_nht.c
new file mode 100644
index 0000000000..f9f937f905
--- /dev/null
+++ b/staticd/static_nht.c
@@ -0,0 +1,81 @@
+/*
+ * Static NHT code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "vrf.h"
+#include "nexthop.h"
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_zebra.h"
+#include "static_nht.h"
+
+void static_nht_update(struct prefix *p, uint32_t nh_num,
+ afi_t afi, vrf_id_t vrf_id)
+{
+ struct route_table *stable;
+ struct static_route *si;
+ struct static_vrf *svrf;
+ struct route_node *rn;
+ struct vrf *vrf;
+ bool orig;
+ bool reinstall;
+
+ vrf = vrf_lookup_by_id(vrf_id);
+
+ if (!vrf->info)
+ return;
+
+ svrf = vrf->info;
+ stable = static_vrf_static_table(afi, SAFI_UNICAST, svrf);
+ if (!stable)
+ return;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ reinstall = false;
+ for (si = rn->info; si; si = si->next) {
+ if (si->type != STATIC_IPV4_GATEWAY &&
+ si->type != STATIC_IPV4_GATEWAY_IFNAME &&
+ si->type != STATIC_IPV6_GATEWAY &&
+ si->type != STATIC_IPV6_GATEWAY_IFNAME)
+ continue;
+
+ orig = si->nh_valid;
+ if (p->family == AF_INET &&
+ p->u.prefix4.s_addr == si->addr.ipv4.s_addr)
+ si->nh_valid = !!nh_num;
+
+ if (p->family == AF_INET6 &&
+ memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0)
+ si->nh_valid = !!nh_num;
+
+ if (orig != si->nh_valid)
+ reinstall = true;
+
+ if (reinstall) {
+ static_zebra_route_add(rn, si, vrf_id,
+ SAFI_UNICAST, true);
+ reinstall = false;
+ }
+ }
+ }
+}
diff --git a/staticd/static_nht.h b/staticd/static_nht.h
new file mode 100644
index 0000000000..f273c71bba
--- /dev/null
+++ b/staticd/static_nht.h
@@ -0,0 +1,25 @@
+/*
+ * Static NHT header.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __STATIC_NHT_H__
+#define __STATIC_NHT_H__
+
+extern void static_nht_update(struct prefix *p, uint32_t nh_num,
+ afi_t afi, vrf_id_t vrf_id);
+#endif
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
new file mode 100644
index 0000000000..ef0e6d057a
--- /dev/null
+++ b/staticd/static_routes.c
@@ -0,0 +1,506 @@
+/*
+ * STATICd - route code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include <lib/nexthop.h>
+#include <lib/memory.h>
+#include <lib/srcdest_table.h>
+#include <lib/if.h>
+#include <lib/vty.h>
+#include <lib/vrf.h>
+#include <lib/memory.h>
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_memory.h"
+#include "static_zebra.h"
+
+/* Install static route into rib. */
+static void static_install_route(struct route_node *rn,
+ struct static_route *si_changed, safi_t safi)
+{
+ struct static_route *si;
+
+ for (si = rn->info; si; si = si->next)
+ static_zebra_nht_register(si, true);
+
+ si = rn->info;
+ if (si)
+ static_zebra_route_add(rn, si_changed, si->vrf_id, safi, true);
+
+}
+
+/* Uninstall static route from RIB. */
+static void static_uninstall_route(vrf_id_t vrf_id, safi_t safi,
+ struct route_node *rn,
+ struct static_route *si_changed)
+{
+
+ if (rn->info)
+ static_zebra_route_add(rn, si_changed, vrf_id, safi, true);
+ else
+ static_zebra_route_add(rn, si_changed, vrf_id, safi, false);
+}
+
+int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
+ struct prefix_ipv6 *src_p, union g_addr *gate,
+ const char *ifname, enum static_blackhole_type bh_type,
+ route_tag_t tag, uint8_t distance, struct static_vrf *svrf,
+ struct static_vrf *nh_svrf,
+ struct static_nh_label *snh_label,
+ uint32_t table_id)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct static_route *pp;
+ struct static_route *cp;
+ struct static_route *update = NULL;
+ struct route_table *stable = svrf->stable[afi][safi];
+
+ if (!stable)
+ return -1;
+
+ if (!gate && (type == STATIC_IPV4_GATEWAY
+ || type == STATIC_IPV4_GATEWAY_IFNAME
+ || type == STATIC_IPV6_GATEWAY
+ || type == STATIC_IPV6_GATEWAY_IFNAME))
+ return -1;
+
+ if (!ifname
+ && (type == STATIC_IFNAME || type == STATIC_IPV4_GATEWAY_IFNAME
+ || type == STATIC_IPV6_GATEWAY_IFNAME))
+ return -1;
+
+ /* Lookup static route prefix. */
+ rn = srcdest_rnode_get(stable, p, src_p);
+
+ /* Do nothing if there is a same static route. */
+ for (si = rn->info; si; si = si->next) {
+ if (type == si->type
+ && (!gate
+ || ((afi == AFI_IP
+ && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
+ || (afi == AFI_IP6
+ && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
+ && (!strcmp(ifname ? ifname : "", si->ifname))) {
+ if ((distance == si->distance) && (tag == si->tag)
+ && (table_id == si->table_id)
+ && !memcmp(&si->snh_label, snh_label,
+ sizeof(struct static_nh_label))
+ && si->bh_type == bh_type) {
+ route_unlock_node(rn);
+ return 0;
+ }
+ update = si;
+ }
+ }
+
+ /* Distance or tag or label changed, delete existing first. */
+ if (update)
+ static_delete_route(afi, safi, type, p, src_p, gate, ifname,
+ update->tag, update->distance, svrf,
+ &update->snh_label, table_id);
+
+ /* Make new static route structure. */
+ si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route));
+
+ si->type = type;
+ si->distance = distance;
+ si->bh_type = bh_type;
+ si->tag = tag;
+ si->vrf_id = svrf->vrf->vrf_id;
+ si->nh_vrf_id = nh_svrf->vrf->vrf_id;
+ strcpy(si->nh_vrfname, nh_svrf->vrf->name);
+ si->table_id = table_id;
+
+ if (ifname)
+ strlcpy(si->ifname, ifname, sizeof(si->ifname));
+ si->ifindex = IFINDEX_INTERNAL;
+
+ switch (type) {
+ case STATIC_IPV4_GATEWAY:
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ si->addr.ipv4 = gate->ipv4;
+ break;
+ case STATIC_IPV6_GATEWAY:
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ si->addr.ipv6 = gate->ipv6;
+ break;
+ case STATIC_IFNAME:
+ break;
+ }
+
+ /* Save labels, if any. */
+ memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label));
+
+ /*
+ * Add new static route information to the tree with sort by
+ * distance value and gateway address.
+ */
+ for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) {
+ if (si->distance < cp->distance)
+ break;
+ if (si->distance > cp->distance)
+ continue;
+ if (si->type == STATIC_IPV4_GATEWAY
+ && cp->type == STATIC_IPV4_GATEWAY) {
+ if (ntohl(si->addr.ipv4.s_addr)
+ < ntohl(cp->addr.ipv4.s_addr))
+ break;
+ if (ntohl(si->addr.ipv4.s_addr)
+ > ntohl(cp->addr.ipv4.s_addr))
+ continue;
+ }
+ }
+
+ /* Make linked list. */
+ if (pp)
+ pp->next = si;
+ else
+ rn->info = si;
+ if (cp)
+ cp->prev = si;
+ si->prev = pp;
+ si->next = cp;
+
+ /* check whether interface exists in system & install if it does */
+ if (!ifname)
+ static_install_route(rn, si, safi);
+ else {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
+ if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
+ si->ifindex = ifp->ifindex;
+ static_install_route(rn, si, safi);
+ } else
+ zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
+ ifname);
+ }
+
+ return 1;
+}
+
+int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
+ struct prefix_ipv6 *src_p, union g_addr *gate,
+ const char *ifname, route_tag_t tag, uint8_t distance,
+ struct static_vrf *svrf,
+ struct static_nh_label *snh_label,
+ uint32_t table_id)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct route_table *stable;
+
+ /* Lookup table. */
+ stable = static_vrf_static_table(afi, safi, svrf);
+ if (!stable)
+ return -1;
+
+ /* Lookup static route prefix. */
+ rn = srcdest_rnode_lookup(stable, p, src_p);
+ if (!rn)
+ return 0;
+
+ /* Find same static route is the tree */
+ for (si = rn->info; si; si = si->next)
+ if (type == si->type
+ && (!gate
+ || ((afi == AFI_IP
+ && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
+ || (afi == AFI_IP6
+ && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
+ && (!strcmp(ifname ? ifname : "", si->ifname))
+ && (!tag || (tag == si->tag))
+ && (table_id == si->table_id)
+ && (!snh_label->num_labels
+ || !memcmp(&si->snh_label, snh_label,
+ sizeof(struct static_nh_label))))
+ break;
+
+ /* Can't find static route. */
+ if (!si) {
+ route_unlock_node(rn);
+ return 0;
+ }
+
+ static_zebra_nht_register(si, false);
+
+ /* Unlink static route from linked list. */
+ if (si->prev)
+ si->prev->next = si->next;
+ else
+ rn->info = si->next;
+ if (si->next)
+ si->next->prev = si->prev;
+
+ /*
+ * If we have other si nodes then route replace
+ * else delete the route
+ */
+ static_uninstall_route(si->vrf_id, safi, rn, si);
+ route_unlock_node(rn);
+
+ /* Free static route configuration. */
+ XFREE(MTYPE_STATIC_ROUTE, si);
+
+ route_unlock_node(rn);
+
+ return 1;
+}
+
+static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
+ safi_t safi)
+{
+ struct route_table *stable;
+ struct route_node *rn;
+ struct static_route *si;
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct static_vrf *svrf;
+
+ svrf = vrf->info;
+
+ stable = static_vrf_static_table(afi, safi, svrf);
+ if (!stable)
+ continue;
+
+ for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ if (!si->ifname[0])
+ continue;
+ if (up) {
+ if (strcmp(si->ifname, ifp->name))
+ continue;
+ si->ifindex = ifp->ifindex;
+ } else {
+ if (si->ifindex != ifp->ifindex)
+ continue;
+ si->ifindex = IFINDEX_INTERNAL;
+ }
+
+ static_install_route(rn, si, safi);
+ }
+ }
+ }
+}
+
+/*
+ * This function looks at a svrf's stable and notices if any of the
+ * nexthops we are using are part of the vrf coming up.
+ * If we are using them then cleanup the nexthop vrf id
+ * to be the new value and then re-installs them
+ *
+ *
+ * stable -> The table we are looking at.
+ * svrf -> The newly changed vrf.
+ * afi -> The afi to look at
+ * safi -> the safi to look at
+ */
+static void static_fixup_vrf(struct static_vrf *svrf,
+ struct route_table *stable, afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct interface *ifp;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0)
+ continue;
+
+ si->nh_vrf_id = svrf->vrf->vrf_id;
+ if (si->ifindex) {
+ ifp = if_lookup_by_name(si->ifname,
+ si->nh_vrf_id);
+ if (ifp)
+ si->ifindex = ifp->ifindex;
+ else
+ continue;
+ }
+
+ static_install_route(rn, si, safi);
+ }
+ }
+}
+
+/*
+ * This function enables static routes in a svrf as it
+ * is coming up. It sets the new vrf_id as appropriate.
+ *
+ * svrf -> The svrf that is being brought up and enabled by the kernel
+ * stable -> The stable we are looking at.
+ * afi -> the afi in question
+ * safi -> the safi in question
+ */
+static void static_enable_vrf(struct static_vrf *svrf,
+ struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct interface *ifp;
+ struct vrf *vrf = svrf->vrf;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ si->vrf_id = vrf->vrf_id;
+ if (si->ifindex) {
+ ifp = if_lookup_by_name(si->ifname,
+ si->nh_vrf_id);
+ if (ifp)
+ si->ifindex = ifp->ifindex;
+ else
+ continue;
+ }
+ static_install_route(rn, si, safi);
+ }
+ }
+}
+
+/*
+ * When a vrf is being enabled by the kernel, go through all the
+ * static routes in the system that use this vrf (both nexthops vrfs
+ * and the routes vrf )
+ *
+ * enable_svrf -> the vrf being enabled
+ */
+void static_fixup_vrf_ids(struct static_vrf *enable_svrf)
+{
+ struct route_table *stable;
+ struct vrf *vrf;
+ afi_t afi;
+ safi_t safi;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct static_vrf *svrf;
+
+ svrf = vrf->info;
+ /* Install any static routes configured for this VRF. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ stable = svrf->stable[afi][safi];
+ if (!stable)
+ continue;
+
+ static_fixup_vrf(enable_svrf, stable,
+ afi, safi);
+
+ if (enable_svrf == svrf)
+ static_enable_vrf(svrf, stable,
+ afi, safi);
+ }
+ }
+ }
+}
+
+/*
+ * Look at the specified stable and if any of the routes in
+ * this table are using the svrf as the nexthop, uninstall
+ * those routes.
+ *
+ * svrf -> the vrf being disabled
+ * stable -> the table we need to look at.
+ * afi -> the afi in question
+ * safi -> the safi in question
+ */
+static void static_cleanup_vrf(struct static_vrf *svrf,
+ struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0)
+ continue;
+
+ static_uninstall_route(si->vrf_id, safi, rn, si);
+ }
+ }
+}
+
+/*
+ * Look at all static routes in this table and uninstall
+ * them.
+ *
+ * stable -> The table to uninstall from
+ * afi -> The afi in question
+ * safi -> the safi in question
+ */
+static void static_disable_vrf(struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn))
+ for (si = rn->info; si; si = si->next)
+ static_uninstall_route(si->vrf_id, safi, rn, si);
+}
+
+/*
+ * When the disable_svrf is shutdown by the kernel, we call
+ * this function and it cleans up all static routes using
+ * this vrf as a nexthop as well as all static routes
+ * in it's stables.
+ *
+ * disable_svrf - The vrf being disabled
+ */
+void static_cleanup_vrf_ids(struct static_vrf *disable_svrf)
+{
+ struct vrf *vrf;
+ afi_t afi;
+ safi_t safi;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct static_vrf *svrf;
+
+ svrf = vrf->info;
+
+ /* Uninstall any static routes configured for this VRF. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ struct route_table *stable;
+
+ stable = svrf->stable[afi][safi];
+ if (!stable)
+ continue;
+
+ static_cleanup_vrf(disable_svrf, stable,
+ afi, safi);
+
+ if (disable_svrf == svrf)
+ static_disable_vrf(stable, afi, safi);
+ }
+ }
+ }
+}
+
+/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
+void static_ifindex_update(struct interface *ifp, bool up)
+{
+ static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
+ static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
+ static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
+ static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
+}
diff --git a/zebra/zebra_static.h b/staticd/static_routes.h
index 0be434fff2..bb1b664378 100644
--- a/zebra/zebra_static.h
+++ b/staticd/static_routes.h
@@ -1,28 +1,26 @@
/*
- * Static Routing Information header
- * Copyright (C) 2016 Cumulus Networks
+ * STATICd - static routes header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
* Donald Sharp
*
- * This file is part of Quagga.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
*
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef __ZEBRA_STATIC_H__
-#define __ZEBRA_STATIC_H__
+#ifndef __STATIC_ROUTES_H__
+#define __STATIC_ROUTES_H__
-#include "zebra/zebra_mpls.h"
+#include "lib/mpls.h"
/* Static route label information */
struct static_nh_label {
@@ -44,7 +42,7 @@ typedef enum {
STATIC_BLACKHOLE,
STATIC_IPV6_GATEWAY,
STATIC_IPV6_GATEWAY_IFNAME,
-} zebra_static_types;
+} static_types;
/* Static route information. */
struct static_route {
@@ -64,7 +62,7 @@ struct static_route {
route_tag_t tag;
/* Flag for this static route's type. */
- zebra_static_types type;
+ static_types type;
/*
* Nexthop value.
@@ -72,43 +70,41 @@ struct static_route {
enum static_blackhole_type bh_type;
union g_addr addr;
ifindex_t ifindex;
+ bool nh_registered;
+ bool nh_valid;
char ifname[INTERFACE_NAMSIZ + 1];
/* Label information */
struct static_nh_label snh_label;
- /* Table Information */
uint32_t table_id;
};
-extern void static_install_route(afi_t afi, safi_t safi, const struct prefix *p,
- const struct prefix_ipv6 *src_p,
- struct static_route *si);
-extern void static_uninstall_route(afi_t afi, safi_t safi,
- const struct prefix *p,
- const struct prefix_ipv6 *src_p,
- struct static_route *si);
-
-extern int static_add_route(afi_t, safi_t safi, uint8_t type, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- const char *ifname,
+extern bool mpls_enabled;
+
+extern struct zebra_privs_t static_privs;
+
+void static_fixup_vrf_ids(struct static_vrf *svrf);
+
+extern int static_add_route(afi_t afi, safi_t safi, uint8_t type,
+ struct prefix *p, struct prefix_ipv6 *src_p,
+ union g_addr *gate, const char *ifname,
enum static_blackhole_type bh_type, route_tag_t tag,
- uint8_t distance, struct zebra_vrf *zvrf,
- struct zebra_vrf *nh_zvrf,
+ uint8_t distance, struct static_vrf *svrf,
+ struct static_vrf *nh_svrf,
struct static_nh_label *snh_label,
uint32_t table_id);
-extern int static_delete_route(afi_t, safi_t safi, uint8_t type,
+extern int static_delete_route(afi_t afi, safi_t safi, uint8_t type,
struct prefix *p, struct prefix_ipv6 *src_p,
union g_addr *gate, const char *ifname,
route_tag_t tag, uint8_t distance,
- struct zebra_vrf *zvrf,
+ struct static_vrf *svrf,
struct static_nh_label *snh_label,
uint32_t table_id);
-extern void static_ifindex_update(struct interface *ifp, bool up);
+extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
-extern void static_cleanup_vrf_ids(struct zebra_vrf *zvrf);
-extern void static_fixup_vrf_ids(struct zebra_vrf *zvrf);
+extern void static_ifindex_update(struct interface *ifp, bool up);
#endif
diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c
new file mode 100644
index 0000000000..6946f21271
--- /dev/null
+++ b/staticd/static_vrf.c
@@ -0,0 +1,196 @@
+/*
+ * STATICd - vrf code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "vrf.h"
+#include "nexthop.h"
+#include "table.h"
+#include "srcdest_table.h"
+
+#include "static_memory.h"
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_vty.h"
+
+static void zebra_stable_node_cleanup(struct route_table *table,
+ struct route_node *node)
+{
+ struct static_route *si, *next;
+
+ if (node->info)
+ for (si = node->info; si; si = next) {
+ next = si->next;
+ XFREE(MTYPE_STATIC_ROUTE, si);
+ }
+}
+
+static struct static_vrf *static_vrf_alloc(void)
+{
+ struct route_table *table;
+ struct static_vrf *svrf;
+ safi_t safi;
+ afi_t afi;
+
+ svrf = XCALLOC(MTYPE_TMP, sizeof(struct static_vrf));
+
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+ if (afi == AFI_IP6)
+ table = srcdest_table_init();
+ else
+ table = route_table_init();
+ table->cleanup = zebra_stable_node_cleanup;
+ svrf->stable[afi][safi] = table;
+ }
+ }
+ return svrf;
+}
+
+static int static_vrf_new(struct vrf *vrf)
+{
+ struct static_vrf *svrf;
+
+ svrf = static_vrf_alloc();
+ vrf->info = svrf;
+ svrf->vrf = vrf;
+
+ return 0;
+}
+
+static int static_vrf_enable(struct vrf *vrf)
+{
+ static_fixup_vrf_ids(vrf->info);
+
+ /*
+ * We may have static routes that are now possible to
+ * insert into the appropriate tables
+ */
+ static_config_install_delayed_routes(vrf->info);
+
+ return 0;
+}
+
+static int static_vrf_disable(struct vrf *vrf)
+{
+ return 0;
+}
+
+static int static_vrf_delete(struct vrf *vrf)
+{
+ struct route_table *table;
+ struct static_vrf *svrf;
+ safi_t safi;
+ afi_t afi;
+
+ svrf = vrf->info;
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+ table = svrf->stable[afi][safi];
+ route_table_finish(table);
+ svrf->stable[afi][safi] = NULL;
+ }
+ }
+ return 0;
+}
+
+/* Lookup the static routing table in a VRF. */
+struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
+ struct static_vrf *svrf)
+{
+ if (!svrf)
+ return NULL;
+
+ if (afi >= AFI_MAX || safi >= SAFI_MAX)
+ return NULL;
+
+ return svrf->stable[afi][safi];
+}
+
+struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id)
+{
+ struct vrf *vrf;
+
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (vrf)
+ return ((struct static_vrf *)vrf->info);
+
+ return NULL;
+}
+
+struct static_vrf *static_vrf_lookup_by_name(const char *name)
+{
+ struct vrf *vrf;
+
+ if (!name)
+ name = VRF_DEFAULT_NAME;
+
+ vrf = vrf_lookup_by_name(name);
+ if (vrf)
+ return ((struct static_vrf *)vrf->info);
+
+ return NULL;
+}
+
+static int static_vrf_config_write(struct vty *vty)
+{
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ static_config(vty, vrf->info, AFI_IP,
+ SAFI_UNICAST, "ip route");
+ static_config(vty, vrf->info, AFI_IP,
+ SAFI_MULTICAST, "ip mroute");
+ static_config(vty, vrf->info, AFI_IP6,
+ SAFI_UNICAST, "ipv6 route");
+ }
+
+ return 0;
+}
+
+int static_vrf_has_config(struct static_vrf *svrf)
+{
+ struct route_table *table;
+ safi_t safi;
+ afi_t afi;
+
+ /*
+ * NOTE: This is a don't care for the default VRF, but we go through
+ * the motions to keep things consistent.
+ */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ table = svrf->stable[afi][safi];
+ if (!table)
+ continue;
+ if (route_table_count(table))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void static_vrf_init(void)
+{
+ vrf_init(static_vrf_new, static_vrf_enable,
+ static_vrf_disable, static_vrf_delete);
+
+ vrf_cmd_init(static_vrf_config_write, &static_privs);
+}
diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h
new file mode 100644
index 0000000000..28fcdd0d36
--- /dev/null
+++ b/staticd/static_vrf.h
@@ -0,0 +1,38 @@
+/*
+ * STATICd - vrf header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __STATIC_VRF_H__
+#define __STATIC_VRF_H__
+
+struct static_vrf {
+ struct vrf *vrf;
+
+ struct route_table *stable[AFI_MAX][SAFI_MAX];
+};
+
+struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name);
+struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id);
+
+int static_vrf_has_config(struct static_vrf *svrf);
+
+void static_vrf_init(void);
+
+struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
+ struct static_vrf *svrf);
+#endif
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
new file mode 100644
index 0000000000..98153f7149
--- /dev/null
+++ b/staticd/static_vty.c
@@ -0,0 +1,1414 @@
+/*
+ * STATICd - vty code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "command.h"
+#include "vty.h"
+#include "vrf.h"
+#include "prefix.h"
+#include "nexthop.h"
+#include "table.h"
+#include "srcdest_table.h"
+#include "mpls.h"
+
+#include "static_vrf.h"
+#include "static_memory.h"
+#include "static_vty.h"
+#include "static_routes.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "staticd/static_vty_clippy.c"
+#endif
+
+static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
+ const char *vrf_name)
+{
+ struct static_vrf *svrf;
+ struct vrf *vrf;
+
+ svrf = static_vrf_lookup_by_name(vrf_name);
+
+ if (svrf)
+ return svrf;
+
+ vrf = vrf_get(VRF_UNKNOWN, vrf_name);
+ if (!vrf) {
+ vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
+ return NULL;
+ }
+ svrf = vrf->info;
+ if (!svrf) {
+ vty_out(vty, "%% Could not create vrf-info %s\n",
+ vrf_name);
+ return NULL;
+ }
+ /* Mark as having FRR configuration */
+ vrf_set_user_cfged(vrf);
+
+ return svrf;
+}
+
+struct static_hold_route {
+ char *vrf_name;
+ char *nhvrf_name;
+ afi_t afi;
+ safi_t safi;
+ char *dest_str;
+ char *mask_str;
+ char *src_str;
+ char *gate_str;
+ char *ifname;
+ char *flag_str;
+ char *tag_str;
+ char *distance_str;
+ char *label_str;
+ char *table_str;
+
+ /* processed & masked destination, used for config display */
+ struct prefix dest;
+};
+
+static struct list *static_list;
+
+static int static_list_compare_helper(const char *s1, const char *s2)
+{
+ /* Are Both NULL */
+ if (s1 == s2)
+ return 0;
+
+ if (!s1 && s2)
+ return -1;
+
+ if (s1 && !s2)
+ return 1;
+
+ return strcmp(s1, s2);
+}
+
+static void static_list_delete(struct static_hold_route *shr)
+{
+ if (shr->vrf_name)
+ XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
+ if (shr->nhvrf_name)
+ XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
+ if (shr->dest_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
+ if (shr->mask_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
+ if (shr->src_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
+ if (shr->gate_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
+ if (shr->ifname)
+ XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
+ if (shr->flag_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
+ if (shr->tag_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
+ if (shr->distance_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
+ if (shr->label_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
+ if (shr->table_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
+
+ XFREE(MTYPE_STATIC_ROUTE, shr);
+}
+
+static int static_list_compare(void *arg1, void *arg2)
+{
+ struct static_hold_route *shr1 = arg1;
+ struct static_hold_route *shr2 = arg2;
+ int ret;
+
+ ret = strcmp(shr1->vrf_name, shr2->vrf_name);
+ if (ret)
+ return ret;
+
+ ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
+ if (ret)
+ return ret;
+
+ ret = shr1->afi - shr2->afi;
+ if (ret)
+ return ret;
+
+ ret = shr1->safi - shr2->safi;
+ if (ret)
+ return ret;
+
+ ret = prefix_cmp(&shr1->dest, &shr2->dest);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->distance_str,
+ shr2->distance_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->table_str,
+ shr2->table_str);
+ if (ret)
+ return ret;
+
+ return static_list_compare_helper(shr1->label_str, shr2->label_str);
+}
+
+
+/* General function for static route. */
+static int zebra_static_route_holdem(
+ struct static_vrf *svrf, struct static_vrf *nh_svrf, afi_t afi,
+ safi_t safi, const char *negate, struct prefix *dest,
+ const char *dest_str, const char *mask_str, const char *src_str,
+ const char *gate_str, const char *ifname, const char *flag_str,
+ const char *tag_str, const char *distance_str, const char *label_str,
+ const char *table_str)
+{
+ struct static_hold_route *shr, *lookup;
+ struct listnode *node;
+
+ zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
+ dest_str);
+
+ shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
+ shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, svrf->vrf->name);
+ shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_svrf->vrf->name);
+ shr->afi = afi;
+ shr->safi = safi;
+ if (dest)
+ prefix_copy(&shr->dest, dest);
+ if (dest_str)
+ shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
+ if (mask_str)
+ shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
+ if (src_str)
+ shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
+ if (gate_str)
+ shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
+ if (ifname)
+ shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
+ if (flag_str)
+ shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
+ if (tag_str)
+ shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
+ if (distance_str)
+ shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
+ if (label_str)
+ shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
+ if (table_str)
+ shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str);
+
+ for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
+ if (static_list_compare(shr, lookup) == 0)
+ break;
+ }
+
+ if (lookup) {
+ if (negate) {
+ listnode_delete(static_list, lookup);
+ static_list_delete(shr);
+ static_list_delete(lookup);
+
+ return CMD_SUCCESS;
+ }
+
+ /*
+ * If a person enters the same line again
+ * we need to silently accept it
+ */
+ goto shr_cleanup;
+ }
+
+ if (!negate) {
+ listnode_add_sort(static_list, shr);
+ return CMD_SUCCESS;
+ }
+
+ shr_cleanup:
+ XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr);
+
+ return CMD_SUCCESS;
+}
+
+static int static_route_leak(
+ struct vty *vty, struct static_vrf *svrf, struct static_vrf *nh_svrf,
+ afi_t afi, safi_t safi, const char *negate, const char *dest_str,
+ const char *mask_str, const char *src_str, const char *gate_str,
+ const char *ifname, const char *flag_str, const char *tag_str,
+ const char *distance_str, const char *label_str, const char *table_str)
+{
+ int ret;
+ uint8_t distance;
+ struct prefix p, src;
+ struct prefix_ipv6 *src_p = NULL;
+ union g_addr gate;
+ union g_addr *gatep = NULL;
+ struct in_addr mask;
+ enum static_blackhole_type bh_type = 0;
+ route_tag_t tag = 0;
+ uint8_t type;
+ struct static_nh_label snh_label;
+ uint32_t table_id = 0;
+
+ ret = str2prefix(dest_str, &p);
+ if (ret <= 0) {
+ if (vty)
+ vty_out(vty, "%% Malformed address\n");
+ else
+ zlog_warn("%s: Malformed address: %s",
+ __PRETTY_FUNCTION__, dest_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ switch (afi) {
+ case AFI_IP:
+ /* Cisco like mask notation. */
+ if (mask_str) {
+ ret = inet_aton(mask_str, &mask);
+ if (ret == 0) {
+ if (vty)
+ vty_out(vty, "%% Malformed address\n");
+ else
+ zlog_warn("%s: Malformed address: %s",
+ __PRETTY_FUNCTION__,
+ mask_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ p.prefixlen = ip_masklen(mask);
+ }
+ break;
+ case AFI_IP6:
+ /* srcdest routing */
+ if (src_str) {
+ ret = str2prefix(src_str, &src);
+ if (ret <= 0 || src.family != AF_INET6) {
+ if (vty)
+ vty_out(vty,
+ "%% Malformed source address\n");
+ else
+ zlog_warn(
+ "%s: Malformed source address: %s",
+ __PRETTY_FUNCTION__, src_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ src_p = (struct prefix_ipv6 *)&src;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask(&p);
+
+ if (svrf->vrf->vrf_id == VRF_UNKNOWN
+ || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) {
+ vrf_set_user_cfged(svrf->vrf);
+ return zebra_static_route_holdem(
+ svrf, nh_svrf, afi, safi, negate, &p, dest_str,
+ mask_str, src_str, gate_str, ifname, flag_str, tag_str,
+ distance_str, label_str, table_str);
+ }
+
+ if (table_str) {
+ /* table configured. check consistent with vrf config
+ */
+ if (svrf->vrf->data.l.table_id != RT_TABLE_MAIN) {
+ if (vty)
+ vty_out(vty,
+ "%% Table %s overlaps vrf table %u\n",
+ table_str, svrf->vrf->data.l.table_id);
+ else
+ zlog_warn(
+ "%s: Table %s overlaps vrf table %u",
+ __PRETTY_FUNCTION__,
+ table_str, svrf->vrf->data.l.table_id);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ /* Administrative distance. */
+ if (distance_str)
+ distance = atoi(distance_str);
+ else
+ distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+ /* tag */
+ if (tag_str)
+ tag = strtoul(tag_str, NULL, 10);
+
+ /* Labels */
+ memset(&snh_label, 0, sizeof(struct static_nh_label));
+ if (label_str) {
+ if (!mpls_enabled) {
+ if (vty)
+ vty_out(vty,
+ "%% MPLS not turned on in kernel, ignoring command\n");
+ else
+ zlog_warn(
+ "%s: MPLS not turned on in kernel ignoring static route to %s",
+ __PRETTY_FUNCTION__, dest_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ int rc = mpls_str2label(label_str, &snh_label.num_labels,
+ snh_label.label);
+ if (rc < 0) {
+ switch (rc) {
+ case -1:
+ if (vty)
+ vty_out(vty, "%% Malformed label(s)\n");
+ else
+ zlog_warn(
+ "%s: Malformed labels specified for route %s",
+ __PRETTY_FUNCTION__, dest_str);
+ break;
+ case -2:
+ if (vty)
+ vty_out(vty,
+ "%% Cannot use reserved label(s) (%d-%d)\n",
+ MPLS_LABEL_RESERVED_MIN,
+ MPLS_LABEL_RESERVED_MAX);
+ else
+ zlog_warn(
+ "%s: Cannot use reserved labels (%d-%d) for %s",
+ __PRETTY_FUNCTION__,
+ MPLS_LABEL_RESERVED_MIN,
+ MPLS_LABEL_RESERVED_MAX,
+ dest_str);
+ break;
+ case -3:
+ if (vty)
+ vty_out(vty,
+ "%% Too many labels. Enter %d or fewer\n",
+ MPLS_MAX_LABELS);
+ else
+ zlog_warn(
+ "%s: Too many labels, Enter %d or fewer for %s",
+ __PRETTY_FUNCTION__,
+ MPLS_MAX_LABELS, dest_str);
+ break;
+ }
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ /* TableID */
+ if (table_str)
+ table_id = atol(table_str);
+
+ /* Null0 static route. */
+ if (ifname != NULL) {
+ if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0
+ || strncasecmp(ifname, "reject", strlen(ifname)) == 0
+ || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) {
+ if (vty)
+ vty_out(vty,
+ "%% Nexthop interface cannot be Null0, reject or blackhole\n");
+ else
+ zlog_warn(
+ "%s: Nexthop interface cannot be Null0, reject or blackhole for %s",
+ __PRETTY_FUNCTION__, dest_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ /* Route flags */
+ if (flag_str) {
+ switch (flag_str[0]) {
+ case 'r':
+ bh_type = STATIC_BLACKHOLE_REJECT;
+ break;
+ case 'b':
+ bh_type = STATIC_BLACKHOLE_DROP;
+ break;
+ case 'N':
+ bh_type = STATIC_BLACKHOLE_NULL;
+ break;
+ default:
+ if (vty)
+ vty_out(vty, "%% Malformed flag %s \n",
+ flag_str);
+ else
+ zlog_warn("%s: Malformed flag %s for %s",
+ __PRETTY_FUNCTION__, flag_str,
+ dest_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ if (gate_str) {
+ if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
+ if (vty)
+ vty_out(vty,
+ "%% Malformed nexthop address %s\n",
+ gate_str);
+ else
+ zlog_warn(
+ "%s: Malformed nexthop address %s for %s",
+ __PRETTY_FUNCTION__, gate_str,
+ dest_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ gatep = &gate;
+ }
+
+ if (gate_str == NULL && ifname == NULL)
+ type = STATIC_BLACKHOLE;
+ else if (gate_str && ifname) {
+ if (afi == AFI_IP)
+ type = STATIC_IPV4_GATEWAY_IFNAME;
+ else
+ type = STATIC_IPV6_GATEWAY_IFNAME;
+ } else if (ifname)
+ type = STATIC_IFNAME;
+ else {
+ if (afi == AFI_IP)
+ type = STATIC_IPV4_GATEWAY;
+ else
+ type = STATIC_IPV6_GATEWAY;
+ }
+
+ if (!negate) {
+ static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
+ bh_type, tag, distance, svrf, nh_svrf,
+ &snh_label, table_id);
+ /* Mark as having FRR configuration */
+ vrf_set_user_cfged(svrf->vrf);
+ } else {
+ static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
+ tag, distance, svrf, &snh_label, table_id);
+ /* If no other FRR config for this VRF, mark accordingly. */
+ if (!static_vrf_has_config(svrf))
+ vrf_reset_user_cfged(svrf->vrf);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int static_route(struct vty *vty, afi_t afi, safi_t safi,
+ const char *negate, const char *dest_str,
+ const char *mask_str, const char *src_str,
+ const char *gate_str, const char *ifname,
+ const char *flag_str, const char *tag_str,
+ const char *distance_str, const char *vrf_name,
+ const char *label_str, const char *table_str)
+{
+ struct static_vrf *svrf;
+
+ /* VRF id */
+ svrf = static_vrf_lookup_by_name(vrf_name);
+
+ /* When trying to delete, the VRF must exist. */
+ if (negate && !svrf) {
+ vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* When trying to create, create the VRF if it doesn't exist.
+ * Note: The VRF isn't active until we hear about it from the kernel.
+ */
+ if (!svrf) {
+ svrf = static_vty_get_unknown_vrf(vty, vrf_name);
+ if (!svrf)
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ return static_route_leak(
+ vty, svrf, svrf, afi, safi, negate, dest_str, mask_str, src_str,
+ gate_str, ifname, flag_str, tag_str, distance_str, label_str,
+ table_str);
+}
+
+void static_config_install_delayed_routes(struct static_vrf *svrf)
+{
+ struct listnode *node, *nnode;
+ struct static_hold_route *shr;
+ struct static_vrf *osvrf, *nh_svrf;
+ int installed;
+
+ for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) {
+ osvrf = static_vrf_lookup_by_name(shr->vrf_name);
+ nh_svrf = static_vrf_lookup_by_name(shr->nhvrf_name);
+
+ if (osvrf != svrf && nh_svrf != svrf)
+ continue;
+
+ if (osvrf->vrf->vrf_id == VRF_UNKNOWN
+ || nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
+ continue;
+
+ installed = static_route_leak(
+ NULL, osvrf, nh_svrf, shr->afi, shr->safi, NULL,
+ shr->dest_str, shr->mask_str, shr->src_str,
+ shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str,
+ shr->distance_str, shr->label_str, shr->table_str);
+
+ if (installed != CMD_SUCCESS)
+ zlog_debug(
+ "%s: Attempt to install %s as a route and it was rejected",
+ __PRETTY_FUNCTION__, shr->dest_str);
+ listnode_delete(static_list, shr);
+ static_list_delete(shr);
+ }
+}
+
+/* Write static route configuration. */
+int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
+ safi_t safi, const char *cmd)
+{
+ struct static_hold_route *shr;
+ struct listnode *node;
+ char spacing[100];
+ struct route_node *rn;
+ struct static_route *si;
+ struct route_table *stable;
+ char buf[SRCDEST2STR_BUFFER];
+ int write = 0;
+
+ stable = svrf->stable[afi][safi];
+ if (stable == NULL)
+ return write;
+
+ sprintf(spacing, "%s%s", (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ",
+ cmd);
+
+ /*
+ * Static routes for vrfs not fully inited
+ */
+ for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) {
+ if (shr->afi != afi || shr->safi != safi)
+ continue;
+
+ if (strcmp(svrf->vrf->name, shr->vrf_name) != 0)
+ continue;
+
+ char dest_str[PREFIX_STRLEN];
+
+ prefix2str(&shr->dest, dest_str, sizeof(dest_str));
+
+ vty_out(vty, "%s ", spacing);
+ if (shr->dest_str)
+ vty_out(vty, "%s ", dest_str);
+ if (shr->src_str)
+ vty_out(vty, "from %s ", shr->src_str);
+ if (shr->gate_str)
+ vty_out(vty, "%s ", shr->gate_str);
+ if (shr->ifname)
+ vty_out(vty, "%s ", shr->ifname);
+ if (shr->flag_str)
+ vty_out(vty, "%s ", shr->flag_str);
+ if (shr->tag_str)
+ vty_out(vty, "tag %s ", shr->tag_str);
+ if (shr->distance_str)
+ vty_out(vty, "%s ", shr->distance_str);
+ if (shr->label_str)
+ vty_out(vty, "label %s ", shr->label_str);
+ if (shr->table_str)
+ vty_out(vty, "table %s", shr->table_str);
+ if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0)
+ vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name);
+ vty_out(vty, "\n");
+ }
+
+ for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
+ for (si = rn->info; si; si = si->next) {
+ vty_out(vty, "%s %s", spacing,
+ srcdest_rnode2str(rn, buf, sizeof(buf)));
+
+ switch (si->type) {
+ case STATIC_IPV4_GATEWAY:
+ vty_out(vty, " %s", inet_ntoa(si->addr.ipv4));
+ break;
+ case STATIC_IPV6_GATEWAY:
+ vty_out(vty, " %s",
+ inet_ntop(AF_INET6, &si->addr.ipv6, buf,
+ sizeof(buf)));
+ break;
+ case STATIC_IFNAME:
+ vty_out(vty, " %s", si->ifname);
+ break;
+ case STATIC_BLACKHOLE:
+ switch (si->bh_type) {
+ case STATIC_BLACKHOLE_DROP:
+ vty_out(vty, " blackhole");
+ break;
+ case STATIC_BLACKHOLE_NULL:
+ vty_out(vty, " Null0");
+ break;
+ case STATIC_BLACKHOLE_REJECT:
+ vty_out(vty, " reject");
+ break;
+ }
+ break;
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ vty_out(vty, " %s %s",
+ inet_ntop(AF_INET, &si->addr.ipv4, buf,
+ sizeof(buf)),
+ si->ifname);
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ vty_out(vty, " %s %s",
+ inet_ntop(AF_INET6, &si->addr.ipv6, buf,
+ sizeof(buf)),
+ si->ifname);
+ break;
+ }
+
+ if (si->tag)
+ vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag);
+
+ if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+ vty_out(vty, " %d", si->distance);
+
+ /* Label information */
+ if (si->snh_label.num_labels)
+ vty_out(vty, " label %s",
+ mpls_label2str(si->snh_label.num_labels,
+ si->snh_label.label, buf,
+ sizeof(buf), 0));
+
+ if (si->nh_vrf_id != si->vrf_id)
+ vty_out(vty, " nexthop-vrf %s", si->nh_vrfname);
+
+ /*
+ * table ID from VRF overrides configured
+ */
+ if (si->table_id &&
+ svrf->vrf->data.l.table_id == RT_TABLE_MAIN)
+ vty_out(vty, " table %u", si->table_id);
+
+ vty_out(vty, "\n");
+
+ write = 1;
+ }
+ return write;
+}
+
+/* Static unicast routes for multicast RPF lookup. */
+DEFPY (ip_mroute_dist,
+ ip_mroute_dist_cmd,
+ "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
+ NO_STR
+ IP_STR
+ "Configure static unicast route into MRIB for multicast RPF lookup\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Nexthop address\n"
+ "Nexthop interface name\n"
+ "Distance\n")
+{
+ return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
+ NULL, NULL, gate_str, ifname, NULL, NULL,
+ distance_str, NULL, NULL, NULL);
+}
+
+/* Static route configuration. */
+DEFPY(ip_route_blackhole,
+ ip_route_blackhole_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ <reject|blackhole>$flag \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n")
+{
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
+ mask_str, NULL, NULL, NULL, flag, tag_str,
+ distance_str, vrf, label, table_str);
+}
+
+DEFPY(ip_route_blackhole_vrf,
+ ip_route_blackhole_vrf_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ <reject|blackhole>$flag \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n")
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ struct static_vrf *svrf = vrf->info;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /*
+ * Coverity is complaining that prefix could
+ * be dereferenced, but we know that prefix will
+ * valid. Add an assert to make it happy
+ */
+ assert(prefix);
+ return static_route_leak(vty, svrf, svrf, AFI_IP, SAFI_UNICAST,
+ no, prefix, mask_str, NULL, NULL, NULL,
+ flag, tag_str, distance_str, label, table_str);
+}
+
+DEFPY(ip_route_address_interface,
+ ip_route_address_interface_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ A.B.C.D$gate \
+ INTERFACE$ifname \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \
+ null route.\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ struct static_vrf *svrf;
+ struct static_vrf *nh_svrf;
+ const char *flag = NULL;
+
+ if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+ flag = "Null0";
+ ifname = NULL;
+ }
+
+ svrf = static_vty_get_unknown_vrf(vty, vrf);
+ if (!svrf) {
+ vty_out(vty, "%% vrf %s is not defined\n", vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
+ NULL, gate_str, ifname, flag, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ip_route_address_interface_vrf,
+ ip_route_address_interface_vrf_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ A.B.C.D$gate \
+ INTERFACE$ifname \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \
+ null route.\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ const char *flag = NULL;
+ struct static_vrf *svrf = vrf->info;
+ struct static_vrf *nh_svrf;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+ flag = "Null0";
+ ifname = NULL;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
+ NULL, gate_str, ifname, flag, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ip_route,
+ ip_route_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ <A.B.C.D$gate|INTERFACE$ifname> \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ struct static_vrf *svrf;
+ struct static_vrf *nh_svrf;
+ const char *flag = NULL;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+ flag = "Null0";
+ ifname = NULL;
+ }
+
+ svrf = static_vty_get_unknown_vrf(vty, vrf);
+ if (!svrf) {
+ vty_out(vty, "%% vrf %s is not defined\n", vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
+ NULL, gate_str, ifname, flag, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ip_route_vrf,
+ ip_route_vrf_cmd,
+ "[no] ip route\
+ <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+ <A.B.C.D$gate|INTERFACE$ifname> \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ struct static_vrf *svrf = vrf->info;
+ struct static_vrf *nh_svrf;
+ const char *flag = NULL;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+ flag = "Null0";
+ ifname = NULL;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
+ NULL, gate_str, ifname, flag, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ipv6_route_blackhole,
+ ipv6_route_blackhole_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ <Null0|reject|blackhole>$flag \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "Null interface\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n")
+{
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
+ NULL, from_str, NULL, NULL, flag, tag_str,
+ distance_str, vrf, label, table_str);
+}
+
+DEFPY(ipv6_route_blackhole_vrf,
+ ipv6_route_blackhole_vrf_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ <Null0|reject|blackhole>$flag \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "Null interface\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n")
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ struct static_vrf *svrf = vrf->info;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /*
+ * Coverity is complaining that prefix could
+ * be dereferenced, but we know that prefix will
+ * valid. Add an assert to make it happy
+ */
+ assert(prefix);
+ return static_route_leak(
+ vty, svrf, svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
+ from_str, NULL, NULL, flag, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ipv6_route_address_interface,
+ ipv6_route_address_interface_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ X:X::X:X$gate \
+ INTERFACE$ifname \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ struct static_vrf *svrf;
+ struct static_vrf *nh_svrf;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ svrf = static_vty_get_unknown_vrf(vty, vrf);
+ if (!svrf) {
+ vty_out(vty, "%% vrf %s is not defined\n", vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
+ from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ipv6_route_address_interface_vrf,
+ ipv6_route_address_interface_vrf_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ X:X::X:X$gate \
+ INTERFACE$ifname \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ struct static_vrf *svrf = vrf->info;
+ struct static_vrf *nh_svrf;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
+ from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ipv6_route,
+ ipv6_route_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ <X:X::X:X$gate|INTERFACE$ifname> \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |vrf NAME \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ struct static_vrf *svrf;
+ struct static_vrf *nh_svrf;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ svrf = static_vty_get_unknown_vrf(vty, vrf);
+ if (!svrf) {
+ vty_out(vty, "%% vrf %s is not defined\n", vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
+ from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
+ table_str);
+}
+
+DEFPY(ipv6_route_vrf,
+ ipv6_route_vrf_cmd,
+ "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+ <X:X::X:X$gate|INTERFACE$ifname> \
+ [{ \
+ tag (1-4294967295) \
+ |(1-255)$distance \
+ |label WORD \
+ |table (1-4294967295) \
+ |nexthop-vrf NAME \
+ }]",
+ NO_STR
+ IPV6_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 source-dest route\n"
+ "IPv6 source prefix\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ MPLS_LABEL_HELPSTR
+ "Table to configure\n"
+ "The table number to configure\n"
+ VRF_CMD_HELP_STR)
+{
+ VTY_DECLVAR_CONTEXT(vrf, vrf);
+ struct static_vrf *svrf = vrf->info;
+ struct static_vrf *nh_svrf;
+
+ if (table_str && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "%% table param only available when running on netns-based vrfs\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (nexthop_vrf)
+ nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+ else
+ nh_svrf = svrf;
+
+ if (!nh_svrf) {
+ vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return static_route_leak(
+ vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
+ from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
+ table_str);
+}
+
+void static_vty_init(void)
+{
+ install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
+
+ install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
+ install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
+ install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
+ install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
+ install_element(CONFIG_NODE, &ip_route_cmd);
+ install_element(VRF_NODE, &ip_route_vrf_cmd);
+
+ install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
+ install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
+ install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
+ install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
+ install_element(CONFIG_NODE, &ipv6_route_cmd);
+ install_element(VRF_NODE, &ipv6_route_vrf_cmd);
+
+ static_list = list_new();
+ static_list->cmp = (int (*)(void *, void *))static_list_compare;
+ static_list->del = (void (*)(void *))static_list_delete;
+}
diff --git a/staticd/static_vty.h b/staticd/static_vty.h
new file mode 100644
index 0000000000..2f65c08b8b
--- /dev/null
+++ b/staticd/static_vty.h
@@ -0,0 +1,28 @@
+/*
+ * STATICd - vty header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __STATIC_VTY_H__
+#define __STATIC_VTY_H__
+
+void static_config_install_delayed_routes(struct static_vrf *svrf);
+
+int static_config(struct vty *vty, struct static_vrf *svrf,
+ afi_t afi, safi_t safi, const char *cmd);
+
+void static_vty_init(void);
+#endif
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
new file mode 100644
index 0000000000..27e126e2a6
--- /dev/null
+++ b/staticd/static_zebra.c
@@ -0,0 +1,375 @@
+/*
+ * Zebra connect code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "srcdest_table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+#include "nexthop.h"
+#include "nexthop_group.h"
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_zebra.h"
+#include "static_nht.h"
+#include "static_vty.h"
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient;
+
+static struct interface *zebra_interface_if_lookup(struct stream *s)
+{
+ char ifname_tmp[INTERFACE_NAMSIZ];
+
+ /* Read interface name. */
+ stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
+
+ /* And look it up. */
+ return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
+}
+
+/* Inteface addition message from zebra. */
+static int interface_add(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
+
+ if (!ifp)
+ return 0;
+
+ static_ifindex_update(ifp, true);
+ return 0;
+}
+
+static int interface_delete(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s;
+
+ s = zclient->ibuf;
+ /* zebra_interface_state_read () updates interface structure in iflist
+ */
+ ifp = zebra_interface_state_read(s, vrf_id);
+
+ if (ifp == NULL)
+ return 0;
+
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
+ static_ifindex_update(ifp, false);
+ return 0;
+}
+
+static int interface_address_add(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+ return 0;
+}
+
+static int interface_address_delete(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *c;
+
+ c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+ if (!c)
+ return 0;
+
+ connected_free(c);
+ return 0;
+}
+
+static int interface_state_up(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_if_lookup(zclient->ibuf);
+
+ if (if_is_vrf(ifp)) {
+ struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
+
+ static_fixup_vrf_ids(svrf);
+ static_config_install_delayed_routes(svrf);
+ }
+
+ return 0;
+}
+
+static int interface_state_down(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ zebra_interface_state_read(zclient->ibuf, vrf_id);
+
+ return 0;
+}
+
+static int route_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct prefix p;
+ enum zapi_route_notify_owner note;
+ uint32_t table_id;
+ char buf[PREFIX_STRLEN];
+
+ prefix2str(&p, buf, sizeof(buf));
+
+ if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
+ return -1;
+
+ switch (note) {
+ case ZAPI_ROUTE_FAIL_INSTALL:
+ zlog_warn("%s: Route %s failed to install for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ case ZAPI_ROUTE_BETTER_ADMIN_WON:
+ zlog_warn("%s: Route %s over-ridden by better route for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ case ZAPI_ROUTE_INSTALLED:
+ break;
+ case ZAPI_ROUTE_REMOVED:
+ break;
+ case ZAPI_ROUTE_REMOVE_FAIL:
+ zlog_warn("%s: Route %s failure to remove for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ }
+
+ return 0;
+}
+static void zebra_connected(struct zclient *zclient)
+{
+ zclient_send_reg_requests(zclient, VRF_DEFAULT);
+}
+
+
+static int static_zebra_nexthop_update(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct zapi_route nhr;
+ afi_t afi = AFI_IP;
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ zlog_warn("Failure to decode nexthop update message");
+ return 1;
+ }
+
+ if (nhr.prefix.family == AF_INET6)
+ afi = AFI_IP6;
+
+ static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
+ return 1;
+}
+
+static void static_zebra_capabilities(struct zclient_capabilities *cap)
+{
+ mpls_enabled = cap->mpls_enabled;
+}
+
+void static_zebra_nht_register(struct static_route *si, bool reg)
+{
+ uint32_t cmd;
+ struct prefix p;
+
+ cmd = (reg) ?
+ ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
+
+ if (si->nh_registered && reg)
+ return;
+
+ if (!si->nh_registered && !reg)
+ return;
+
+ memset(&p, 0, sizeof(p));
+ switch (si->type) {
+ case STATIC_IFNAME:
+ case STATIC_BLACKHOLE:
+ return;
+ case STATIC_IPV4_GATEWAY:
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = si->addr.ipv4;
+ break;
+ case STATIC_IPV6_GATEWAY:
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_BITLEN;
+ p.u.prefix6 = si->addr.ipv6;
+ break;
+ }
+
+ if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
+ zlog_warn("%s: Failure to send nexthop to zebra",
+ __PRETTY_FUNCTION__);
+
+ si->nh_registered = reg;
+}
+
+extern void static_zebra_route_add(struct route_node *rn,
+ struct static_route *si_changed,
+ vrf_id_t vrf_id, safi_t safi, bool install)
+{
+ struct static_route *si = rn->info;
+ const struct prefix *p, *src_pp;
+ struct zapi_nexthop *api_nh;
+ struct zapi_route api;
+ uint32_t nh_num = 0;
+
+ p = src_pp = NULL;
+ srcdest_rnode_prefixes(rn, &p, &src_pp);
+
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = vrf_id;
+ api.type = ZEBRA_ROUTE_STATIC;
+ api.safi = safi;
+ memcpy(&api.prefix, p, sizeof(api.prefix));
+
+ if (src_pp) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+ memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
+ }
+ SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ if (si_changed->distance) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = si_changed->distance;
+ }
+ if (si_changed->tag) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = si_changed->tag;
+ }
+ api.tableid = si_changed->table_id;
+
+ zlog_debug("Distance sent down: %d %d", si_changed->distance, install);
+ for (/*loaded above*/; si; si = si->next) {
+ api_nh = &api.nexthops[nh_num];
+ if (si->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+
+ if (si->distance != si_changed->distance)
+ continue;
+
+ api_nh->vrf_id = si->nh_vrf_id;
+ switch (si->type) {
+ case STATIC_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->ifindex = si->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
+ break;
+ case STATIC_IPV4_GATEWAY:
+ if (!si->nh_valid)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->ifindex = si->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV6_GATEWAY:
+ if (!si->nh_valid)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV6;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ api_nh->ifindex = si->ifindex;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_BLACKHOLE:
+ api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
+ switch (si->bh_type) {
+ case STATIC_BLACKHOLE_DROP:
+ case STATIC_BLACKHOLE_NULL:
+ api_nh->bh_type = BLACKHOLE_NULL;
+ break;
+ case STATIC_BLACKHOLE_REJECT:
+ api_nh->bh_type = BLACKHOLE_REJECT;
+ }
+ break;
+ }
+
+ if (si->snh_label.num_labels) {
+ int i;
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
+ api_nh->label_num = si->snh_label.num_labels;
+ for (i = 0; i < api_nh->label_num; i++)
+ api_nh->labels[i] = si->snh_label.label[i];
+ }
+ nh_num++;
+ }
+
+ api.nexthop_num = nh_num;
+
+ /*
+ * If we have been given an install but nothing is valid
+ * go ahead and delete the route for double plus fun
+ */
+ if (!nh_num && install)
+ install = false;
+
+ zclient_route_send(install ?
+ ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
+ zclient, &api);
+}
+void static_zebra_init(void)
+{
+ struct zclient_options opt = { .receive_notify = true };
+
+ zclient = zclient_new_notify(master, &opt);
+
+ zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
+ zclient->zebra_capabilities = static_zebra_capabilities;
+ zclient->zebra_connected = zebra_connected;
+ zclient->interface_add = interface_add;
+ zclient->interface_delete = interface_delete;
+ zclient->interface_up = interface_state_up;
+ zclient->interface_down = interface_state_down;
+ zclient->interface_address_add = interface_address_add;
+ zclient->interface_address_delete = interface_address_delete;
+ zclient->route_notify_owner = route_notify_owner;
+ zclient->nexthop_update = static_zebra_nexthop_update;
+}
diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h
new file mode 100644
index 0000000000..a82eb162e1
--- /dev/null
+++ b/staticd/static_zebra.h
@@ -0,0 +1,30 @@
+/*
+ * Zebra connect library for staticd
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ */
+#ifndef __STATIC_ZEBRA_H__
+#define __STATIC_ZEBRA_H__
+
+extern struct thread_master *master;
+
+extern void static_zebra_nht_register(struct static_route *si, bool reg);
+
+extern void static_zebra_route_add(struct route_node *rn,
+ struct static_route *si_changed,
+ vrf_id_t vrf_id, safi_t safi, bool install);
+extern void static_zebra_init(void);
+#endif
diff --git a/staticd/staticd.conf.sample b/staticd/staticd.conf.sample
new file mode 100644
index 0000000000..bb1c2edca8
--- /dev/null
+++ b/staticd/staticd.conf.sample
@@ -0,0 +1,3 @@
+!
+!
+log stdout
diff --git a/staticd/subdir.am b/staticd/subdir.am
new file mode 100644
index 0000000000..3b06a92e22
--- /dev/null
+++ b/staticd/subdir.am
@@ -0,0 +1,33 @@
+#
+# staticd
+#
+
+if STATICD
+noinst_LIBRARIES += staticd/libstatic.a
+sbin_PROGRAMS += staticd/staticd
+dist_examples_DATA += staticd/staticd.conf.sample
+endif
+
+staticd_libstatic_a_SOURCES = \
+ staticd/static_memory.c \
+ staticd/static_nht.c \
+ staticd/static_routes.c \
+ staticd/static_zebra.c \
+ staticd/static_vrf.c \
+ staticd/static_vty.c \
+ # end
+
+noinst_HEADERS += \
+ staticd/static_memory.h \
+ staticd/static_nht.h \
+ staticd/static_zebra.h \
+ staticd/static_routes.h \
+ staticd/static_vty.h \
+ staticd/static_vrf.h \
+ # end
+
+staticd/static_vty_clippy.c: $(CLIPPY_DEPS)
+staticd/static_vty.$(OBJEXT): staticd/static_vty_clippy.c
+
+staticd_staticd_SOURCES = staticd/static_main.c
+staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la @LIBCAP@
diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
index cca702b138..4abbe81499 100644
--- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
Binary files differ
diff --git a/tests/isisd/test_isis_vertex_queue.c b/tests/isisd/test_isis_vertex_queue.c
index fe528203aa..3e31b83351 100644
--- a/tests/isisd/test_isis_vertex_queue.c
+++ b/tests/isisd/test_isis_vertex_queue.c
@@ -17,21 +17,21 @@ static size_t vertex_count;
static void setup_test_vertices(void)
{
union isis_N nid, nip = {
- .prefix.family = AF_UNSPEC
+ .ip.dest.family = AF_UNSPEC
};
vertices = XMALLOC(MTYPE_TMP, sizeof(*vertices) * 16);
- nip.prefix.family = AF_INET;
- nip.prefix.prefixlen = 24;
- inet_pton(AF_INET, "192.168.1.0", &nip.prefix.u.prefix4);
+ nip.ip.dest.family = AF_INET;
+ nip.ip.dest.prefixlen = 24;
+ inet_pton(AF_INET, "192.168.1.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
- nip.prefix.family = AF_INET;
- nip.prefix.prefixlen = 24;
- inet_pton(AF_INET, "192.168.2.0", &nip.prefix.u.prefix4);
+ nip.ip.dest.family = AF_INET;
+ nip.ip.dest.prefixlen = 24;
+ inet_pton(AF_INET, "192.168.2.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
@@ -48,9 +48,9 @@ static void setup_test_vertices(void)
vertices[vertex_count]->d_N = 15;
vertex_count++;
- nip.prefix.family = AF_INET;
- nip.prefix.prefixlen = 24;
- inet_pton(AF_INET, "192.168.3.0", &nip.prefix.u.prefix4);
+ nip.ip.dest.family = AF_INET;
+ nip.ip.dest.prefixlen = 24;
+ inet_pton(AF_INET, "192.168.3.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh
index e1fb529d35..6071f4804d 100755
--- a/tools/checkpatch.sh
+++ b/tools/checkpatch.sh
@@ -72,12 +72,13 @@ else
echo "Done."
for file in ${tmp1}/*_cp; do
if [ -a ${tmp2}/$(basename $file) ]; then
- result=$(diff $file ${tmp2}/$(basename $file) | grep -A3 "ERROR\|WARNING" | grep -A2 -B2 "${tmp1}")
+ result=$(diff $file ${tmp2}/$(basename $file) | awk '/< ERROR|< WARNING/,/^< $|^< #|^<[^ ]/ { print $0; ++n }; END { exit n }')
else
- result=$(cat $file | grep -A3 "ERROR\|WARNING" | grep -A2 -B2 "${tmp1}")
+ result=$(cat $file | awk '/ERROR|WARNING/,/^$/ { print $0; ++n }; END { exit n }')
fi
- if [ "$?" -eq "0" ]; then
- echo "Report for $(basename $file _cp)" 1>&2
+ ni="$?"
+ if [ "$ni" -ne "0" ]; then
+ echo "Report for $(basename $file _cp) | $ni issues" 1>&2
echo "===============================================" 1>&2
echo "$result" 1>&2
if echo $result | grep -q "ERROR"; then
diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf
index e6c0cde968..04a857f47d 100644
--- a/tools/etc/frr/daemons.conf
+++ b/tools/etc/frr/daemons.conf
@@ -18,6 +18,7 @@ eigrpd_options=" --daemon -A 127.0.0.1"
babeld_options=" --daemon -A 127.0.0.1"
sharpd_options=" --daemon -A 127.0.0.1"
pbrd_options=" --daemon -A 127.0.0.1"
+staticd_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
watchfrr_enable=yes
diff --git a/tools/frr b/tools/frr
index 43aa2954ac..91c9091448 100755
--- a/tools/frr
+++ b/tools/frr
@@ -21,7 +21,7 @@ V_PATH=/var/run/frr
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd"
MAX_INSTANCES=5
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
@@ -170,6 +170,22 @@ start()
`eval echo "$""$1""_options"`
fi
fi
+
+ # Start the staticd automatically
+ if [ "$1" = "zebra" ]; then
+ echo -n "starting staticd since zebra is running"
+ if ! check_daemon staticd ; then
+ echo -n " (binary does not exist)"
+ return;
+ fi
+
+ ${SSD} \
+ --start \
+ --pidfile=`pidfile staticd` \
+ --exec "$D_PATH/staticd" \
+ -- \
+ `eval echo "$"staticd"_options"`
+ fi
}
# Stop the daemon given in the parameter, printing its name to the terminal.
@@ -210,6 +226,11 @@ stop()
echo -n " $inst"
rm -f `pidfile $inst`
rm -f `vtyfile $inst`
+
+ if [ "$1" = "zebra" ]; then
+ echo -n "Stopping staticd since zebra is running"
+ stop staticd
+ fi
fi
}
diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am
index 5d6f890e99..6d0b4a8fdb 100644
--- a/vtysh/Makefile.am
+++ b/vtysh/Makefile.am
@@ -146,6 +146,10 @@ vtysh_scan += $(top_srcdir)/pbrd/pbr_vty.c
vtysh_scan += $(top_srcdir)/pbrd/pbr_debug.c
endif
+if STATICD
+vtysh_scan += $(top_srcdir)/staticd/static_vty.c
+endif
+
vtysh_cmd_FILES = $(vtysh_scan) \
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index b56eaa899f..e25a576926 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -133,6 +133,7 @@ struct vtysh_client vtysh_client[] = {
{.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
+ {.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
};
enum vtysh_write_integrated vtysh_write_integrated =
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 6fa61dd883..e6ed5659cf 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -39,6 +39,7 @@ DECLARE_MGROUP(MVTYSH)
#define VTYSH_BABELD 0x1000
#define VTYSH_SHARPD 0x2000
#define VTYSH_PBRD 0x4000
+#define VTYSH_STATICD 0x8000
#define VTYSH_WAS_ACTIVE (-2)
@@ -47,7 +48,7 @@ DECLARE_MGROUP(MVTYSH)
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
-#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD
+#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD
#define VTYSH_NS VTYSH_ZEBRA
diff --git a/zebra/connected.c b/zebra/connected.c
index 8869d34fd6..57bfcc4d16 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -403,10 +403,10 @@ void connected_down(struct interface *ifp, struct connected *ifc)
* head.
*/
rib_delete(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, &nh, 0, 0, false);
+ &p, NULL, &nh, 0, 0, 0, false);
rib_delete(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
- &p, NULL, &nh, 0, 0, false);
+ &p, NULL, &nh, 0, 0, 0, false);
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
char buf[PREFIX_STRLEN];
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 66e98e2e51..56e27e6dc8 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -893,7 +893,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
zlog_warn(
- "Invalid address family: %d received from kernel interface addr change: %d",
+ "Invalid address family: %u received from kernel interface addr change: %u",
ifa->ifa_family, h->nlmsg_type);
return 0;
}
@@ -1133,7 +1133,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE
|| ifi->ifi_family == AF_INET6)) {
zlog_warn(
- "Invalid address family: %d received from kernel link change: %d",
+ "Invalid address family: %u received from kernel link change: %u",
ifi->ifi_family, h->nlmsg_type);
return 0;
}
diff --git a/zebra/interface.c b/zebra/interface.c
index 1067f9bdc1..4211155c27 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -48,7 +48,6 @@
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
#include "zebra/zebra_vxlan.h"
-#include "zebra/zebra_static.h"
#define ZEBRA_PTM_SUPPORT
@@ -577,7 +576,6 @@ void if_add_update(struct interface *ifp)
"interface %s vrf %u index %d becomes active.",
ifp->name, ifp->vrf_id, ifp->ifindex);
- static_ifindex_update(ifp, true);
} else {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s vrf %u index %d is added.",
@@ -736,8 +734,6 @@ void if_delete_update(struct interface *ifp)
zlog_debug("interface %s vrf %u index %d is now inactive.",
ifp->name, ifp->vrf_id, ifp->ifindex);
- static_ifindex_update(ifp, false);
-
/* Delete connected routes from the kernel. */
if_delete_connected(ifp);
@@ -777,8 +773,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
old_vrf_id = ifp->vrf_id;
- static_ifindex_update(ifp, false);
-
/* Uninstall connected routes. */
if_uninstall_connected(ifp);
@@ -803,8 +797,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
if (if_is_operative(ifp))
if_install_connected(ifp);
- static_ifindex_update(ifp, true);
-
/* Due to connected route change, schedule RIB processing for both old
* and new VRF.
*/
@@ -934,12 +926,6 @@ void if_up(struct interface *ifp)
/* Install connected routes to the kernel. */
if_install_connected(ifp);
- /* Install any static routes using this vrf interface */
- if (IS_ZEBRA_IF_VRF(ifp)) {
- static_fixup_vrf_ids(zvrf);
- static_config_install_delayed_routes(zvrf);
- }
-
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%u: IF %s up, scheduling RIB processing",
ifp->vrf_id, ifp->name);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index b85c4748c4..71d709e72d 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1043,7 +1043,7 @@ void rtm_read(struct rt_msghdr *rtm)
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- NULL, 0, 0, true);
+ NULL, 0, 0, 0, true);
if (!nh.type) {
nh.type = NEXTHOP_TYPE_IPV4;
@@ -1058,7 +1058,7 @@ void rtm_read(struct rt_msghdr *rtm)
else
rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &nh, 0, 0, true);
+ &nh, 0, 0, 0, true);
}
if (dest.sa.sa_family == AF_INET6) {
/* One day we might have a debug section here like one in the
@@ -1089,7 +1089,7 @@ void rtm_read(struct rt_msghdr *rtm)
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- NULL, 0, 0, true);
+ NULL, 0, 0, 0, true);
if (!nh.type) {
nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX
@@ -1106,7 +1106,7 @@ void rtm_read(struct rt_msghdr *rtm)
else
rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
- &nh, 0, 0, true);
+ &nh, 0, 0, 0, true);
}
}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 69c0ebb7ec..e3101fbe72 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -597,7 +597,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re)
rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table,
re->flags, &p, NULL, re->ng.nexthop,
- zebrad.rtm_table_default, re->metric, false);
+ zebrad.rtm_table_default, re->metric, re->distance, false);
return 0;
}
diff --git a/zebra/rib.h b/zebra/rib.h
index 6509cdaba7..a37b2bf221 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -291,8 +291,6 @@ extern int is_zebra_valid_kernel_table(uint32_t table_id);
extern int is_zebra_main_routing_table(uint32_t table_id);
extern int zebra_check_addr(const struct prefix *p);
-extern void rib_addnode(struct route_node *rn, struct route_entry *re,
- int process);
extern void rib_delnode(struct route_node *rn, struct route_entry *re);
extern void rib_install_kernel(struct route_node *rn, struct route_entry *re,
struct route_entry *old);
@@ -313,7 +311,8 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
- uint32_t table_id, uint32_t metric, bool fromkernel);
+ uint32_t table_id, uint32_t metric, uint8_t distance,
+ bool fromkernel);
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr,
@@ -450,9 +449,6 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
extern void zebra_vty_init(void);
-extern int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
- safi_t safi, const char *cmd);
-extern void static_config_install_delayed_routes(struct zebra_vrf *zvrf);
extern pid_t pid;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 5facfa5faa..6a258e6853 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -644,12 +644,14 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (gate)
memcpy(&nh.gate, gate, sz);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, &src_p, &nh, table, metric, true);
+ &p, &src_p, &nh, table, metric, distance,
+ true);
} else {
/* XXX: need to compare the entire list of nexthops
* here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, &src_p, NULL, table, metric, true);
+ &p, &src_p, NULL, table, metric, distance,
+ true);
}
}
@@ -763,11 +765,9 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
return 0;
}
- if (!(rtm->rtm_family == AF_INET || rtm->rtm_family == AF_INET6
- || rtm->rtm_family == AF_ETHERNET
- || rtm->rtm_family == AF_MPLS)) {
+ if (!(rtm->rtm_family == AF_INET || rtm->rtm_family == AF_INET6)) {
zlog_warn(
- "Invalid address family: %d received from kernel route change: %d",
+ "Invalid address family: %u received from kernel route change: %u",
rtm->rtm_family, h->nlmsg_type);
return 0;
}
@@ -780,10 +780,6 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
nl_rttype_to_str(rtm->rtm_type),
nl_rtproto_to_str(rtm->rtm_protocol), ns_id);
- /* We don't care about change notifications for the MPLS table. */
- /* TODO: Revisit this. */
- if (rtm->rtm_family == AF_MPLS)
- return 0;
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0) {
@@ -2422,7 +2418,7 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
return netlink_ipneigh_change(h, len, ns_id);
else {
zlog_warn(
- "Invalid address family: %d received from kernel neighbor change: %d",
+ "Invalid address family: %u received from kernel neighbor change: %u",
ndm->ndm_family, h->nlmsg_type);
return 0;
}
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index d683e92bcc..87d3769a5a 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -206,7 +206,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
frh = NLMSG_DATA(h);
if (frh->family != AF_INET && frh->family != AF_INET6) {
zlog_warn(
- "Invalid address family: %d received from kernel rule change: %d",
+ "Invalid address family: %u received from kernel rule change: %u",
frh->family, h->nlmsg_type);
return 0;
}
diff --git a/zebra/subdir.am b/zebra/subdir.am
index d3abcef6d5..73354ec38e 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -63,7 +63,6 @@ zebra_zebra_SOURCES = \
zebra/zebra_rib.c \
zebra/zebra_rnh.c \
zebra/zebra_routemap.c \
- zebra/zebra_static.c \
zebra/zebra_vrf.c \
zebra/zebra_vty.c \
zebra/zebra_vxlan.c \
@@ -108,7 +107,6 @@ noinst_HEADERS += \
zebra/zebra_pw.h \
zebra/zebra_rnh.h \
zebra/zebra_routemap.h \
- zebra/zebra_static.h \
zebra/zebra_vrf.h \
zebra/zebra_vxlan.h \
zebra/zebra_vxlan_private.h \
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index c16fa70857..ad574d7e8b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1565,7 +1565,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
api.flags, &api.prefix, src_p, NULL, table_id, api.metric,
- false);
+ api.distance, false);
/* Stats */
switch (api.prefix.family) {
@@ -1767,7 +1767,7 @@ static void zread_ipv4_delete(ZAPI_HANDLER_ARGS)
table_id = zvrf->table_id;
rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, NULL, NULL, table_id, 0, false);
+ api.flags, &p, NULL, NULL, table_id, 0, 0, false);
client->v4_route_del_cnt++;
stream_failure:
@@ -2191,7 +2191,7 @@ static void zread_ipv6_delete(ZAPI_HANDLER_ARGS)
src_pp = NULL;
rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, src_pp, NULL, client->rtm_table, 0, false);
+ api.flags, &p, src_pp, NULL, client->rtm_table, 0, 0, false);
client->v6_route_del_cnt++;
@@ -2245,7 +2245,7 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
client->notify_owner = true;
/* accept only dynamic routing protocols */
- if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_STATIC)) {
+ if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_CONNECT)) {
zlog_notice(
"client %d says hello and bids fair to announce only %s routes vrf=%u",
client->sock, zebra_route_string(proto),
diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c
index 01bc66e5cd..2e02b12311 100644
--- a/zebra/zebra_mpls_vty.c
+++ b/zebra/zebra_mpls_vty.c
@@ -37,7 +37,6 @@
#include "zebra/zebra_rnh.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
-#include "zebra/zebra_static.h"
static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd,
const char *inlabel_str, const char *gate_str,
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 71d48632c1..18bd6b6cbe 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2086,7 +2086,8 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
rib_queue_add(rn);
}
-void rib_addnode(struct route_node *rn, struct route_entry *re, int process)
+static void rib_addnode(struct route_node *rn,
+ struct route_entry *re, int process)
{
/* RE node has been un-removed before route-node is processed.
* route_node must hence already be on the queue for processing..
@@ -2135,10 +2136,6 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
if (dest->selected_fib == re)
dest->selected_fib = NULL;
- /* free RE and nexthops */
- if (re->type == ZEBRA_ROUTE_STATIC)
- zebra_deregister_rnh_static_nexthops(re->ng.nexthop->vrf_id,
- re->ng.nexthop, rn);
nexthops_free(re->ng.nexthop);
XFREE(MTYPE_RE, re);
}
@@ -2324,7 +2321,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
{
struct route_table *table;
struct route_node *rn;
- struct route_entry *same;
+ struct route_entry *same = NULL;
struct nexthop *nexthop;
int ret = 0;
@@ -2358,8 +2355,13 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
/* Lookup route node.*/
rn = srcdest_rnode_get(table, p, src_p);
- /* If same type of route are installed, treat it as a implicit
- withdraw. */
+ zlog_debug("Distance: %d", re->distance);
+ /*
+ * If same type of route are installed, treat it as a implicit
+ * withdraw.
+ * If the user has specified the No route replace semantics
+ * for the install don't do a route replace.
+ */
RNODE_FOREACH_RE (rn, same) {
if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED))
continue;
@@ -2371,14 +2373,21 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
if (same->type == ZEBRA_ROUTE_KERNEL
&& same->metric != re->metric)
continue;
+
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) &&
+ same->distance != re->distance)
+ continue;
+
/*
- * We should allow duplicate connected routes because of
- * IPv6 link-local routes and unnumbered interfaces on Linux.
+ * We should allow duplicate connected routes
+ * because of IPv6 link-local routes and unnumbered
+ * interfaces on Linux.
*/
if (same->type != ZEBRA_ROUTE_CONNECT)
break;
}
+ zlog_debug("same: %p distance: %d", same, same ? same->distance : -1);
/* If this route is kernel route, set FIB flag to the route. */
if (RIB_SYSTEM_ROUTE(re))
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
@@ -2410,7 +2419,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
- uint32_t table_id, uint32_t metric, bool fromkernel)
+ uint32_t table_id, uint32_t metric, uint8_t distance,
+ bool fromkernel)
{
struct route_table *table;
struct route_node *rn;
@@ -2464,6 +2474,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
continue;
if (re->instance != instance)
continue;
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) &&
+ distance != re->distance)
+ continue;
+
if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric)
continue;
if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop)
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index d482e0ab3d..453f08a183 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -131,7 +131,6 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
rnh->client_list = list_new();
rnh->vrf_id = vrfid;
- rnh->zebra_static_route_list = list_new();
rnh->zebra_pseudowire_list = list_new();
route_lock_node(rn);
rn->info = rnh;
@@ -167,7 +166,6 @@ void zebra_free_rnh(struct rnh *rnh)
{
rnh->flags |= ZEBRA_NHT_DELETED;
list_delete_and_null(&rnh->client_list);
- list_delete_and_null(&rnh->zebra_static_route_list);
list_delete_and_null(&rnh->zebra_pseudowire_list);
free_state(rnh->vrf_id, rnh->state, rnh->node);
XFREE(MTYPE_RNH, rnh);
@@ -218,82 +216,10 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
}
listnode_delete(rnh->client_list, client);
if (list_isempty(rnh->client_list)
- && list_isempty(rnh->zebra_static_route_list)
&& list_isempty(rnh->zebra_pseudowire_list))
zebra_delete_rnh(rnh, type);
}
-void zebra_register_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
- struct route_node *static_rn)
-{
- struct rnh *rnh;
-
- rnh = zebra_add_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
- if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) {
- listnode_add(rnh->zebra_static_route_list, static_rn);
- }
-}
-
-void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
- struct route_node *static_rn)
-{
- struct rnh *rnh;
-
- rnh = zebra_lookup_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE);
- if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
- return;
-
- listnode_delete(rnh->zebra_static_route_list, static_rn);
-
- if (list_isempty(rnh->client_list)
- && list_isempty(rnh->zebra_static_route_list)
- && list_isempty(rnh->zebra_pseudowire_list))
- zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
-}
-
-void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
- struct nexthop *nexthop,
- struct route_node *rn)
-{
- struct nexthop *nh;
- struct prefix nh_p;
-
- for (nh = nexthop; nh; nh = nh->next) {
- switch (nh->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- nh_p.family = AF_INET;
- nh_p.prefixlen = IPV4_MAX_BITLEN;
- nh_p.u.prefix4 = nh->gate.ipv4;
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- nh_p.family = AF_INET6;
- nh_p.prefixlen = IPV6_MAX_BITLEN;
- nh_p.u.prefix6 = nh->gate.ipv6;
- break;
- /*
- * Not sure what really to do here, we are not
- * supposed to have either of these for NHT
- * and the code has no way to know what prefix
- * to use. So I'm going to just continue
- * for the moment, which is preferable to
- * what is currently happening which is a
- * CRASH and BURN.
- * Some simple testing shows that we
- * are not leaving slag around for these
- * skipped static routes. Since
- * they don't appear to be installed
- */
- case NEXTHOP_TYPE_IFINDEX:
- case NEXTHOP_TYPE_BLACKHOLE:
- continue;
- break;
- }
- zebra_deregister_rnh_static_nh(vrf_id, &nh_p, rn);
- }
-}
-
/* XXX move this utility function elsewhere? */
static void addr2hostprefix(int af, const union g_addr *addr,
struct prefix *prefix)
@@ -342,7 +268,6 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
pw->rnh = NULL;
if (list_isempty(rnh->client_list)
- && list_isempty(rnh->zebra_static_route_list)
&& list_isempty(rnh->zebra_pseudowire_list))
zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
}
@@ -575,115 +500,6 @@ static void zebra_rnh_process_pbr_tables(int family,
}
}
-static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
- struct route_node *nrn,
- struct rnh *rnh,
- struct route_node *prn,
- struct route_entry *re)
-{
- struct listnode *node;
- int num_resolving_nh = 0;
- struct route_node *static_rn;
- struct route_entry *sre;
- struct nexthop *nexthop;
- char bufn[INET6_ADDRSTRLEN];
- char bufp[INET6_ADDRSTRLEN];
- char bufs[INET6_ADDRSTRLEN];
-
- if (IS_ZEBRA_DEBUG_NHT) {
- prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
- if (prn)
- prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
- }
-
- if (prn && re) {
- /* Apply route-map for "static" to route resolving this
- * nexthop to see if it is filtered or not.
- */
- num_resolving_nh = zebra_rnh_apply_nht_rmap(family, prn, re,
- ZEBRA_ROUTE_STATIC);
- if (num_resolving_nh)
- rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
- else
- rnh->filtered[ZEBRA_ROUTE_STATIC] = 1;
- } else
- rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
-
- /* Evaluate each static route associated with this nexthop. */
- for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
- static_rn)) {
- RNODE_FOREACH_RE (static_rn, sre) {
- if (sre->type != ZEBRA_ROUTE_STATIC)
- continue;
-
- /* Set the filter flag for the correct nexthop - static
- * route may
- * be having multiple. We care here only about
- * registered nexthops.
- */
- for (nexthop = sre->ng.nexthop; nexthop;
- nexthop = nexthop->next) {
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->gate.ipv4.s_addr
- == nrn->p.u.prefix4.s_addr) {
- if (num_resolving_nh)
- UNSET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_FILTERED);
- else
- SET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_FILTERED);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
-
- if (memcmp(&nexthop->gate.ipv6,
- &nrn->p.u.prefix6, 16)
- == 0) {
- if (num_resolving_nh)
- UNSET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_FILTERED);
- else
- SET_FLAG(
- nexthop->flags,
- NEXTHOP_FLAG_FILTERED);
- }
- break;
- default:
- break;
- }
- }
-
- if (IS_ZEBRA_DEBUG_NHT) {
- prefix2str(&static_rn->p, bufs,
- INET6_ADDRSTRLEN);
- if (prn && re)
- zlog_debug(
- "%u:%s: NH change %s, scheduling static route %s",
- vrfid, bufn,
- num_resolving_nh
- ? ""
- : "(filtered by route-map)",
- bufs);
- else
- zlog_debug(
- "%u:%s: NH unreachable, scheduling static route %s",
- vrfid, bufn, bufs);
- }
-
- SET_FLAG(sre->status, ROUTE_ENTRY_CHANGED);
- SET_FLAG(sre->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
- }
-
- rib_queue_add(static_rn);
- }
-}
-
/*
* Determine appropriate route (route entry) resolving a tracked
* nexthop.
@@ -809,10 +625,6 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
zebra_rnh_notify_protocol_clients(vrfid, family, nrn, rnh, prn,
rnh->state);
- /* Process static routes attached to this nexthop */
- zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
- rnh->state);
-
zebra_rnh_process_pbr_tables(family, nrn, rnh, prn,
rnh->state);
@@ -962,7 +774,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
return;
/* free RE and nexthops */
- zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn);
nexthops_free(re->ng.nexthop);
XFREE(MTYPE_RE, re);
}
@@ -1173,9 +984,6 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
client->sock,
rnh->filtered[client->proto] ? "(filtered)" : "");
- if (!list_isempty(rnh->zebra_static_route_list))
- vty_out(vty, " zebra%s",
- rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
if (!list_isempty(rnh->zebra_pseudowire_list))
vty_out(vty, " zebra[pseudowires]");
vty_out(vty, "\n");
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index ea7d5545e8..9e09a1bc6f 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -39,14 +39,16 @@ struct rnh {
struct route_entry *state;
struct prefix resolved_route;
struct list *client_list;
- struct list
- *zebra_static_route_list; /* static routes dependent on this NH
- */
- struct list
- *zebra_pseudowire_list; /* pseudowires dependent on this NH */
+
+ /* pseudowires dependent on this nh */
+ struct list *zebra_pseudowire_list;
+
struct route_node *node;
- int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client
- */
+
+ /*
+ * if this has been filtered for the client
+ */
+ int filtered[ZEBRA_ROUTE_MAX];
};
typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
@@ -73,13 +75,6 @@ extern void zebra_free_rnh(struct rnh *rnh);
extern void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type);
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_type_t type, vrf_id_t vrfid);
-extern void zebra_register_rnh_static_nh(vrf_id_t, struct prefix *,
- struct route_node *);
-extern void zebra_deregister_rnh_static_nexthops(vrf_id_t,
- struct nexthop *nexthop,
- struct route_node *rn);
-extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *,
- struct route_node *);
extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c
deleted file mode 100644
index 76346f6b66..0000000000
--- a/zebra/zebra_static.c
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Static Routing Information code
- * Copyright (C) 2016 Cumulus Networks
- * Donald Sharp
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <zebra.h>
-
-#include <lib/nexthop.h>
-#include <lib/memory.h>
-#include <lib/srcdest_table.h>
-#include <lib/if.h>
-
-#include "vty.h"
-#include "zebra/debug.h"
-#include "zebra/rib.h"
-#include "zebra/zserv.h"
-#include "zebra/zebra_vrf.h"
-#include "zebra/zebra_static.h"
-#include "zebra/zebra_rnh.h"
-#include "zebra/redistribute.h"
-#include "zebra/zebra_memory.h"
-
-/* Install static route into rib. */
-void static_install_route(afi_t afi, safi_t safi, const struct prefix *p,
- const struct prefix_ipv6 *src_p,
- struct static_route *si)
-{
- struct route_entry *re;
- struct route_node *rn;
- struct route_table *table;
- struct prefix nh_p;
- struct nexthop *nexthop = NULL;
- enum blackhole_type bh_type = 0;
- struct vrf *nh_vrf;
-
- /* Lookup table. */
- table = zebra_vrf_table_with_table_id(afi, safi,
- si->vrf_id,
- si->table_id);
- if (!table)
- return;
-
- /*
- * If a specific vrf is coming up and the nexthop vrf we are
- * looking at using hasn't been brought up yet, just don't
- * install the static route yet.
- * When the nexthop vrf comes up we will get another call
- * back to do the right thing. I'm putting this check
- * here because we are calling static_install_route a bunch
- * from a bunch of different callpaths.
- */
- nh_vrf = vrf_lookup_by_id(si->nh_vrf_id);
- if (!nh_vrf)
- return;
-
- memset(&nh_p, 0, sizeof(nh_p));
- if (si->type == STATIC_BLACKHOLE) {
- switch (si->bh_type) {
- case STATIC_BLACKHOLE_DROP:
- case STATIC_BLACKHOLE_NULL:
- bh_type = BLACKHOLE_NULL;
- break;
- case STATIC_BLACKHOLE_REJECT:
- bh_type = BLACKHOLE_REJECT;
- break;
- }
- }
-
- /* Lookup existing route */
- rn = srcdest_rnode_get(table, p, src_p);
- RNODE_FOREACH_RE (rn, re) {
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
- continue;
-
- if (re->type == ZEBRA_ROUTE_STATIC
- && re->distance == si->distance)
- break;
- }
-
- if (re) {
- /* if tag value changed , update old value in RIB */
- if (re->tag != si->tag)
- re->tag = si->tag;
-
- /* Same distance static route is there. Update it with new
- nexthop. */
- route_unlock_node(rn);
- switch (si->type) {
- case STATIC_IPV4_GATEWAY:
- nexthop = route_entry_nexthop_ipv4_add(
- re, &si->addr.ipv4, NULL, si->nh_vrf_id);
- nh_p.family = AF_INET;
- nh_p.prefixlen = IPV4_MAX_BITLEN;
- nh_p.u.prefix4 = si->addr.ipv4;
- zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
- break;
- case STATIC_IPV4_GATEWAY_IFNAME:
- nexthop = route_entry_nexthop_ipv4_ifindex_add(
- re, &si->addr.ipv4, NULL, si->ifindex,
- si->nh_vrf_id);
- break;
- case STATIC_IFNAME:
- nexthop = route_entry_nexthop_ifindex_add(
- re, si->ifindex, si->nh_vrf_id);
- break;
- case STATIC_BLACKHOLE:
- nexthop =
- route_entry_nexthop_blackhole_add(re, bh_type);
- break;
- case STATIC_IPV6_GATEWAY:
- nexthop = route_entry_nexthop_ipv6_add(
- re, &si->addr.ipv6, si->nh_vrf_id);
- nh_p.family = AF_INET6;
- nh_p.prefixlen = IPV6_MAX_BITLEN;
- nh_p.u.prefix6 = si->addr.ipv6;
- zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
- break;
- case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop = route_entry_nexthop_ipv6_ifindex_add(
- re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id);
- break;
- }
- /* Update label(s), if present. */
- if (si->snh_label.num_labels)
- nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
- si->snh_label.num_labels,
- &si->snh_label.label[0]);
-
- if (IS_ZEBRA_DEBUG_RIB) {
- char buf[INET6_ADDRSTRLEN];
- if (IS_ZEBRA_DEBUG_RIB) {
- inet_ntop(p->family, &p->u.prefix, buf,
- INET6_ADDRSTRLEN);
- zlog_debug(
- "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
- si->vrf_id, buf, p->prefixlen, rn, re,
- re->type);
- }
- }
-
- re->uptime = time(NULL);
- /* Schedule route for processing or invoke NHT, as appropriate.
- */
- if (si->type == STATIC_IPV4_GATEWAY
- || si->type == STATIC_IPV6_GATEWAY)
- zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1,
- RNH_NEXTHOP_TYPE, &nh_p);
- else
- rib_queue_add(rn);
- } else {
- /* This is new static route. */
- re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
-
- re->type = ZEBRA_ROUTE_STATIC;
- re->instance = 0;
- re->distance = si->distance;
- re->metric = 0;
- re->mtu = 0;
- re->vrf_id = si->vrf_id;
- if (!vrf_is_backend_netns()) {
- re->table =
- (si->vrf_id != VRF_DEFAULT)
- ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id
- : zebrad.rtm_table_default;
- } else {
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(si->vrf_id);
-
- if (zvrf->table_id != RT_TABLE_MAIN ||
- zvrf->table_id != zebrad.rtm_table_default)
- re->table = zvrf->table_id;
- else
- re->table = zebrad.rtm_table_default;
- }
- re->nexthop_num = 0;
- re->tag = si->tag;
-
- switch (si->type) {
- case STATIC_IPV4_GATEWAY:
- nexthop = route_entry_nexthop_ipv4_add(
- re, &si->addr.ipv4, NULL, si->nh_vrf_id);
- nh_p.family = AF_INET;
- nh_p.prefixlen = IPV4_MAX_BITLEN;
- nh_p.u.prefix4 = si->addr.ipv4;
- zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
- break;
- case STATIC_IPV4_GATEWAY_IFNAME:
- nexthop = route_entry_nexthop_ipv4_ifindex_add(
- re, &si->addr.ipv4, NULL, si->ifindex,
- si->nh_vrf_id);
- break;
- case STATIC_IFNAME:
- nexthop = route_entry_nexthop_ifindex_add(
- re, si->ifindex, si->nh_vrf_id);
- break;
- case STATIC_BLACKHOLE:
- nexthop =
- route_entry_nexthop_blackhole_add(re, bh_type);
- break;
- case STATIC_IPV6_GATEWAY:
- nexthop = route_entry_nexthop_ipv6_add(
- re, &si->addr.ipv6, si->nh_vrf_id);
- nh_p.family = AF_INET6;
- nh_p.prefixlen = IPV6_MAX_BITLEN;
- nh_p.u.prefix6 = si->addr.ipv6;
- zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
- break;
- case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop = route_entry_nexthop_ipv6_ifindex_add(
- re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id);
- break;
- }
- /* Update label(s), if present. */
- if (si->snh_label.num_labels)
- nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
- si->snh_label.num_labels,
- &si->snh_label.label[0]);
-
- if (IS_ZEBRA_DEBUG_RIB) {
- char buf[INET6_ADDRSTRLEN];
- if (IS_ZEBRA_DEBUG_RIB) {
- inet_ntop(p->family, &p->u.prefix, buf,
- INET6_ADDRSTRLEN);
- zlog_debug(
- "%u:%s/%d: Inserting route rn %p, re %p (type %d)",
- si->vrf_id, buf, p->prefixlen, rn, re,
- re->type);
- }
- }
- re->uptime = time(NULL);
- /* Link this re to the tree. Schedule for processing or invoke
- * NHT,
- * as appropriate.
- */
- if (si->type == STATIC_IPV4_GATEWAY
- || si->type == STATIC_IPV6_GATEWAY) {
- rib_addnode(rn, re, 0);
- zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1,
- RNH_NEXTHOP_TYPE, &nh_p);
- } else
- rib_addnode(rn, re, 1);
- }
-}
-
-/* this works correctly with IFNAME<>IFINDEX because a static route on a
- * non-active interface will have IFINDEX_INTERNAL and thus compare false
- */
-static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
-{
- if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
- && si->type == STATIC_BLACKHOLE)
- return 1;
-
- if (nexthop->type == NEXTHOP_TYPE_IPV4
- && si->type == STATIC_IPV4_GATEWAY
- && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4))
- return 1;
- else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
- && si->type == STATIC_IPV4_GATEWAY_IFNAME
- && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)
- && nexthop->ifindex == si->ifindex)
- return 1;
- else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
- && si->type == STATIC_IFNAME
- && nexthop->ifindex == si->ifindex)
- return 1;
- else if (nexthop->type == NEXTHOP_TYPE_IPV6
- && si->type == STATIC_IPV6_GATEWAY
- && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6))
- return 1;
- else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
- && si->type == STATIC_IPV6_GATEWAY_IFNAME
- && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)
- && nexthop->ifindex == si->ifindex)
- return 1;
-
- return 0;
-}
-
-/* Uninstall static route from RIB. */
-void static_uninstall_route(afi_t afi, safi_t safi, const struct prefix *p,
- const struct prefix_ipv6 *src_p,
- struct static_route *si)
-{
- struct route_node *rn;
- struct route_entry *re;
- struct nexthop *nexthop;
- struct route_table *table;
- struct prefix nh_p;
-
- /* Lookup table. */
- table = zebra_vrf_table_with_table_id(afi, safi,
- si->vrf_id,
- si->table_id);
- if (!table)
- return;
-
- /* Lookup existing route with type and distance. */
- rn = srcdest_rnode_lookup(table, p, src_p);
- if (!rn)
- return;
-
- RNODE_FOREACH_RE (rn, re) {
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
- continue;
-
- if (re->type == ZEBRA_ROUTE_STATIC
- && re->distance == si->distance && re->tag == si->tag)
- break;
- }
-
- if (!re) {
- route_unlock_node(rn);
- return;
- }
-
- /* Lookup nexthop. */
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
- if (static_nexthop_same(nexthop, si))
- break;
-
- /* Can't find nexthop. */
- if (!nexthop) {
- route_unlock_node(rn);
- return;
- }
-
- /* Check nexthop. */
- if (re->nexthop_num == 1)
- rib_delnode(rn, re);
- else {
- /* Mark this nexthop as inactive and reinstall the route. Then,
- * delete
- * the nexthop. There is no need to re-evaluate the route for
- * this
- * scenario.
- */
- if (IS_ZEBRA_DEBUG_RIB) {
- char buf[INET6_ADDRSTRLEN];
- if (IS_ZEBRA_DEBUG_RIB) {
- inet_ntop(p->family, &p->u.prefix, buf,
- INET6_ADDRSTRLEN);
- zlog_debug(
- "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
- si->vrf_id, buf, p->prefixlen, rn, re,
- re->type);
- }
- }
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
- rib_dest_t *dest = rib_dest_from_rnode(rn);
-
- /* If there are other active nexthops, do an update. */
- if (re->nexthop_active_num > 1) {
- /* Update route in kernel if it's in fib */
- if (dest->selected_fib)
- rib_install_kernel(rn, re, re);
- /* Update redistribution if it's selected */
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
- redistribute_update(
- p, (struct prefix *)src_p, re,
- NULL);
- } else {
- /* Remove from redistribute if selected route
- * becomes inactive */
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
- redistribute_delete(
- p, (struct prefix *)src_p, re);
- /* Remove from kernel if fib route becomes
- * inactive */
- if (dest->selected_fib)
- rib_uninstall_kernel(rn, re);
- }
- }
-
- if (afi == AFI_IP) {
- /* Delete the nexthop and dereg from NHT */
- nh_p.family = AF_INET;
- nh_p.prefixlen = IPV4_MAX_BITLEN;
- nh_p.u.prefix4 = nexthop->gate.ipv4;
- } else {
- nh_p.family = AF_INET6;
- nh_p.prefixlen = IPV6_MAX_BITLEN;
- nh_p.u.prefix6 = nexthop->gate.ipv6;
- }
- route_entry_nexthop_delete(re, nexthop);
- zebra_deregister_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
- nexthop_free(nexthop);
- }
- /* Unlock node. */
- route_unlock_node(rn);
-}
-
-int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- const char *ifname, enum static_blackhole_type bh_type,
- route_tag_t tag, uint8_t distance, struct zebra_vrf *zvrf,
- struct zebra_vrf *nh_zvrf,
- struct static_nh_label *snh_label,
- uint32_t table_id)
-{
- struct route_node *rn;
- struct static_route *si;
- struct static_route *pp;
- struct static_route *cp;
- struct static_route *update = NULL;
- struct route_table *stable = zvrf->stable[afi][safi];
-
- if (!stable)
- return -1;
-
- if (!gate && (type == STATIC_IPV4_GATEWAY
- || type == STATIC_IPV4_GATEWAY_IFNAME
- || type == STATIC_IPV6_GATEWAY
- || type == STATIC_IPV6_GATEWAY_IFNAME))
- return -1;
-
- if (!ifname
- && (type == STATIC_IFNAME || type == STATIC_IPV4_GATEWAY_IFNAME
- || type == STATIC_IPV6_GATEWAY_IFNAME))
- return -1;
-
- /* Lookup static route prefix. */
- rn = srcdest_rnode_get(stable, p, src_p);
-
- /* Do nothing if there is a same static route. */
- for (si = rn->info; si; si = si->next) {
- if (type == si->type
- && (!gate
- || ((afi == AFI_IP
- && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
- || (afi == AFI_IP6
- && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
- && (!strcmp(ifname ? ifname : "", si->ifname))) {
- if ((distance == si->distance) && (tag == si->tag)
- && !memcmp(&si->snh_label, snh_label,
- sizeof(struct static_nh_label))
- && si->bh_type == bh_type) {
- route_unlock_node(rn);
- return 0;
- } else
- update = si;
- }
- }
-
- /* Distance or tag or label changed, delete existing first. */
- if (update)
- static_delete_route(afi, safi, type, p, src_p, gate, ifname,
- update->tag, update->distance, zvrf,
- &update->snh_label, table_id);
-
- /* Make new static route structure. */
- si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route));
-
- si->type = type;
- si->distance = distance;
- si->bh_type = bh_type;
- si->tag = tag;
- si->vrf_id = zvrf_id(zvrf);
- si->nh_vrf_id = zvrf_id(nh_zvrf);
- strcpy(si->nh_vrfname, nh_zvrf->vrf->name);
- si->table_id = table_id;
-
- if (ifname)
- strlcpy(si->ifname, ifname, sizeof(si->ifname));
- si->ifindex = IFINDEX_INTERNAL;
-
- switch (type) {
- case STATIC_IPV4_GATEWAY:
- case STATIC_IPV4_GATEWAY_IFNAME:
- si->addr.ipv4 = gate->ipv4;
- break;
- case STATIC_IPV6_GATEWAY:
- case STATIC_IPV6_GATEWAY_IFNAME:
- si->addr.ipv6 = gate->ipv6;
- break;
- case STATIC_IFNAME:
- break;
- }
-
- /* Save labels, if any. */
- memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label));
-
- /* Add new static route information to the tree with sort by
- distance value and gateway address. */
- for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) {
- if (si->distance < cp->distance)
- break;
- if (si->distance > cp->distance)
- continue;
- if (si->type == STATIC_IPV4_GATEWAY
- && cp->type == STATIC_IPV4_GATEWAY) {
- if (ntohl(si->addr.ipv4.s_addr)
- < ntohl(cp->addr.ipv4.s_addr))
- break;
- if (ntohl(si->addr.ipv4.s_addr)
- > ntohl(cp->addr.ipv4.s_addr))
- continue;
- }
- }
-
- /* Make linked list. */
- if (pp)
- pp->next = si;
- else
- rn->info = si;
- if (cp)
- cp->prev = si;
- si->prev = pp;
- si->next = cp;
-
- /* check whether interface exists in system & install if it does */
- if (!ifname)
- static_install_route(afi, safi, p, src_p, si);
- else {
- struct interface *ifp;
-
- ifp = if_lookup_by_name(ifname, zvrf_id(nh_zvrf));
- if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
- si->ifindex = ifp->ifindex;
- static_install_route(afi, safi, p, src_p, si);
- } else
- zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
- ifname);
- }
-
- return 1;
-}
-
-int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
- struct prefix_ipv6 *src_p, union g_addr *gate,
- const char *ifname, route_tag_t tag, uint8_t distance,
- struct zebra_vrf *zvrf,
- struct static_nh_label *snh_label,
- uint32_t table_id)
-{
- struct route_node *rn;
- struct static_route *si;
- struct route_table *stable;
-
- /* Lookup table. */
- stable = zebra_vrf_static_table(afi, safi, zvrf);
- if (!stable)
- return -1;
-
- /* Lookup static route prefix. */
- rn = srcdest_rnode_lookup(stable, p, src_p);
- if (!rn)
- return 0;
-
- /* Find same static route is the tree */
- for (si = rn->info; si; si = si->next)
- if (type == si->type
- && (!gate
- || ((afi == AFI_IP
- && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
- || (afi == AFI_IP6
- && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
- && (!strcmp(ifname ? ifname : "", si->ifname))
- && (!tag || (tag == si->tag))
- && (table_id == si->table_id)
- && (!snh_label->num_labels
- || !memcmp(&si->snh_label, snh_label,
- sizeof(struct static_nh_label))))
- break;
-
- /* Can't find static route. */
- if (!si) {
- route_unlock_node(rn);
- return 0;
- }
-
- /* Uninstall from rib. */
- if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL)
- static_uninstall_route(afi, safi, p, src_p, si);
-
- /* Unlink static route from linked list. */
- if (si->prev)
- si->prev->next = si->next;
- else
- rn->info = si->next;
- if (si->next)
- si->next->prev = si->prev;
- route_unlock_node(rn);
-
- /* Free static route configuration. */
- XFREE(MTYPE_STATIC_ROUTE, si);
-
- route_unlock_node(rn);
-
- return 1;
-}
-
-static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
- safi_t safi)
-{
- struct route_table *stable;
- struct route_node *rn;
- struct static_route *si;
- const struct prefix *p, *src_pp;
- struct prefix_ipv6 *src_p;
- struct vrf *vrf;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct zebra_vrf *zvrf;
-
- zvrf = vrf->info;
-
- stable = zebra_vrf_static_table(afi, safi, zvrf);
- if (!stable)
- continue;
-
- for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
- srcdest_rnode_prefixes(rn, &p, &src_pp);
- src_p = (struct prefix_ipv6 *)src_pp;
-
- for (si = rn->info; si; si = si->next) {
- if (!si->ifname[0])
- continue;
- if (up) {
- if (strcmp(si->ifname, ifp->name))
- continue;
- si->ifindex = ifp->ifindex;
- static_install_route(afi, safi, p, src_p, si);
- } else {
- if (si->ifindex != ifp->ifindex)
- continue;
- static_uninstall_route(afi, safi, p, src_p, si);
- si->ifindex = IFINDEX_INTERNAL;
- }
- }
- }
- }
-}
-
-/*
- * This function looks at a zvrf's stable and notices if any of the
- * nexthops we are using are part of the vrf coming up.
- * If we are using them then cleanup the nexthop vrf id
- * to be the new value and then re-installs them
- *
- *
- * stable -> The table we are looking at.
- * zvrf -> The newly changed vrf.
- * afi -> The afi to look at
- * safi -> the safi to look at
- */
-static void static_fixup_vrf(struct zebra_vrf *zvrf,
- struct route_table *stable, afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_route *si;
- struct interface *ifp;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- for (si = rn->info; si; si = si->next) {
- if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0)
- continue;
-
- si->nh_vrf_id = zvrf->vrf->vrf_id;
- if (si->ifindex) {
- ifp = if_lookup_by_name(si->ifname,
- si->nh_vrf_id);
- if (ifp)
- si->ifindex = ifp->ifindex;
- else
- continue;
- }
- static_install_route(afi, safi, &rn->p, NULL, si);
- }
- }
-}
-
-/*
- * This function enables static routes in a zvrf as it
- * is coming up. It sets the new vrf_id as appropriate.
- *
- * zvrf -> The zvrf that is being brought up and enabled by the kernel
- * stable -> The stable we are looking at.
- * afi -> the afi in question
- * safi -> the safi in question
- */
-static void static_enable_vrf(struct zebra_vrf *zvrf,
- struct route_table *stable,
- afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_route *si;
- struct interface *ifp;
- struct vrf *vrf = zvrf->vrf;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- for (si = rn->info; si; si = si->next) {
- si->vrf_id = vrf->vrf_id;
- if (si->ifindex) {
- ifp = if_lookup_by_name(si->ifname,
- si->nh_vrf_id);
- if (ifp)
- si->ifindex = ifp->ifindex;
- else
- continue;
- }
- static_install_route(afi, safi, &rn->p, NULL, si);
- }
- }
-}
-
-/*
- * When a vrf is being enabled by the kernel, go through all the
- * static routes in the system that use this vrf (both nexthops vrfs
- * and the routes vrf )
- *
- * enable_zvrf -> the vrf being enabled
- */
-void static_fixup_vrf_ids(struct zebra_vrf *enable_zvrf)
-{
- struct route_table *stable;
- struct vrf *vrf;
- afi_t afi;
- safi_t safi;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct zebra_vrf *zvrf;
-
- zvrf = vrf->info;
- /* Install any static routes configured for this VRF. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- stable = zvrf->stable[afi][safi];
- if (!stable)
- continue;
-
- static_fixup_vrf(enable_zvrf, stable,
- afi, safi);
-
- if (enable_zvrf == zvrf)
- static_enable_vrf(zvrf, stable,
- afi, safi);
- }
- }
- }
-}
-
-/*
- * Look at the specified stable and if any of the routes in
- * this table are using the zvrf as the nexthop, uninstall
- * those routes.
- *
- * zvrf -> the vrf being disabled
- * stable -> the table we need to look at.
- * afi -> the afi in question
- * safi -> the safi in question
- */
-static void static_cleanup_vrf(struct zebra_vrf *zvrf,
- struct route_table *stable,
- afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_route *si;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- for (si = rn->info; si; si = si->next) {
- if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0)
- continue;
-
- static_uninstall_route(afi, safi, &rn->p, NULL, si);
- }
- }
-}
-
-/*
- * Look at all static routes in this table and uninstall
- * them.
- *
- * stable -> The table to uninstall from
- * afi -> The afi in question
- * safi -> the safi in question
- */
-static void static_disable_vrf(struct route_table *stable,
- afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_route *si;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- for (si = rn->info; si; si = si->next) {
- static_uninstall_route(afi, safi, &rn->p, NULL, si);
- }
- }
-}
-
-/*
- * When the disable_zvrf is shutdown by the kernel, we call
- * this function and it cleans up all static routes using
- * this vrf as a nexthop as well as all static routes
- * in it's stables.
- *
- * disable_zvrf - The vrf being disabled
- */
-void static_cleanup_vrf_ids(struct zebra_vrf *disable_zvrf)
-{
- struct vrf *vrf;
- afi_t afi;
- safi_t safi;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct zebra_vrf *zvrf;
-
- zvrf = vrf->info;
-
- /* Uninstall any static routes configured for this VRF. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- struct route_table *stable;
-
- stable = zvrf->stable[afi][safi];
- if (!stable)
- continue;
-
- static_cleanup_vrf(disable_zvrf, stable,
- afi, safi);
-
- if (disable_zvrf == zvrf)
- static_disable_vrf(stable, afi, safi);
- }
- }
- }
-}
-
-/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
-void static_ifindex_update(struct interface *ifp, bool up)
-{
- static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
- static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
- static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
- static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
-}
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 3c21c3c1e5..05ae418b57 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -35,7 +35,6 @@
#include "zebra/zebra_rnh.h"
#include "zebra/router-id.h"
#include "zebra/zebra_memory.h"
-#include "zebra/zebra_static.h"
#include "zebra/interface.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_vxlan.h"
@@ -155,8 +154,6 @@ static int zebra_vrf_disable(struct vrf *vrf)
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
zvrf_id(zvrf));
- static_cleanup_vrf_ids(zvrf);
-
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
@@ -268,9 +265,6 @@ static int zebra_vrf_delete(struct vrf *vrf)
route_table_finish(table);
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
}
-
- table = zvrf->stable[afi][safi];
- route_table_finish(table);
}
route_table_finish(zvrf->rnh_table[afi]);
@@ -294,24 +288,6 @@ static int zebra_vrf_delete(struct vrf *vrf)
*/
int zebra_vrf_has_config(struct zebra_vrf *zvrf)
{
- afi_t afi;
- safi_t safi;
- struct route_table *stable;
-
- /* NOTE: This is a don't care for the default VRF, but we go through
- * the motions to keep things consistent.
- */
- /* Any static routes? */
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- stable = zvrf->stable[afi][safi];
- if (!stable)
- continue;
- if (route_table_count(stable))
- return 1;
- }
- }
-
/* EVPN L3-VNI? */
if (zvrf->l3vni)
return 1;
@@ -366,18 +342,6 @@ void zebra_rtable_node_cleanup(struct route_table *table,
XFREE(MTYPE_RIB_DEST, node->info);
}
-static void zebra_stable_node_cleanup(struct route_table *table,
- struct route_node *node)
-{
- struct static_route *si, *next;
-
- if (node->info)
- for (si = node->info; si; si = next) {
- next = si->next;
- XFREE(MTYPE_STATIC_ROUTE, si);
- }
-}
-
static void zebra_rnhtable_node_cleanup(struct route_table *table,
struct route_node *node)
{
@@ -414,24 +378,9 @@ static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
struct zebra_vrf *zebra_vrf_alloc(void)
{
struct zebra_vrf *zvrf;
- afi_t afi;
- safi_t safi;
- struct route_table *table;
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
- /* Allocate table for static route configuration. */
- for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
- for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
- if (afi == AFI_IP6)
- table = srcdest_table_init();
- else
- table = route_table_init();
- table->cleanup = zebra_stable_node_cleanup;
- zvrf->stable[afi][safi] = table;
- }
- }
-
zebra_vxlan_init_tables(zvrf);
zebra_mpls_init_tables(zvrf);
zebra_pw_init(zvrf);
@@ -475,19 +424,6 @@ struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id)
return zvrf->table[afi][safi];
}
-/* Lookup the static routing table in a VRF. */
-struct route_table *zebra_vrf_static_table(afi_t afi, safi_t safi,
- struct zebra_vrf *zvrf)
-{
- if (!zvrf)
- return NULL;
-
- if (afi >= AFI_MAX || safi >= SAFI_MAX)
- return NULL;
-
- return zvrf->stable[afi][safi];
-}
-
struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id,
vrf_id_t vrf_id)
{
@@ -545,10 +481,6 @@ static int vrf_config_write(struct vty *vty)
}
- static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
- static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute");
- static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route");
-
if (zvrf_id(zvrf) != VRF_DEFAULT)
vty_endframe(vty, " exit-vrf\n!\n");
}
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 5c5d2f5225..b8664f4ec7 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -53,9 +53,6 @@ struct zebra_vrf {
/* Routing table. */
struct route_table *table[AFI_MAX][SAFI_MAX];
- /* Static route configuration. */
- struct route_table *stable[AFI_MAX][SAFI_MAX];
-
/* Recursive Nexthop table */
struct route_table *rnh_table[AFI_MAX];
@@ -159,8 +156,7 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id);
extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *);
extern struct zebra_vrf *zebra_vrf_alloc(void);
extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t);
-extern struct route_table *zebra_vrf_static_table(afi_t, safi_t,
- struct zebra_vrf *zvrf);
+
extern struct route_table *
zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, vrf_id_t vrf_id);
extern int zebra_vrf_has_config(struct zebra_vrf *zvrf);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 4d71682f64..4f1d5cf6d5 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -41,7 +41,6 @@
#include "zebra/zebra_rnh.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
-#include "zebra/zebra_static.h"
#include "lib/json.h"
#include "zebra/zebra_vxlan.h"
#ifndef VTYSH_EXTRACT_PL
@@ -78,572 +77,6 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
/* VNI range as per RFC 7432 */
#define CMD_VNI_RANGE "(1-16777215)"
-struct static_hold_route {
- char *vrf_name;
- char *nhvrf_name;
- afi_t afi;
- safi_t safi;
- char *dest_str;
- char *mask_str;
- char *src_str;
- char *gate_str;
- char *ifname;
- char *flag_str;
- char *tag_str;
- char *distance_str;
- char *label_str;
- char *table_str;
-
- /* processed & masked destination, used for config display */
- struct prefix dest;
-};
-
-static struct list *static_list;
-
-static int static_list_compare_helper(const char *s1, const char *s2)
-{
- /* Are Both NULL */
- if (s1 == s2)
- return 0;
-
- if (!s1 && s2)
- return -1;
-
- if (s1 && !s2)
- return 1;
-
- return strcmp(s1, s2);
-}
-
-static void static_list_delete(struct static_hold_route *shr)
-{
- if (shr->vrf_name)
- XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
- if (shr->nhvrf_name)
- XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
- if (shr->dest_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
- if (shr->mask_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
- if (shr->src_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
- if (shr->gate_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
- if (shr->ifname)
- XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
- if (shr->flag_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
- if (shr->tag_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
- if (shr->distance_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
- if (shr->label_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
-
- XFREE(MTYPE_STATIC_ROUTE, shr);
-}
-
-static int static_list_compare(void *arg1, void *arg2)
-{
- struct static_hold_route *shr1 = arg1;
- struct static_hold_route *shr2 = arg2;
- int ret;
-
- ret = strcmp(shr1->vrf_name, shr2->vrf_name);
- if (ret)
- return ret;
-
- ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
- if (ret)
- return ret;
-
- ret = shr1->afi - shr2->afi;
- if (ret)
- return ret;
-
- ret = shr1->safi - shr2->safi;
- if (ret)
- return ret;
-
- ret = prefix_cmp(&shr1->dest, &shr2->dest);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->distance_str,
- shr2->distance_str);
- if (ret)
- return ret;
-
- ret = static_list_compare_helper(shr1->table_str,
- shr2->table_str);
- if (ret)
- return ret;
-
- return static_list_compare_helper(shr1->label_str, shr2->label_str);
-}
-
-
-/* General function for static route. */
-static int zebra_static_route_holdem(
- struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf, afi_t afi,
- safi_t safi, const char *negate, struct prefix *dest,
- const char *dest_str, const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname, const char *flag_str,
- const char *tag_str, const char *distance_str, const char *label_str,
- const char *table_str)
-{
- struct static_hold_route *shr, *lookup;
- struct listnode *node;
-
- zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
- dest_str);
-
- shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
- shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, zvrf->vrf->name);
- shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_zvrf->vrf->name);
- shr->afi = afi;
- shr->safi = safi;
- if (dest)
- prefix_copy(&shr->dest, dest);
- if (dest_str)
- shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
- if (mask_str)
- shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
- if (src_str)
- shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
- if (gate_str)
- shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
- if (ifname)
- shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
- if (flag_str)
- shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
- if (tag_str)
- shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
- if (distance_str)
- shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
- if (label_str)
- shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
- if (table_str)
- shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str);
-
- for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
- if (static_list_compare(shr, lookup) == 0)
- break;
- }
-
- if (lookup) {
- if (negate) {
- listnode_delete(static_list, lookup);
- static_list_delete(shr);
- static_list_delete(lookup);
-
- return CMD_SUCCESS;
- }
-
- /*
- * If a person enters the same line again
- * we need to silently accept it
- */
- goto shr_cleanup;
- }
-
- if (!negate) {
- listnode_add_sort(static_list, shr);
- return CMD_SUCCESS;
- }
-
-shr_cleanup:
- XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
- XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
- XFREE(MTYPE_STATIC_ROUTE, shr);
-
- return CMD_SUCCESS;
-}
-
-static int zebra_static_route_leak(
- struct vty *vty, struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf,
- afi_t afi, safi_t safi, const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str, const char *gate_str,
- const char *ifname, const char *flag_str, const char *tag_str,
- const char *distance_str, const char *label_str, const char *table_str)
-{
- int ret;
- uint8_t distance;
- struct prefix p, src;
- struct prefix_ipv6 *src_p = NULL;
- union g_addr gate;
- union g_addr *gatep = NULL;
- struct in_addr mask;
- enum static_blackhole_type bh_type = 0;
- route_tag_t tag = 0;
- uint8_t type;
- struct static_nh_label snh_label;
- uint32_t table_id = 0;
-
- ret = str2prefix(dest_str, &p);
- if (ret <= 0) {
- if (vty)
- vty_out(vty, "%% Malformed address\n");
- else
- zlog_warn("%s: Malformed address: %s",
- __PRETTY_FUNCTION__, dest_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- switch (afi) {
- case AFI_IP:
- /* Cisco like mask notation. */
- if (mask_str) {
- ret = inet_aton(mask_str, &mask);
- if (ret == 0) {
- if (vty)
- vty_out(vty, "%% Malformed address\n");
- else
- zlog_warn("%s: Malformed address: %s",
- __PRETTY_FUNCTION__,
- mask_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- p.prefixlen = ip_masklen(mask);
- }
- break;
- case AFI_IP6:
- /* srcdest routing */
- if (src_str) {
- ret = str2prefix(src_str, &src);
- if (ret <= 0 || src.family != AF_INET6) {
- if (vty)
- vty_out(vty,
- "%% Malformed source address\n");
- else
- zlog_warn(
- "%s: Malformed Source address: %s",
- __PRETTY_FUNCTION__, src_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- src_p = (struct prefix_ipv6 *)&src;
- }
- break;
- default:
- break;
- }
-
- /* Apply mask for given prefix. */
- apply_mask(&p);
-
- if (zvrf->vrf->vrf_id == VRF_UNKNOWN
- || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) {
- vrf_set_user_cfged(zvrf->vrf);
- return zebra_static_route_holdem(
- zvrf, nh_zvrf, afi, safi, negate, &p, dest_str,
- mask_str, src_str, gate_str, ifname, flag_str, tag_str,
- distance_str, label_str, table_str);
- }
- if (table_str) {
- /* table configured. check consistent with vrf config
- */
- if (zvrf->table_id != RT_TABLE_MAIN &&
- zvrf->table_id != zebrad.rtm_table_default) {
- if (vty)
- vty_out(vty,
- "%% Table %s overlaps vrf table %u\n",
- table_str, zvrf->table_id);
- else
- zlog_warn(
- "%s: Table %s overlaps vrf table %u",
- __PRETTY_FUNCTION__,
- table_str, zvrf->table_id);
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- /* Administrative distance. */
- if (distance_str)
- distance = atoi(distance_str);
- else
- distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
-
- /* tag */
- if (tag_str)
- tag = strtoul(tag_str, NULL, 10);
-
- /* Labels */
- memset(&snh_label, 0, sizeof(struct static_nh_label));
- if (label_str) {
- if (!mpls_enabled) {
- if (vty)
- vty_out(vty,
- "%% MPLS not turned on in kernel, ignoring command\n");
- else
- zlog_warn(
- "%s: MPLS not turned on in kernel ignoring static route to %s",
- __PRETTY_FUNCTION__, dest_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- int rc = mpls_str2label(label_str, &snh_label.num_labels,
- snh_label.label);
- if (rc < 0) {
- switch (rc) {
- case -1:
- if (vty)
- vty_out(vty, "%% Malformed label(s)\n");
- else
- zlog_warn(
- "%s: Malformed labels specified for route %s",
- __PRETTY_FUNCTION__, dest_str);
- break;
- case -2:
- if (vty)
- vty_out(vty,
- "%% Cannot use reserved label(s) (%d-%d)\n",
- MPLS_LABEL_RESERVED_MIN,
- MPLS_LABEL_RESERVED_MAX);
- else
- zlog_warn(
- "%s: Cannot use reserved labels (%d-%d) for %s",
- __PRETTY_FUNCTION__,
- MPLS_LABEL_RESERVED_MIN,
- MPLS_LABEL_RESERVED_MAX,
- dest_str);
- break;
- case -3:
- if (vty)
- vty_out(vty,
- "%% Too many labels. Enter %d or fewer\n",
- MPLS_MAX_LABELS);
- else
- zlog_warn(
- "%s: Too many labels, Enter %d or fewer for %s",
- __PRETTY_FUNCTION__,
- MPLS_MAX_LABELS, dest_str);
- break;
- }
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
- /* TableID */
- if (table_str)
- table_id = atol(table_str);
-
- /* Null0 static route. */
- if (ifname != NULL) {
- if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0
- || strncasecmp(ifname, "reject", strlen(ifname)) == 0
- || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) {
- if (vty)
- vty_out(vty,
- "%% Nexthop interface cannot be Null0, reject or blackhole\n");
- else
- zlog_warn(
- "%s: Nexthop interface cannot be Null0, reject or blackhole for %s",
- __PRETTY_FUNCTION__, dest_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- /* Route flags */
- if (flag_str) {
- switch (flag_str[0]) {
- case 'r':
- bh_type = STATIC_BLACKHOLE_REJECT;
- break;
- case 'b':
- bh_type = STATIC_BLACKHOLE_DROP;
- break;
- case 'N':
- bh_type = STATIC_BLACKHOLE_NULL;
- break;
- default:
- if (vty)
- vty_out(vty, "%% Malformed flag %s \n",
- flag_str);
- else
- zlog_warn("%s: Malformed flag %s for %s",
- __PRETTY_FUNCTION__, flag_str,
- dest_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- if (gate_str) {
- if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
- if (vty)
- vty_out(vty,
- "%% Malformed nexthop address %s\n",
- gate_str);
- else
- zlog_warn(
- "%s: Malformed nexthop address %s for %s",
- __PRETTY_FUNCTION__, gate_str,
- dest_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- gatep = &gate;
- }
-
- if (gate_str == NULL && ifname == NULL)
- type = STATIC_BLACKHOLE;
- else if (gate_str && ifname) {
- if (afi == AFI_IP)
- type = STATIC_IPV4_GATEWAY_IFNAME;
- else
- type = STATIC_IPV6_GATEWAY_IFNAME;
- } else if (ifname)
- type = STATIC_IFNAME;
- else {
- if (afi == AFI_IP)
- type = STATIC_IPV4_GATEWAY;
- else
- type = STATIC_IPV6_GATEWAY;
- }
-
- if (!negate) {
- static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
- bh_type, tag, distance, zvrf, nh_zvrf,
- &snh_label, table_id);
- /* Mark as having FRR configuration */
- vrf_set_user_cfged(zvrf->vrf);
- } else {
- static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
- tag, distance, zvrf, &snh_label, table_id);
- /* If no other FRR config for this VRF, mark accordingly. */
- if (!zebra_vrf_has_config(zvrf))
- vrf_reset_user_cfged(zvrf->vrf);
- }
-
- return CMD_SUCCESS;
-}
-
-static struct zebra_vrf *zebra_vty_get_unknown_vrf(struct vty *vty,
- const char *vrf_name)
-{
- struct zebra_vrf *zvrf;
- struct vrf *vrf;
-
- zvrf = zebra_vrf_lookup_by_name(vrf_name);
-
- if (zvrf)
- return zvrf;
-
- vrf = vrf_get(VRF_UNKNOWN, vrf_name);
- if (!vrf) {
- vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
- return NULL;
- }
- zvrf = vrf->info;
- if (!zvrf) {
- vty_out(vty, "%% Could not create vrf-info %s\n",
- vrf_name);
- return NULL;
- }
- /* Mark as having FRR configuration */
- vrf_set_user_cfged(vrf);
-
- return zvrf;
-}
-
-static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *vrf_name,
- const char *label_str, const char *table_str)
-{
- struct zebra_vrf *zvrf;
-
- /* VRF id */
- zvrf = zebra_vrf_lookup_by_name(vrf_name);
-
- /* When trying to delete, the VRF must exist. */
- if (negate && !zvrf) {
- vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* When trying to create, create the VRF if it doesn't exist.
- * Note: The VRF isn't active until we hear about it from the kernel.
- */
- if (!zvrf) {
- zvrf = zebra_vty_get_unknown_vrf(vty, vrf_name);
- if (!zvrf)
- return CMD_WARNING_CONFIG_FAILED;
- }
- return zebra_static_route_leak(
- vty, zvrf, zvrf, afi, safi, negate, dest_str, mask_str, src_str,
- gate_str, ifname, flag_str, tag_str, distance_str, label_str,
- table_str);
-}
-
-void static_config_install_delayed_routes(struct zebra_vrf *zvrf)
-{
- struct listnode *node, *nnode;
- struct static_hold_route *shr;
- struct zebra_vrf *ozvrf, *nh_zvrf;
- int installed;
-
- for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) {
- ozvrf = zebra_vrf_lookup_by_name(shr->vrf_name);
- nh_zvrf = zebra_vrf_lookup_by_name(shr->nhvrf_name);
-
- if (ozvrf != zvrf && nh_zvrf != zvrf)
- continue;
-
- if (ozvrf->vrf->vrf_id == VRF_UNKNOWN
- || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN)
- continue;
-
- installed = zebra_static_route_leak(
- NULL, ozvrf, nh_zvrf, shr->afi, shr->safi, NULL,
- shr->dest_str, shr->mask_str, shr->src_str,
- shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str,
- shr->distance_str, shr->label_str, shr->table_str);
-
- if (installed != CMD_SUCCESS)
- zlog_debug(
- "%s: Attempt to install %s as a route and it was rejected",
- __PRETTY_FUNCTION__, shr->dest_str);
- listnode_delete(static_list, shr);
- static_list_delete(shr);
- }
-}
-/* Static unicast routes for multicast RPF lookup. */
-DEFPY (ip_mroute_dist,
- ip_mroute_dist_cmd,
- "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
- NO_STR
- IP_STR
- "Configure static unicast route into MRIB for multicast RPF lookup\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "Nexthop address\n"
- "Nexthop interface name\n"
- "Distance\n")
-{
- return zebra_static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
- NULL, NULL, gate_str, ifname, NULL, NULL,
- distance_str, NULL, NULL, NULL);
-}
-
DEFUN (ip_multicast_mode,
ip_multicast_mode_cmd,
"ip multicast rpf-lookup-mode <urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix>",
@@ -737,343 +170,6 @@ DEFUN (show_ip_rpf_addr,
return CMD_SUCCESS;
}
-/* Static route configuration. */
-DEFPY(ip_route_blackhole,
- ip_route_blackhole_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- <reject|blackhole>$flag \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n")
-{
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
- mask_str, NULL, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
-}
-
-DEFPY(ip_route_blackhole_vrf,
- ip_route_blackhole_vrf_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- <reject|blackhole>$flag \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n")
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- struct zebra_vrf *zvrf = vrf->info;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- /*
- * Coverity is complaining that prefix could
- * be dereferenced, but we know that prefix will
- * valid. Add an assert to make it happy
- */
- assert(prefix);
- return zebra_static_route_leak(vty, zvrf, zvrf, AFI_IP, SAFI_UNICAST,
- no, prefix, mask_str, NULL, NULL, NULL,
- flag, tag_str, distance_str, label, table_str);
-}
-
-DEFPY(ip_route_address_interface,
- ip_route_address_interface_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- A.B.C.D$gate \
- INTERFACE$ifname \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \
- null route.\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- struct zebra_vrf *zvrf;
- struct zebra_vrf *nh_zvrf;
-
- const char *flag = NULL;
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- zvrf = zebra_vty_get_unknown_vrf(vty, vrf);
- if (!zvrf) {
- vty_out(vty, "%% vrf %s is not defined\n", vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
- NULL, gate_str, ifname, flag, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ip_route_address_interface_vrf,
- ip_route_address_interface_vrf_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- A.B.C.D$gate \
- INTERFACE$ifname \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \
- null route.\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- const char *flag = NULL;
- struct zebra_vrf *zvrf = vrf->info;
- struct zebra_vrf *nh_zvrf;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
- NULL, gate_str, ifname, flag, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ip_route,
- ip_route_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- <A.B.C.D$gate|INTERFACE$ifname> \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- struct zebra_vrf *zvrf;
- struct zebra_vrf *nh_zvrf;
- const char *flag = NULL;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- zvrf = zebra_vty_get_unknown_vrf(vty, vrf);
- if (!zvrf) {
- vty_out(vty, "%% vrf %s is not defined\n", vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
- NULL, gate_str, ifname, flag, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ip_route_vrf,
- ip_route_vrf_cmd,
- "[no] ip route\
- <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
- <A.B.C.D$gate|INTERFACE$ifname> \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR IP_STR
- "Establish static routes\n"
- "IP destination prefix (e.g. 10.0.0.0/8)\n"
- "IP destination prefix\n"
- "IP destination prefix mask\n"
- "IP gateway address\n"
- "IP gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this route\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- struct zebra_vrf *zvrf = vrf->info;
- struct zebra_vrf *nh_zvrf;
- const char *flag = NULL;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
- NULL, gate_str, ifname, flag, tag_str, distance_str, label,
- table_str);
-}
-
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast)
@@ -1308,6 +404,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_object_int_add(json_route, "metric", re->metric);
}
+ if (re->tag)
+ json_object_int_add(json_route, "tag", re->tag);
+
json_object_int_add(json_route, "internalStatus",
re->status);
json_object_int_add(json_route, "internalFlags",
@@ -1633,6 +732,29 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
}
}
+static void vty_show_ip_route_detail_json(struct vty *vty,
+ struct route_node *rn)
+{
+ json_object *json = NULL;
+ json_object *json_prefix = NULL;
+ struct route_entry *re;
+ char buf[BUFSIZ];
+
+ json = json_object_new_object();
+
+ RNODE_FOREACH_RE (rn, re) {
+ json_prefix = json_object_new_array();
+ vty_show_ip_route(vty, rn, re, json_prefix);
+ prefix2str(&rn->p, buf, sizeof buf);
+ json_object_object_add(json, buf, json_prefix);
+ json_prefix = NULL;
+ }
+
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+}
+
static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
struct route_table *table, afi_t afi,
bool use_fib, route_tag_t tag,
@@ -1714,15 +836,15 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
}
if (json_prefix) {
- prefix2str(&rn->p, buf, sizeof buf);
+ prefix2str(&rn->p, buf, sizeof(buf));
json_object_object_add(json, buf, json_prefix);
json_prefix = NULL;
}
}
if (use_json) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
}
@@ -2061,7 +1183,8 @@ DEFPY (show_route_detail,
X:X::X:X$address\
|X:X::X:X/M$prefix\
>\
- >",
+ >\
+ [json$json]",
SHOW_STR
IP_STR
"IP routing table\n"
@@ -2072,7 +1195,8 @@ DEFPY (show_route_detail,
"IP routing table\n"
VRF_FULL_CMD_HELP_STR
"IPv6 Address\n"
- "IPv6 prefix\n")
+ "IPv6 prefix\n"
+ JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
struct route_table *table;
@@ -2103,7 +1227,10 @@ DEFPY (show_route_detail,
continue;
}
- vty_show_ip_route_detail(vty, rn, 0);
+ if (json)
+ vty_show_ip_route_detail_json(vty, rn);
+ else
+ vty_show_ip_route_detail(vty, rn, 0);
route_unlock_node(rn);
}
@@ -2128,7 +1255,10 @@ DEFPY (show_route_detail,
return CMD_WARNING;
}
- vty_show_ip_route_detail(vty, rn, 0);
+ if (json)
+ vty_show_ip_route_detail_json(vty, rn);
+ else
+ vty_show_ip_route_detail(vty, rn, 0);
route_unlock_node(rn);
}
@@ -2331,449 +1461,6 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
vty_out(vty, "\n");
}
-/* Write static route configuration. */
-int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
- safi_t safi, const char *cmd)
-{
- struct static_hold_route *shr;
- struct listnode *node;
- char spacing[100];
- struct route_node *rn;
- struct static_route *si;
- struct route_table *stable;
- char buf[SRCDEST2STR_BUFFER];
- int write = 0;
-
- if ((stable = zvrf->stable[afi][safi]) == NULL)
- return write;
-
- sprintf(spacing, "%s%s", (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ",
- cmd);
-
- /*
- * Static routes for vrfs not fully inited
- */
- for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) {
- if (shr->afi != afi || shr->safi != safi)
- continue;
-
- if (strcmp(zvrf->vrf->name, shr->vrf_name) != 0)
- continue;
-
- char dest_str[PREFIX_STRLEN];
-
- prefix2str(&shr->dest, dest_str, sizeof(dest_str));
-
- vty_out(vty, "%s ", spacing);
- if (shr->dest_str)
- vty_out(vty, "%s ", dest_str);
- if (shr->src_str)
- vty_out(vty, "from %s ", shr->src_str);
- if (shr->gate_str)
- vty_out(vty, "%s ", shr->gate_str);
- if (shr->ifname)
- vty_out(vty, "%s ", shr->ifname);
- if (shr->flag_str)
- vty_out(vty, "%s ", shr->flag_str);
- if (shr->tag_str)
- vty_out(vty, "tag %s ", shr->tag_str);
- if (shr->distance_str)
- vty_out(vty, "%s ", shr->distance_str);
- if (shr->label_str)
- vty_out(vty, "label %s ", shr->label_str);
- if (shr->table_str)
- vty_out(vty, "table %s ", shr->table_str);
- if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0)
- vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name);
- vty_out(vty, "\n");
- }
-
- for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
- for (si = rn->info; si; si = si->next) {
- vty_out(vty, "%s %s", spacing,
- srcdest_rnode2str(rn, buf, sizeof buf));
-
- switch (si->type) {
- case STATIC_IPV4_GATEWAY:
- vty_out(vty, " %s", inet_ntoa(si->addr.ipv4));
- break;
- case STATIC_IPV6_GATEWAY:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &si->addr.ipv6, buf,
- sizeof buf));
- break;
- case STATIC_IFNAME:
- vty_out(vty, " %s", si->ifname);
- break;
- case STATIC_BLACKHOLE:
- switch (si->bh_type) {
- case STATIC_BLACKHOLE_DROP:
- vty_out(vty, " blackhole");
- break;
- case STATIC_BLACKHOLE_NULL:
- vty_out(vty, " Null0");
- break;
- case STATIC_BLACKHOLE_REJECT:
- vty_out(vty, " reject");
- break;
- }
- break;
- case STATIC_IPV4_GATEWAY_IFNAME:
- vty_out(vty, " %s %s",
- inet_ntop(AF_INET, &si->addr.ipv4, buf,
- sizeof buf),
- si->ifname);
- break;
- case STATIC_IPV6_GATEWAY_IFNAME:
- vty_out(vty, " %s %s",
- inet_ntop(AF_INET6, &si->addr.ipv6, buf,
- sizeof buf),
- si->ifname);
- break;
- }
-
- if (si->tag)
- vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag);
-
- if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
- vty_out(vty, " %d", si->distance);
-
- /* Label information */
- if (si->snh_label.num_labels)
- vty_out(vty, " label %s",
- mpls_label2str(si->snh_label.num_labels,
- si->snh_label.label, buf,
- sizeof buf, 0));
-
- if (si->nh_vrf_id != si->vrf_id) {
- vty_out(vty, " nexthop-vrf %s", si->nh_vrfname);
- }
-
- /* table ID from VRF overrides configured
- */
- if (si->table_id && zvrf->table_id == RT_TABLE_MAIN)
- vty_out(vty, " table %u", si->table_id);
-
- vty_out(vty, "\n");
-
- write = 1;
- }
- return write;
-}
-
-DEFPY(ipv6_route_blackhole,
- ipv6_route_blackhole_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- <Null0|reject|blackhole>$flag \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "Null interface\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n")
-{
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
- NULL, from_str, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
-}
-
-DEFPY(ipv6_route_blackhole_vrf,
- ipv6_route_blackhole_vrf_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- <Null0|reject|blackhole>$flag \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "Null interface\n"
- "Emit an ICMP unreachable when matched\n"
- "Silently discard pkts when matched\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n")
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- struct zebra_vrf *zvrf = vrf->info;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- /*
- * Coverity is complaining that prefix could
- * be dereferenced, but we know that prefix will
- * valid. Add an assert to make it happy
- */
- assert(prefix);
- return zebra_static_route_leak(
- vty, zvrf, zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
- from_str, NULL, NULL, flag, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ipv6_route_address_interface,
- ipv6_route_address_interface_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- X:X::X:X$gate \
- INTERFACE$ifname \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "IPv6 gateway address\n"
- "IPv6 gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- struct zebra_vrf *zvrf;
- struct zebra_vrf *nh_zvrf;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- zvrf = zebra_vty_get_unknown_vrf(vty, vrf);
- if (!zvrf) {
- vty_out(vty, "%% vrf %s is not defined\n", vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
- from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ipv6_route_address_interface_vrf,
- ipv6_route_address_interface_vrf_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- X:X::X:X$gate \
- INTERFACE$ifname \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "IPv6 gateway address\n"
- "IPv6 gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- struct zebra_vrf *zvrf = vrf->info;
- struct zebra_vrf *nh_zvrf;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
- from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ipv6_route,
- ipv6_route_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- <X:X::X:X$gate|INTERFACE$ifname> \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |vrf NAME \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "IPv6 gateway address\n"
- "IPv6 gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- VRF_CMD_HELP_STR
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- struct zebra_vrf *zvrf;
- struct zebra_vrf *nh_zvrf;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- zvrf = zebra_vty_get_unknown_vrf(vty, vrf);
- if (!zvrf) {
- vty_out(vty, "%% vrf %s is not defined\n", vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
- from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
- table_str);
-}
-
-DEFPY(ipv6_route_vrf,
- ipv6_route_vrf_cmd,
- "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
- <X:X::X:X$gate|INTERFACE$ifname> \
- [{ \
- tag (1-4294967295) \
- |(1-255)$distance \
- |label WORD \
- |table (1-4294967295) \
- |nexthop-vrf NAME \
- }]",
- NO_STR
- IPV6_STR
- "Establish static routes\n"
- "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
- "IPv6 source-dest route\n"
- "IPv6 source prefix\n"
- "IPv6 gateway address\n"
- "IPv6 gateway interface name\n"
- "Set tag for this route\n"
- "Tag value\n"
- "Distance value for this prefix\n"
- MPLS_LABEL_HELPSTR
- "Table to configure\n"
- "The table number to configure\n"
- VRF_CMD_HELP_STR)
-{
- VTY_DECLVAR_CONTEXT(vrf, vrf);
- struct zebra_vrf *zvrf = vrf->info;
- struct zebra_vrf *nh_zvrf;
-
- if (table_str && !vrf_is_backend_netns()) {
- vty_out(vty,
- "%% table param only available when running on netns-based vrfs\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (nexthop_vrf)
- nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf);
- else
- nh_zvrf = zvrf;
-
- if (!nh_zvrf) {
- vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return zebra_static_route_leak(
- vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
- from_str, gate_str, ifname, NULL, tag_str, distance_str, label,
- table_str);
-}
-
/*
* Show IPv6 mroute command.Used to dump
* the Multicast routing table.
@@ -3932,16 +2619,9 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &allow_external_route_update_cmd);
install_element(CONFIG_NODE, &no_allow_external_route_update_cmd);
- install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
+
install_element(CONFIG_NODE, &ip_multicast_mode_cmd);
install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd);
- install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
- install_element(CONFIG_NODE,
- &ip_route_address_interface_cmd);
- install_element(CONFIG_NODE, &ip_route_cmd);
- install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
- install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
- install_element(VRF_NODE, &ip_route_vrf_cmd);
install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd);
install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd);
@@ -3966,15 +2646,6 @@ void zebra_vty_init(void)
install_element(VIEW_NODE, &show_ip_rpf_cmd);
install_element(VIEW_NODE, &show_ip_rpf_addr_cmd);
- install_element(CONFIG_NODE,
- &ipv6_route_blackhole_cmd);
- install_element(CONFIG_NODE,
- &ipv6_route_address_interface_cmd);
- install_element(CONFIG_NODE, &ipv6_route_cmd);
- install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
- install_element(VRF_NODE,
- &ipv6_route_address_interface_vrf_cmd);
- install_element(VRF_NODE, &ipv6_route_vrf_cmd);
install_element(CONFIG_NODE, &ip_nht_default_route_cmd);
install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd);
install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd);
@@ -4011,7 +2682,5 @@ void zebra_vty_init(void)
install_element(VRF_NODE, &vrf_vni_mapping_cmd);
install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
- static_list = list_new();
- static_list->cmp = (int (*)(void *, void *))static_list_compare;
- static_list->del = (void (*)(void *))static_list_delete;
+
}