diff options
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, ¬e)) + 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 Binary files differindex cca702b138..4abbe81499 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz 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 @@ -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; + } |
