]> git.puffer.fish Git - mirror/frr.git/commitdiff
staticd: Start the addition of a staticd
authorDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 8 May 2018 11:58:32 +0000 (07:58 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Sun, 29 Jul 2018 16:37:24 +0000 (12:37 -0400)
This is the start of separating out the static
handling code from zebra -> staticd.  This will
help simplify the zebra code and isolate static
route handling to it's own code base.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
32 files changed:
Makefile.am
configure.ac
staticd/.gitignore [new file with mode: 0644]
staticd/Makefile [new file with mode: 0644]
staticd/static_main.c [new file with mode: 0644]
staticd/static_memory.c [new file with mode: 0644]
staticd/static_memory.h [new file with mode: 0644]
staticd/static_nht.c [new file with mode: 0644]
staticd/static_nht.h [new file with mode: 0644]
staticd/static_routes.c [new file with mode: 0644]
staticd/static_routes.h [new file with mode: 0644]
staticd/static_vrf.c [new file with mode: 0644]
staticd/static_vrf.h [new file with mode: 0644]
staticd/static_vty.c [new file with mode: 0644]
staticd/static_vty.h [new file with mode: 0644]
staticd/static_zebra.c [new file with mode: 0644]
staticd/static_zebra.h [new file with mode: 0644]
staticd/staticd.conf.sample [new file with mode: 0644]
staticd/subdir.am [new file with mode: 0644]
vtysh/Makefile.am
vtysh/vtysh.c
vtysh/vtysh.h
zebra/interface.c
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_static.c
zebra/zebra_static.h
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c

index f9fb231962c7e99405c4189dbe60743f67f11737..8c96f39f397a23586eddf7635161cb48b6123410 100644 (file)
@@ -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@ \
index a155a12ba718c56463749d3b4bfa5d3ff110343f..f65b1640d2054a8b7a4885af20628af4bc9ece53 100755 (executable)
@@ -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/staticd/.gitignore b/staticd/.gitignore
new file mode 100644 (file)
index 0000000..af89530
--- /dev/null
@@ -0,0 +1,2 @@
+libstatic.a
+staticd
diff --git a/staticd/Makefile b/staticd/Makefile
new file mode 100644 (file)
index 0000000..ecd33df
--- /dev/null
@@ -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 (file)
index 0000000..7da526c
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * STATICd - main code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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"
+
+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();
+
+       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 (file)
index 0000000..9eb5a6f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * static memory code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..60d2d9b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * static memory code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..e6592c9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Static NHT code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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_IPV6_GATEWAY)
+                               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, vrf_id, SAFI_UNICAST, true);
+       }
+}
diff --git a/staticd/static_nht.h b/staticd/static_nht.h
new file mode 100644 (file)
index 0000000..27d5e74
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Static NHT header.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..3eb4c8c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * STATICd - vrf code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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, 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->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)
+{
+
+       if (rn->info)
+               static_zebra_route_add(rn, vrf_id, safi, true);
+       else
+               static_zebra_route_add(rn, 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, 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, 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);
+       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, 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;
+       bool install;
+
+       for (rn = route_top(stable); rn; rn = route_next(rn)) {
+               install = false;
+               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;
+                       install = true;
+                       if (si->ifindex) {
+                               ifp = if_lookup_by_name(si->ifname,
+                                                       si->nh_vrf_id);
+                               if (ifp)
+                                       si->ifindex = ifp->ifindex;
+                               else
+                                       continue;
+                       }
+               }
+
+               if (install)
+                       static_install_route(rn, 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;
+       bool install;
+
+       for (rn = route_top(stable); rn; rn = route_next(rn)) {
+               install = false;
+               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;
+                       }
+                       install = true;
+               }
+
+               if (install)
+                       static_install_route(rn, 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);
+               }
+       }
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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/staticd/static_routes.h b/staticd/static_routes.h
new file mode 100644 (file)
index 0000000..ec4ca18
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * STATICd - static routes header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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_ROUTES_H__
+#define __STATIC_ROUTES_H__
+
+#include "lib/mpls.h"
+
+/* Static route label information */
+struct static_nh_label {
+       uint8_t num_labels;
+       uint8_t reserved[3];
+       mpls_label_t label[MPLS_MAX_LABELS];
+};
+
+enum static_blackhole_type {
+       STATIC_BLACKHOLE_DROP = 0,
+       STATIC_BLACKHOLE_NULL,
+       STATIC_BLACKHOLE_REJECT
+};
+
+typedef enum {
+       STATIC_IFNAME,
+       STATIC_IPV4_GATEWAY,
+       STATIC_IPV4_GATEWAY_IFNAME,
+       STATIC_BLACKHOLE,
+       STATIC_IPV6_GATEWAY,
+       STATIC_IPV6_GATEWAY_IFNAME,
+} static_types;
+
+/* Static route information. */
+struct static_route {
+       /* For linked list. */
+       struct static_route *prev;
+       struct static_route *next;
+
+       /* VRF identifier. */
+       vrf_id_t vrf_id;
+       vrf_id_t nh_vrf_id;
+       char nh_vrfname[VRF_NAMSIZ + 1];
+
+       /* Administrative distance. */
+       uint8_t distance;
+
+       /* Tag */
+       route_tag_t tag;
+
+       /* Flag for this static route's type. */
+       static_types type;
+
+       /*
+        * Nexthop value.
+        */
+       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;
+
+       uint32_t table_id;
+};
+
+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 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 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);
+
+extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
+
+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 (file)
index 0000000..45225bf
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * STATICd - vrf code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..40d5697
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * STATICd - vrf header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..1f54e9b
--- /dev/null
@@ -0,0 +1,1414 @@
+/*
+ * STATICd - vty code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..be7056a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * STATICd - vty header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 (file)
index 0000000..3f7440d
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Zebra connect code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "srcdest_table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+#include "nexthop.h"
+#include "nexthop_group.h"
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_zebra.h"
+#include "static_nht.h"
+#include "static_vty.h"
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient;
+
+static struct interface *zebra_interface_if_lookup(struct stream *s)
+{
+       char ifname_tmp[INTERFACE_NAMSIZ];
+
+       /* Read interface name. */
+       stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
+
+       /* And look it up. */
+       return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
+}
+
+/* Inteface addition message from zebra. */
+static int interface_add(int command, struct zclient *zclient,
+                              zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+
+       ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
+
+       if (!ifp)
+               return 0;
+
+       static_ifindex_update(ifp, true);
+       return 0;
+}
+
+static int interface_delete(int command, struct zclient *zclient,
+                           zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+       struct stream *s;
+
+       s = zclient->ibuf;
+       /* zebra_interface_state_read () updates interface structure in iflist
+        */
+       ifp = zebra_interface_state_read(s, vrf_id);
+
+       if (ifp == NULL)
+               return 0;
+
+       if_set_index(ifp, IFINDEX_INTERNAL);
+
+       static_ifindex_update(ifp, false);
+       return 0;
+}
+
+static int interface_address_add(int command, struct zclient *zclient,
+                                zebra_size_t length, vrf_id_t vrf_id)
+{
+       zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+       return 0;
+}
+
+static int interface_address_delete(int command, struct zclient *zclient,
+                                   zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct connected *c;
+
+       c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+       if (!c)
+               return 0;
+
+       connected_free(c);
+       return 0;
+}
+
+static int interface_state_up(int command, struct zclient *zclient,
+                             zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+
+       ifp = zebra_interface_if_lookup(zclient->ibuf);
+
+       if (if_is_vrf(ifp)) {
+               struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
+
+               static_fixup_vrf_ids(svrf);
+               static_config_install_delayed_routes(svrf);
+       }
+
+       return 0;
+}
+
+static int interface_state_down(int command, struct zclient *zclient,
+                               zebra_size_t length, vrf_id_t vrf_id)
+{
+       zebra_interface_state_read(zclient->ibuf, vrf_id);
+
+       return 0;
+}
+
+static int route_notify_owner(int command, struct zclient *zclient,
+                             zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct prefix p;
+       enum zapi_route_notify_owner note;
+       uint32_t table_id;
+       char buf[PREFIX_STRLEN];
+
+       prefix2str(&p, buf, sizeof(buf));
+
+       if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
+               return -1;
+
+       switch (note) {
+       case ZAPI_ROUTE_FAIL_INSTALL:
+               zlog_warn("%s: Route %s failed to install for table: %u",
+                         __PRETTY_FUNCTION__, buf, table_id);
+               break;
+       case ZAPI_ROUTE_BETTER_ADMIN_WON:
+               zlog_warn("%s: Route %s over-ridden by better route for table: %u",
+                         __PRETTY_FUNCTION__, buf, table_id);
+               break;
+       case ZAPI_ROUTE_INSTALLED:
+               break;
+       case ZAPI_ROUTE_REMOVED:
+               break;
+       case ZAPI_ROUTE_REMOVE_FAIL:
+               zlog_warn("%s: Route %s failure to remove for table: %u",
+                         __PRETTY_FUNCTION__, buf, table_id);
+               break;
+       }
+
+       return 0;
+}
+static void zebra_connected(struct zclient *zclient)
+{
+       zclient_send_reg_requests(zclient, VRF_DEFAULT);
+}
+
+
+static int static_zebra_nexthop_update(int command, struct zclient *zclient,
+                                      zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct zapi_route nhr;
+       afi_t afi = AFI_IP;
+
+       if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+               zlog_warn("Failure to decode nexthop update message");
+               return 1;
+       }
+
+       if (nhr.prefix.family == AF_INET6)
+               afi = AFI_IP6;
+
+       static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
+       return 1;
+}
+
+static void static_zebra_capabilities(struct zclient_capabilities *cap)
+{
+       mpls_enabled = cap->mpls_enabled;
+}
+
+void static_zebra_nht_register(struct static_route *si, bool reg)
+{
+       uint32_t cmd;
+       struct prefix p;
+
+       cmd = (reg) ?
+               ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
+
+       if (si->nh_registered && reg)
+               return;
+
+       if (!si->nh_registered && !reg)
+               return;
+
+       memset(&p, 0, sizeof(p));
+       switch (si->type) {
+       case STATIC_IPV4_GATEWAY_IFNAME:
+       case STATIC_IFNAME:
+       case STATIC_BLACKHOLE:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               return;
+       case STATIC_IPV4_GATEWAY:
+               p.family = AF_INET;
+               p.prefixlen = IPV4_MAX_BITLEN;
+               p.u.prefix4 = si->addr.ipv4;
+               break;
+       case STATIC_IPV6_GATEWAY:
+               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, 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.message, ZAPI_MESSAGE_NEXTHOP);
+
+       for (/*loaded above*/; si; si = si->next) {
+               api_nh = &api.nexthops[nh_num];
+               if (si->nh_vrf_id == VRF_UNKNOWN)
+                       continue;
+
+               /*
+                * If we create a ecmp static route the
+                * last distance and tag entered wins.  Why because
+                * this cli choosen sucks
+                */
+               if (si->distance) {
+                       SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+                       api.distance = si->distance;
+               }
+               if (si->tag) {
+                       SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+                       api.tag = si->tag;
+               }
+
+               api.tableid = si->table_id;
+
+               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 (file)
index 0000000..b408bc6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Zebra connect library for staticd
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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_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, 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 (file)
index 0000000..bb1c2ed
--- /dev/null
@@ -0,0 +1,3 @@
+!
+!
+log stdout
diff --git a/staticd/subdir.am b/staticd/subdir.am
new file mode 100644 (file)
index 0000000..3b06a92
--- /dev/null
@@ -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@
index 5d6f890e99fd6ba129d130bf5114aef14d7fc04e..6d0b4a8fdb85719d1ac61fc6adc0e8e01162e5cf 100644 (file)
@@ -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 \
index b56eaa899f5fb7a2b55e13ff236fa34bc667f792..e25a576926072fe574dd22cd0e6a284f33e32d31 100644 (file)
@@ -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 =
index 6fa61dd883683d71c085d0b4c41cb813c460bf8d..e6ed5659cffb8210d632e26a89515a846f1a1e66 100644 (file)
@@ -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
index 1067f9bdc1938ace635b6dd17849a7581dd47624..7fe7058de9c1b79580feae3e49cdbe2d18fcbfb8 100644 (file)
@@ -577,7 +577,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 +735,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 +774,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 +798,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 +927,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);
index 6509cdaba79b0b7e0d1efed3153afc7735efc7c3..439327aa48c6d2fede1e09e4d8e2310453402867 100644 (file)
@@ -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);
@@ -450,9 +448,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;
 
