bgpd, zebra: Use next hop tracking for connected routes too

Allow next hop tracking to work with connected routes
And cleanup obsolete code in bgp_scan and bgp_import.

Signed-off-by: Dinesh Dutt <ddutt@cumulusnetworks.com>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Edits: Paul Jakma <paul.jakma@hpe.com> Rebase re-ordering conflicts with
       NHT route-map, potential errors.
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 21e1411..34b5fd1 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -39,6 +39,7 @@
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_fsm.h"
 
 extern struct zclient *zclient;
 extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
@@ -51,19 +52,15 @@
 			int keep);
 
 int
-bgp_find_nexthop (struct bgp_info *path, int *changed, int *metricchanged)
+bgp_find_nexthop (struct bgp_info *path, int connected)
 {
   struct bgp_nexthop_cache *bnc = path->nexthop;
 
   if (!bnc)
     return 0;
 
-  if (changed)
-    *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
-
-  if (metricchanged)
-    *metricchanged = CHECK_FLAG(bnc->change_flags,
-				BGP_NEXTHOP_METRIC_CHANGED);
+  if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
+    return 0;
 
   return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
 }
@@ -78,7 +75,7 @@
 
   path_nh_map(path, NULL, 0);
 
-  if (LIST_EMPTY(&(bnc->paths)))
+  if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
     {
       if (BGP_DEBUG(nht, NHT))
 	{
@@ -94,15 +91,34 @@
 }
 
 int
-bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed,
-			 int *metricchanged)
+bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer,
+			 int connected)
 {
   struct bgp_node *rn;
   struct bgp_nexthop_cache *bnc;
   struct prefix p;
 
-  if (make_prefix(afi, ri, &p) < 0)
-    return 1;
+  if (ri)
+    {
+      if (make_prefix(afi, ri, &p) < 0)
+	return 1;
+    }
+  else if (peer)
+    {
+      if (afi == AFI_IP)
+	{
+	  p.family = AF_INET;
+	  p.prefixlen = IPV4_MAX_BITLEN;
+	  p.u.prefix4 = peer->su.sin.sin_addr;
+	}
+      else if (afi == AFI_IP6)
+	{
+	  p.family = AF_INET6;
+	  p.prefixlen = IPV6_MAX_BITLEN;
+	  p.u.prefix6 = peer->su.sin6.sin6_addr;
+	}
+    }
+
   rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
 
   if (!rn->info)
@@ -111,23 +127,27 @@
       rn->info = bnc;
       bnc->node = rn;
       bgp_lock_node(rn);
-      register_nexthop(bnc);
+      if (connected)
+	SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
     }
+
   bnc = rn->info;
   bgp_unlock_node (rn);
-  path_nh_map(ri, bnc, 1);
 
-  if (changed)
-    *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
+  if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+    register_nexthop(bnc);
 
-  if (metricchanged)
-    *metricchanged = CHECK_FLAG(bnc->change_flags,
-				BGP_NEXTHOP_METRIC_CHANGED);
+  if (ri)
+    {
+      path_nh_map(ri, bnc, 1);
 
-  if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
-    (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
-  else if (ri->extra)
-    ri->extra->igpmetric = 0;
+      if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
+	(bgp_info_extra_get(ri))->igpmetric = bnc->metric;
+      else if (ri->extra)
+	ri->extra->igpmetric = 0;
+    }
+  else if (peer)
+    bnc->nht_info = (void *)peer;
 
   return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
 }
@@ -269,6 +289,7 @@
   else
     {
       bnc->flags &= ~BGP_NEXTHOP_VALID;
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
       bnc_nexthop_free(bnc);
       bnc->nexthop = NULL;
     }
@@ -326,12 +347,21 @@
 
   /* Check socket. */
   if (!zclient || zclient->sock < 0)
-    return;
+    {
+      zlog_debug("%s: Can't send NH register, Zebra client not established",
+		 __FUNCTION__);
+      return;
+    }
 
   p = &(bnc->node->p);
   s = zclient->obuf;
   stream_reset (s);
   zclient_create_header (s, command, VRF_DEFAULT);
+  if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+    stream_putc(s, 1);
+  else
+    stream_putc(s, 0);
+
   stream_putw(s, PREFIX_FAMILY(p));
   stream_putc(s, p->prefixlen);
   switch (PREFIX_FAMILY(p))
@@ -339,11 +369,9 @@
     case AF_INET:
       stream_put_in_addr (s, &p->u.prefix4);
       break;
-#ifdef HAVE_IPV6
     case AF_INET6:
       stream_put(s, &(p->u.prefix6), 16);
       break;
-#endif
     default:
       break;
     }
@@ -353,6 +381,11 @@
   /* TBD: handle the failure */
   if (ret < 0)
     zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
+
+  if (command == ZEBRA_NEXTHOP_REGISTER)
+    SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+  else if (command == ZEBRA_NEXTHOP_UNREGISTER)
+    UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
   return;
 }
 
@@ -371,7 +404,6 @@
   if (bnc->flags & BGP_NEXTHOP_REGISTERED)
     return;
   sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
-  SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
 }
 
 /**
@@ -389,7 +421,6 @@
     return;
 
   sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
-  UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
 }
 
 /**
@@ -406,6 +437,7 @@
   struct bgp_info *path;
   struct bgp *bgp = bgp_get_default();
   int afi;
+  struct peer *peer = (struct peer *)bnc->nht_info;
 
   LIST_FOREACH(path, &(bnc->paths), nh_thread)
     {
@@ -448,6 +480,15 @@
 
       bgp_process(bgp, rn, afi, SAFI_UNICAST);
     }
+
+  if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
+    {
+      if (BGP_DEBUG(nht, NHT))
+	zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
+      bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+      SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+    }
+
   RESET_FLAG(bnc->change_flags);
 }