--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -244,20 +244,189 @@
 	return 0;
 }
 
-int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
-			   union sockunion *via, struct interface **ifp)
+static int nhrp_route_check_nexthop(const union sockunion *addr,
+		struct route_info *ri, 	struct interface *nifp,
+		struct interface *ifp)
 {
-	struct route_node *rn;
-	struct route_info *ri;
+	ifindex_t network_id = IFINDEX_INTERNAL;
 	struct prefix lookup;
-	afi_t afi = family2afi(sockunion_family(addr));
+
+	if (!addr)
+		return -1;
 
 	sockunion2hostprefix(addr, &lookup);
 
-	rn = route_node_match(zebra_rib[afi], &lookup);
-	if (!rn)
-		return 0;
+	if (!ri)
+		return -1;
+
+	if (nifp)
+		network_id = nifp->ifindex;
+
+	if (ri->nhrp_ifp) {
+		debugf(NHRP_DEBUG_ROUTE, "recursive check %pFX: nexthop_nhrp_if=%s nhrp_if=%s",
+				&lookup,
+		       ri->nhrp_ifp->name, network_id ?
+		       nifp->name : "(unspec)" );
+		if (network_id && (ri->nhrp_ifp->ifindex == network_id))
+			return -1;
+		return 1;
+	}
+
+
+	network_id = IFINDEX_INTERNAL;
+
+	if (ri->ifp) {
+		if (ifp) {
+			network_id = ifp->ifindex;
+			debugf(NHRP_DEBUG_ROUTE, "recursive check %pFX: "
+				"zebra route dev %s nhrp_if=%s",
+				&lookup,
+			       ri->ifp->name, nifp ?
+			       nifp->name : "(unspec)");
+			if (ri->ifp->ifindex == network_id)
+				return -1;
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static int __prefix_matcher_maxlen(void *data, const struct prefix *p1, const struct prefix *p2)
+{
+	int maxlen;
+
+	if (data) {
+		maxlen = *(int *)data;
+		return prefix_match_length_max(maxlen, p1, p2);
+	} else
+		return prefix_match(p1, p2);
+}
+
+/* recurse a route until we find a valid interface, nhrp or otherwise */
+static struct route_node * nhrp_route_recurse_nexthop_int(
+		const union sockunion *addr, struct prefix *p,
+		union sockunion *via, struct interface **ifp,
+		struct nhrp_interface **nifp, int *max, struct prefix *rp)
+{
+
+	struct route_node *rn = NULL;
+	struct route_info *ri = NULL;
+	struct prefix *lookup;
+	unsigned int lookuplen;
+	int chk = 0;
+	struct interface *lnifp = NULL;
+	struct interface *lifp = NULL;
+	char buf[PREFIX_STRLEN];
+	int tablecnt = 0;
+	int i;
+	afi_t afi = family2afi(sockunion_family(addr));
+
+
+	if (!max || (*max) < 1 || !rp)
+		return NULL;
 
+	for (i = 0 ; rp[i].family; i++);
+	lookup = &rp[i];
+	sockunion2hostprefix(addr, lookup);
+	lookuplen = lookup->prefixlen;
+
+	while( i-- > 0) {
+		if (prefix_match(lookup, &rp[i]))
+		{
+			memset(&rp[i], 0, sizeof(rp[0]));
+			return NULL;
+		}
+	}
+
+	if (ifp && *ifp)
+		lifp = (*ifp);
+
+	if (nifp) {
+		if (*nifp)
+			lnifp = (*nifp)->ifp;
+		else if (lifp)
+			lnifp = lifp->info;
+	}
+
+	rn = route_node_match(zebra_rib[afi], lookup);
+	tablecnt = (zebra_rib[afi]) ? zebra_rib[afi]->count : 0;
+	while(rn && ((*max) > 0)) {
+		(*max)--;
+		debugf(NHRP_DEBUG_ROUTE, "recursive lookup %pFX: left %d tablecnt %d",
+		       	&lookup, *max, tablecnt);
+
+		if (!(ri = rn->info))
+			break;
+		if ((chk = nhrp_route_check_nexthop(&(ri->via), ri, lnifp, lifp)) == 1)
+			break;
+		if (chk < 0)
+			break;
+		route_unlock_node(rn);
+		rn = nhrp_route_recurse_nexthop_int(&(ri->via), p, via, ifp, nifp, max, rp);
+		if ((*max) < 1)
+			break;
+		while (!rn && (*max) && lookuplen) {
+			(*max)--;
+			lookuplen--;
+#if 1
+			debugf(NHRP_DEBUG_ROUTE, "file %s func %s line %d: ifp %p",
+					__FILE__, __func__, __LINE__, ifp);
+#endif
+			rn = route_node_match_fun(zebra_rib[afi], lookup, &__prefix_matcher_maxlen, &lookuplen);
+			if (rn) {
+			       if (rn->info != ri)
+					break;
+				route_unlock_node(rn);
+				rn = NULL;
+			}
+		}
+	}
+
+	if (!rn || (*max) < 1)
+	 	return rn;
+
+	if (chk < 1 && rn) {
+		route_unlock_node(rn);
+		rn = NULL;
+		return rn;
+	}
+	else
+		(*max) = 0;
+
+	if (ri) {
+
+		if (ri->ifp && ifp)
+			*ifp = ri->ifp;
+		if (ri->nhrp_ifp && nifp && *nifp)
+			 (*nifp)->ifp = ri->nhrp_ifp;
+		if (via) {
+			*via = ri->via;
+			if (p)
+				sockunion2hostprefix(via, p);
+		}
+	}
+	return rn;
+}
+
+int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
+			   union sockunion *via, struct interface **ifp,
+			   struct nhrp_interface **nifp)
+{
+ 	struct route_node *rn;
+	struct route_info *ri;
+	struct prefix lookup;
+	afi_t afi = family2afi(sockunion_family(addr));
+	char buf[PREFIX_STRLEN];
+	int recurse_max = 100;
+	struct prefix rp[100];
+
+ 	sockunion2hostprefix(addr, &lookup);
+	memset(rp, 0, sizeof(rp));
+	rn = nhrp_route_recurse_nexthop_int(addr, &lookup, via, ifp, nifp, &recurse_max, rp);
+ 	if (!rn)
+ 		rn = route_node_match(zebra_rib[afi], &lookup);
+ 	if (!rn)
+ 		return 0;
 	ri = rn->info;
 	if (ri->nhrp_ifp) {
 		debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: nhrp_if=%s", &lookup,
@@ -307,7 +476,8 @@
 	}
 
 	for (i = 0; i < 4; i++) {
-		if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp))
+
+		if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp, &nifp))
 			return NHRP_ROUTE_BLACKHOLE;
 		if (ifp) {
 			/* Departing from nbma network? */
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -351,7 +351,8 @@
 			 const union sockunion *nexthop, uint32_t mtu);
 int nhrp_route_read(ZAPI_CALLBACK_ARGS);
 int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
