]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_rnh.c
zebra: delay default vrf name after vrf initialization
[mirror_frr.git] / zebra / zebra_rnh.c
index d482e0ab3da3ec1d796c304e3eaddf9eb031022d..f57bf7984a54d4b2ddc182a4c024d24b105d924c 100644 (file)
@@ -36,6 +36,7 @@
 #include "nexthop.h"
 #include "vrf.h"
 
+#include "zebra/zebra_router.h"
 #include "zebra/rib.h"
 #include "zebra/rt.h"
 #include "zebra/zserv.h"
@@ -47,6 +48,7 @@
 #include "zebra/zebra_routemap.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_memory.h"
+#include "zebra/zebra_errors.h"
 
 static void free_state(vrf_id_t vrf_id, struct route_entry *re,
                       struct route_node *rn);
@@ -102,7 +104,8 @@ char *rnh_str(struct rnh *rnh, char *buf, int size)
        return buf;
 }
 
-struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
+struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
+                         bool *exists)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -116,8 +119,10 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
        table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
        if (!table) {
                prefix2str(p, buf, sizeof(buf));
-               zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
+               flog_warn(EC_ZEBRA_RNH_NO_TABLE,
+                         "%u: Add RNH %s type %d - table not found", vrfid,
                          buf, type);
+               exists = false;
                return NULL;
        }
 
@@ -131,12 +136,13 @@ 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;
                rnh->node = rn;
-       }
+               *exists = false;
+       } else
+               *exists = true;
 
        route_unlock_node(rn);
        return (rn->info);
@@ -166,9 +172,8 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
 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);
+       list_delete(&rnh->client_list);
+       list_delete(&rnh->zebra_pseudowire_list);
        free_state(rnh->vrf_id, rnh->state, rnh->node);
        XFREE(MTYPE_RNH, rnh);
 }
@@ -191,6 +196,14 @@ void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
        route_unlock_node(rn);
 }
 
+/*
+ * This code will send to the registering client
+ * the looked up rnh.
+ * For a rnh that was created, there is no data
+ * so it will send an empty nexthop group
+ * If rnh exists then we know it has been evaluated
+ * and as such it will have a resolved rnh.
+ */
 void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
                          rnh_type_t type, vrf_id_t vrf_id)
 {
@@ -202,8 +215,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
        }
        if (!listnode_lookup(rnh->client_list, client)) {
                listnode_add(rnh->client_list, client);
-               send_client(rnh, client, type,
-                           vrf_id); // Pending: check if its needed
+               send_client(rnh, client, type, vrf_id);
        }
 }
 
@@ -218,82 +230,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)
@@ -311,7 +251,7 @@ static void addr2hostprefix(int af, const union g_addr *addr,
                break;
        default:
                memset(prefix, 0, sizeof(*prefix));
-               zlog_warn("%s: unknown address family %d", __func__, af);
+               zlog_debug("%s: unknown address family %d", __func__, af);
                break;
        }
 }
@@ -320,13 +260,19 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
 {
        struct prefix nh;
        struct rnh *rnh;
+       bool exists;
+       struct zebra_vrf *zvrf;
+
+       zvrf = vrf_info_lookup(vrf_id);
+       if (!zvrf)
+               return;
 
        addr2hostprefix(pw->af, &pw->nexthop, &nh);
-       rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
+       rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists);
        if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
                listnode_add(rnh->zebra_pseudowire_list, pw);
                pw->rnh = rnh;
-               zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
+               zebra_evaluate_rnh(zvrf, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
        }
 }
 
@@ -342,7 +288,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);
 }
@@ -350,7 +295,8 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
 /* Apply the NHT route-map for a client to the route (and nexthops)
  * resolving a NH.
  */