index 71d48632c14a434ec50c4f5abe61a8f42b7f40ec..33eebfe99ec0c0f6046c27758728145482613ee8 100644 (file)
@@ -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);
 }
index d482e0ab3da3ec1d796c304e3eaddf9eb031022d..453f08a183a5c750e055b33be7bf42a43d3f2c5f 100644 (file)
@@ -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");
index ea7d5545e820b5c149bfdf8b1f4cd1aaf1a190d7..9e09a1bc6f1ed54a9bf790b95f6aa942041461db 100644 (file)
@@ -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,
index 76346f6b663e62aced2cd8f5a4bfeb33afeffddb..d6e07f125475cc73c9170a91110161f2f5eb684d 100644 (file)
  * 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);
-}
index 0be434fff2220e9eea14b1fc714b74567852d031..4885b1b8fdbbfd5a66f9969e3b91b001d5ab443d 100644 (file)
 #ifndef __ZEBRA_STATIC_H__
 #define __ZEBRA_STATIC_H__
 
-#include "zebra/zebra_mpls.h"
-
-/* Static route label information */
-struct static_nh_label {
-       uint8_t num_labels;
-       uint8_t reserved[3];
-       mpls_label_t label[MPLS_MAX_LABELS];
-};
-
-enum static_blackhole_type {
-       STATIC_BLACKHOLE_DROP = 0,
-       STATIC_BLACKHOLE_NULL,
-       STATIC_BLACKHOLE_REJECT
-};
-
-typedef enum {
-       STATIC_IFNAME,
-       STATIC_IPV4_GATEWAY,
-       STATIC_IPV4_GATEWAY_IFNAME,
-       STATIC_BLACKHOLE,
-       STATIC_IPV6_GATEWAY,
-       STATIC_IPV6_GATEWAY_IFNAME,
-} zebra_static_types;
-
-/* Static route information. */
-struct static_route {
-       /* For linked list. */
-       struct static_route *prev;
-       struct static_route *next;
-
-       /* VRF identifier. */
-       vrf_id_t vrf_id;
-       vrf_id_t nh_vrf_id;
-       char nh_vrfname[VRF_NAMSIZ + 1];
-
-       /* Administrative distance. */
-       uint8_t distance;
-
-       /* Tag */
-       route_tag_t tag;
-
-       /* Flag for this static route's type. */
-       zebra_static_types type;
-
-       /*
-        * Nexthop value.
-        */
-       enum static_blackhole_type bh_type;
-       union g_addr addr;
-       ifindex_t ifindex;
-
-       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,
-                           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);
-
-extern int static_delete_route(afi_t, 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);
-
-extern void static_ifindex_update(struct interface *ifp, bool up);
-
-extern void static_cleanup_vrf_ids(struct zebra_vrf *zvrf);
-extern void static_fixup_vrf_ids(struct zebra_vrf *zvrf);
 #endif
index 3c21c3c1e585eb5c6fe35509d043b9cc2d0cea62..607001fe2b6e1362d9132e7906bb635833dddc09 100644 (file)
@@ -155,8 +155,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 +266,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 +289,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 +343,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 +379,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 +425,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 +482,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");
        }
index 5c5d2f5225f86ef37d83f8991765f65f02b5d2d8..b8664f4ec764ec64e07989edd754e91931a5ab03 100644 (file)
@@ -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);
index 4d71682f6436fab581b89bae6d665a3d2d44c442..117ed3a9556260c71e0505009fed59c87aad70a6 100644 (file)
@@ -78,572 +78,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 +171,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)
@@ -2331,449 +1428,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 +2586,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 +2613,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 +2649,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;
+
 }