-			   union sockunion *via, struct interface **ifp);
+			   union sockunion *via, struct interface **ifp,
+			   struct nhrp_interface **nifp);
 enum nhrp_route_type nhrp_route_address(struct interface *in_ifp,
 					union sockunion *addr, struct prefix *p,
 					struct nhrp_peer **peer);
--- a/lib/table.h
+++ b/lib/table.h
@@ -214,6 +214,12 @@
 						      union prefixconstptr pu);
 ext_pure struct route_node *route_node_match(struct route_table *table,
 					     union prefixconstptr pu);
+ext_pure struct route_node *route_node_match_fun(struct route_table *table,
+					     union prefixconstptr pu,
+					     int (*matcher_fun) (void *data,
+						     const struct prefix * p1,
+						     const struct prefix * p2),
+					     void *data);
 ext_pure struct route_node *route_node_match_ipv4(struct route_table *table,
 						  const struct in_addr *addr);
 ext_pure struct route_node *route_node_match_ipv6(struct route_table *table,
--- a/lib/table.c
+++ b/lib/table.c
@@ -223,6 +223,45 @@
 	return NULL;
 }
 
+struct route_node *route_node_match_fun(struct route_table *table,
+				    union prefixconstptr pu,
+				    int(*matcher_fun)
+				    (void *data,
+				     const struct prefix *p1,
+				     const struct prefix *p2),
+				    void *data)
+{
+	const struct prefix *p = pu.p;
+	struct route_node *node;
+	struct route_node *matched;
+
+	if (!matcher_fun)
+		return route_node_match(table, pu);
+
+	matched = NULL;
+	node = table->top;
+
+	/* Walk down tree.  If there is matched route then store it to
+	   matched. */
+	while (node && node->p.prefixlen <= p->prefixlen
+	       && matcher_fun(data, &node->p, p)) {
+		if (node->info)
+			matched = node;
+
+		if (node->p.prefixlen == p->prefixlen)
+			break;
+
+		node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
+	}
+
+	/* If matched route found, return it. */
+	if (matched)
+		return route_lock_node(matched);
+
+	return NULL;
+}
+
+
 struct route_node *route_node_match_ipv4(struct route_table *table,
 					 const struct in_addr *addr)
 {
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -179,6 +179,24 @@
 /* If n includes p prefix then return 1 else return 0. */
 int prefix_match(const struct prefix *n, const struct prefix *p)
 {
+	return prefix_match_length(-1, -1, n, p);
+}
+
+int prefix_match_length_min(int min_len,
+	const struct prefix *n, const struct prefix *p)
+{
+	return prefix_match_length(-1, min_len, n, p);
+}
+
+int prefix_match_length_max(int max_len,
+	const struct prefix *n, const struct prefix *p)
+{
+	return prefix_match_length(max_len, -1, n, p);
+}
+
+int prefix_match_length(int max_len, int min_len,
+	const struct prefix *n, const struct prefix *p)
+{
 	int offset;
 	int shift;
 	const uint8_t *np, *pp;
@@ -187,6 +205,13 @@
 	if (n->prefixlen > p->prefixlen)
 		return 0;
 
+	/* We may not want to match prefixes of any length */
+	if (max_len > 0 && n->prefixlen > max_len)
+		return 0;
+	if (min_len > 0 && n->prefixlen < min_len)
+		return 0;
+
+
 	if (n->family == AF_FLOWSPEC) {
 		/* prefixlen is unused. look at fs prefix len */
 		if (n->u.prefix_flowspec.family !=
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -449,6 +449,10 @@
 extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx,
 				   const struct prefix *match_pfx);
 extern int prefix_match(const struct prefix *, const struct prefix *);
+extern int prefix_match_length_min(int, const struct prefix *, const struct prefix *);
+extern int prefix_match_length_max(int, const struct prefix *, const struct prefix *);
+extern int prefix_match_length(int, int, const struct prefix *, const struct prefix *);
+
 extern int prefix_match_network_statement(const struct prefix *,
 					  const struct prefix *);
 extern int prefix_same(union prefixconstptr, union prefixconstptr);