-static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
+static int zebra_rnh_apply_nht_rmap(int family, struct zebra_vrf *zvrf,
+                                   struct route_node *prn,
                                    struct route_entry *re, int proto)
 {
        int at_least_one = 0;
@@ -363,8 +309,8 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
        if (prn && re) {
                for (nexthop = re->ng.nexthop; nexthop;
                     nexthop = nexthop->next) {
-                       ret = zebra_nht_route_map_check(rmap_family, proto,
-                                                       &prn->p, re, nexthop);
+                       ret = zebra_nht_route_map_check(
+                               rmap_family, proto, &prn->p, zvrf, re, nexthop);
                        if (ret != RMAP_DENYMATCH) {
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                                at_least_one++; /* at least one valid NH */
@@ -381,7 +327,7 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
  * for BGP route for import.
  */
 static struct route_entry *
-zebra_rnh_resolve_import_entry(vrf_id_t vrfid, int family,
+zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, int family,
                               struct route_node *nrn, struct rnh *rnh,
                               struct route_node **prn)
 {
@@ -391,7 +337,7 @@ zebra_rnh_resolve_import_entry(vrf_id_t vrfid, int family,
 
        *prn = NULL;
 
-       route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
+       route_table = zvrf->table[family2afi(family)][SAFI_UNICAST];
        if (!route_table) // unexpected
                return NULL;
 
@@ -463,11 +409,9 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family,
 /*
  * Notify clients registered for this nexthop about a change.
  */
-static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
-                                             struct route_node *nrn,
-                                             struct rnh *rnh,
-                                             struct route_node *prn,
-                                             struct route_entry *re)
+static void zebra_rnh_notify_protocol_clients(
+       struct zebra_vrf *zvrf, int family, struct route_node *nrn,
+       struct rnh *rnh, struct route_node *prn, struct route_entry *re)
 {
        struct listnode *node;
        struct zserv *client;
@@ -479,11 +423,11 @@ static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
                prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
                if (prn && re) {
                        prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
-                       zlog_debug("%u:%s: NH resolved over route %s", vrfid,
-                                  bufn, bufp);
+                       zlog_debug("%u:%s: NH resolved over route %s",
+                                  zvrf->vrf->vrf_id, bufn, bufp);
                } else
-                       zlog_debug("%u:%s: NH has become unresolved", vrfid,
-                                  bufn);
+                       zlog_debug("%u:%s: NH has become unresolved",
+                                  zvrf->vrf->vrf_id, bufn);
        }
 
        for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
@@ -493,7 +437,7 @@ static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
                         * nexthop to see if it is filtered or not.
                         */
                        num_resolving_nh = zebra_rnh_apply_nht_rmap(
-                               family, prn, re, client->proto);
+                               family, zvrf, prn, re, client->proto);
                        if (num_resolving_nh)
                                rnh->filtered[client->proto] = 0;
                        else
@@ -502,7 +446,7 @@ static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
                        if (IS_ZEBRA_DEBUG_NHT)
                                zlog_debug(
                                        "%u:%s: Notifying client %s about NH %s",
-                                       vrfid, bufn,
+                                       zvrf->vrf->vrf_id, bufn,
                                        zebra_route_string(client->proto),
                                        num_resolving_nh
                                                ? ""
@@ -512,11 +456,11 @@ static void zebra_rnh_notify_protocol_clients(vrf_id_t vrfid, int family,
                        if (IS_ZEBRA_DEBUG_NHT)
                                zlog_debug(
                                        "%u:%s: Notifying client %s about NH (unreachable)",
-                                       vrfid, bufn,
+                                       zvrf->vrf->vrf_id, bufn,
                                        zebra_route_string(client->proto));
                }
 
-               send_client(rnh, client, RNH_NEXTHOP_TYPE, vrfid);
+               send_client(rnh, client, RNH_NEXTHOP_TYPE, zvrf->vrf->vrf_id);
        }
 }
 
@@ -526,12 +470,11 @@ static void zebra_rnh_process_pbr_tables(int family,
                                         struct route_node *prn,
                                         struct route_entry *re)
 {
-       struct zebra_ns_table *znst;
+       struct zebra_router_table *zrt;
        struct route_entry *o_re;
        struct route_node *o_rn;
        struct listnode *node;
        struct zserv *client;
-       struct zebra_ns *zns;
        afi_t afi = AFI_IP;
 
        if (family == AF_INET6)
@@ -549,13 +492,12 @@ static void zebra_rnh_process_pbr_tables(int family,
        if (!client)
                return;
 
-       zns = zebra_ns_lookup(NS_DEFAULT);
-       RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) {
-               if (afi != znst->afi)
+       RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+               if (afi != zrt->afi)
                        continue;
 
-               for (o_rn = route_top(znst->table);
-                    o_rn; o_rn = srcdest_route_next(o_rn)) {
+               for (o_rn = route_top(zrt->table); o_rn;
+                    o_rn = srcdest_route_next(o_rn)) {
                        RNODE_FOREACH_RE (o_rn, o_re) {
                                if (o_re->type == ZEBRA_ROUTE_PBR)
                                        break;
@@ -575,113 +517,16 @@ 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)
+/*
+ * Utility to determine whether a candidate nexthop is useable. We make this
+ * check in a couple of places, so this is a single home for the logic we
+ * use.
+ */
+static bool rnh_nexthop_valid(const struct nexthop *nh)
 {
-       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);
-       }
+       return ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+                || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+               && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
 }
 
 /*
@@ -689,17 +534,18 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
  * nexthop.
  */
 static struct route_entry *
-zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family,
+zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family,
                                struct route_node *nrn, struct rnh *rnh,
                                struct route_node **prn)
 {
        struct route_table *route_table;
        struct route_node *rn;
        struct route_entry *re;
+       struct nexthop *nexthop;
 
        *prn = NULL;
 
-       route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
+       route_table = zvrf->table[family2afi(family)][SAFI_UNICAST];
        if (!route_table)
                return NULL;
 
@@ -728,12 +574,23 @@ zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family,
                        if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
                                continue;
 
+                       /* Just being SELECTED isn't quite enough - must
+                        * have an installed nexthop to be useful.
+                        */
+                       for (nexthop = re->ng.nexthop; nexthop;
+                            nexthop = nexthop->next) {
+                               if (rnh_nexthop_valid(nexthop))
+                                       break;
+                       }
+
+                       if (nexthop == NULL)
+                               continue;
+
                        if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
                                if ((re->type == ZEBRA_ROUTE_CONNECT)
                                    || (re->type == ZEBRA_ROUTE_STATIC))
                                        break;
                                if (re->type == ZEBRA_ROUTE_NHRP) {
-                                       struct nexthop *nexthop;
 
                                        for (nexthop = re->ng.nexthop; nexthop;
                                             nexthop = nexthop->next)
@@ -776,8 +633,8 @@ static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
  * take appropriate action; this involves notifying any clients and/or
  * scheduling dependent static routes for processing.
  */
-static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
-                                        struct route_node *nrn,
+static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, int family,
+                                        int force, struct route_node *nrn,
                                         struct rnh *rnh,
                                         struct route_node *prn,
                                         struct route_entry *re)
@@ -806,24 +663,20 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
                 * rnh->state.
                 */
                /* Notify registered protocol clients. */
-               zebra_rnh_notify_protocol_clients(vrfid, family, nrn, rnh, prn,
+               zebra_rnh_notify_protocol_clients(zvrf, 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);
+               zebra_rnh_process_pbr_tables(family, nrn, rnh, prn, rnh->state);
 
                /* Process pseudowires attached to this nexthop */
-               zebra_rnh_process_pseudowires(vrfid, rnh);
+               zebra_rnh_process_pseudowires(zvrf->vrf->vrf_id, rnh);
        }
 }
 
 /* Evaluate one tracked entry */
-static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
-                                    rnh_type_t type, struct route_node *nrn)
+static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, int family,
+                                    int force, rnh_type_t type,
+                                    struct route_node *nrn)
 {
        struct rnh *rnh;
        struct route_entry *re;
@@ -832,18 +685,18 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
 
        if (IS_ZEBRA_DEBUG_NHT) {
                prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
-               zlog_debug("%u:%s: Evaluate RNH, type %d %s", vrfid, bufn, type,
-                          force ? "(force)" : "");
+               zlog_debug("%u:%s: Evaluate RNH, type %d %s", zvrf->vrf->vrf_id,
+                          bufn, type, force ? "(force)" : "");
        }
 
        rnh = nrn->info;
 
        /* Identify route entry (RE) resolving this tracked entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
+               re = zebra_rnh_resolve_import_entry(zvrf, family, nrn, rnh,
                                                    &prn);
        else
-               re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
+               re = zebra_rnh_resolve_nexthop_entry(zvrf, family, nrn, rnh,
                                                     &prn);
 
        /* If the entry cannot be resolved and that is also the existing state,
@@ -854,11 +707,11 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
 
        /* Process based on type of entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               zebra_rnh_eval_import_check_entry(vrfid, family, force, nrn,
-                                                 rnh, re);
+               zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, family,
+                                                 force, nrn, rnh, re);
        else
-               zebra_rnh_eval_nexthop_entry(vrfid, family, force, nrn, rnh,
-                                            prn, re);
+               zebra_rnh_eval_nexthop_entry(zvrf, family, force, nrn, rnh, prn,
+                                            re);
 }
 
 /*
@@ -870,7 +723,7 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
  * we can have a situation where one re entry
  * covers multiple nexthops we are interested in.
  */
-static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
+static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, int family,
                                     rnh_type_t type, struct route_node *nrn)
 {
        struct rnh *rnh;
@@ -881,10 +734,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
 
        /* Identify route entry (RIB) resolving this tracked entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, rnh,
+               re = zebra_rnh_resolve_import_entry(zvrf, family, nrn, rnh,
                                                    &prn);
        else
-               re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
+               re = zebra_rnh_resolve_nexthop_entry(zvrf, family, nrn, rnh,
                                                     &prn);
 
        if (re) {
@@ -896,13 +749,13 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
 /* Evaluate all tracked entries (nexthops or routes for import into BGP)
  * of a particular VRF and address-family or a specific prefix.
  */
-void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type,
-                       struct prefix *p)
+void zebra_evaluate_rnh(struct zebra_vrf *zvrf, int family, int force,
+                       rnh_type_t type, struct prefix *p)
 {
        struct route_table *rnh_table;
        struct route_node *nrn;
 
-       rnh_table = get_rnh_table(vrfid, family, type);
+       rnh_table = get_rnh_table(zvrf->vrf->vrf_id, family, type);
        if (!rnh_table) // unexpected
                return;
 
@@ -910,7 +763,7 @@ void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type,
                /* Evaluating a specific entry, make sure it exists. */
                nrn = route_node_lookup(rnh_table, p);
                if (nrn && nrn->info)
-                       zebra_rnh_evaluate_entry(vrfid, family, force, type,
+                       zebra_rnh_evaluate_entry(zvrf, family, force, type,
                                                 nrn);
 
                if (nrn)
@@ -920,14 +773,14 @@ void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type,
                nrn = route_top(rnh_table);
                while (nrn) {
                        if (nrn->info)
-                               zebra_rnh_evaluate_entry(vrfid, family, force,
+                               zebra_rnh_evaluate_entry(zvrf, family, force,
                                                         type, nrn);
                        nrn = route_next(nrn); /* this will also unlock nrn */
                }
                nrn = route_top(rnh_table);
                while (nrn) {
                        if (nrn->info)
-                               zebra_rnh_clear_nhc_flag(vrfid, family, type,
+                               zebra_rnh_clear_nhc_flag(zvrf, family, type,
                                                         nrn);
                        nrn = route_next(nrn); /* this will also unlock nrn */
                }
@@ -962,7 +815,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);
 }
@@ -1046,7 +898,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
                break;
        default:
-               zlog_err("%s: Unknown family (%d) notification attempted\n",
+               flog_err(EC_ZEBRA_RNH_UNKNOWN_FAMILY,
+                        "%s: Unknown family (%d) notification attempted\n",
                         __FUNCTION__, rn->p.family);
                break;
        }
@@ -1059,9 +912,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                nump = stream_get_endp(s);
                stream_putc(s, 0);
                for (nh = re->ng.nexthop; nh; nh = nh->next)
-                       if ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
-                            || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
-                           && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) {
+                       if (rnh_nexthop_valid(nh)) {
+                               stream_putl(s, nh->vrf_id);
                                stream_putc(s, nh->type);
                                switch (nh->type) {
                                case NEXTHOP_TYPE_IPV4:
@@ -1173,9 +1025,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");