]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd-nht-import-check-fix.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:04:20 +0000 (18:04 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:04:20 +0000 (18:04 -0700)
BGP: Fix network import check use with NHT instead of scanner

When next hop tracking was implemented and the bgp scanner was eliminated,
the "network import-check" command got broken. This patch fixes that
issue. NHT is used to not just track nexthops, but also the static routes
that are announced as part of BGP's network command. The routes are
registered only when import-check is enabled. To optimize performance,
we register static routes only when import-check is enabled.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
22 files changed:
bgpd/bgp_nexthop.c
bgpd/bgp_nexthop.h
bgpd/bgp_nht.c
bgpd/bgp_nht.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/log.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_rnh_null.c
zebra/zebra_routemap.c
zebra/zebra_vty.c
zebra/zserv.c

index 850ea91e99fb78bcf6cb13b5c15e85cd06824a3e..cdbc5cc38478e37972f7502238d044bb1909f305 100644 (file)
@@ -48,11 +48,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 /* Route table for next-hop lookup cache. */
 struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
-static struct bgp_table *cache1_table[AFI_MAX];
 
 /* Route table for connected route. */
 static struct bgp_table *bgp_connected_table[AFI_MAX];
 
+/* Route table for import-check */
+struct bgp_table *bgp_import_check_table[AFI_MAX];
 
 char *
 bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size)
@@ -571,15 +572,14 @@ DEFUN (show_ip_bgp_nexthop_detail,
 void
 bgp_scan_init (void)
 {
-  cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
-  bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP];
-
+  bgp_nexthop_cache_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
   bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
+  bgp_import_check_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
 
 #ifdef HAVE_IPV6
-  cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
-  bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6];
+  bgp_nexthop_cache_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
   bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
+  bgp_import_check_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
 #endif /* HAVE_IPV6 */
 
 }
@@ -599,20 +599,26 @@ bgp_scan_finish (void)
   /* Only the current one needs to be reset. */
   bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]);
 
-  bgp_table_unlock (cache1_table[AFI_IP]);
-  cache1_table[AFI_IP] = NULL;
+  bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP]);
+  bgp_nexthop_cache_table[AFI_IP] = NULL;
 
   bgp_table_unlock (bgp_connected_table[AFI_IP]);
   bgp_connected_table[AFI_IP] = NULL;
 
+  bgp_table_unlock (bgp_import_check_table[AFI_IP]);
+  bgp_import_check_table[AFI_IP] = NULL;
+
 #ifdef HAVE_IPV6
   /* Only the current one needs to be reset. */
   bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]);
 
-  bgp_table_unlock (cache1_table[AFI_IP6]);
-  cache1_table[AFI_IP6] = NULL;
+  bgp_table_unlock (bgp_nexthop_cache_table[AFI_IP6]);
+  bgp_nexthop_cache_table[AFI_IP6] = NULL;
 
   bgp_table_unlock (bgp_connected_table[AFI_IP6]);
   bgp_connected_table[AFI_IP6] = NULL;
+
+  bgp_table_unlock (bgp_import_check_table[AFI_IP6]);
+  bgp_import_check_table[AFI_IP6] = NULL;
 #endif /* HAVE_IPV6 */
 }
index cee967303f423f3aee4803ef6c344b469b9170d4..9c9f909625b9c7d28ce883d3ed175ebbeb299576 100644 (file)
@@ -41,6 +41,8 @@ struct bgp_nexthop_cache
 #define BGP_NEXTHOP_REGISTERED        (1 << 1)
 #define BGP_NEXTHOP_CONNECTED         (1 << 2)
 #define BGP_NEXTHOP_PEER_NOTIFIED     (1 << 3)
+#define BGP_STATIC_ROUTE              (1 << 4)
+#define BGP_STATIC_ROUTE_EXACT_MATCH  (1 << 5)
 
   u_int16_t change_flags;
 
index b76cf0248bcf212d0c884daaa429e09c28596d36..061746fc42b1c8aad1af2bb5a108ec48bd031572 100644 (file)
 
 extern struct zclient *zclient;
 extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
+extern struct bgp_table *bgp_import_check_table[AFI_MAX];
 
-static void register_nexthop(struct bgp_nexthop_cache *bnc);
-static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
+static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
+                          int is_bgp_static_route);
+static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
+                                int is_bgp_static_route);
 static void evaluate_paths(struct bgp_nexthop_cache *bnc);
 static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
 static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
@@ -81,7 +84,7 @@ bgp_unlink_nexthop (struct bgp_info *path)
          zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
                     bnc_str(bnc, buf, INET6_ADDRSTRLEN));
        }
-      unregister_nexthop(bnc);
+      unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
       bnc->node->info = NULL;
       bgp_unlock_node(bnc->node);
       bnc_free(bnc);
@@ -95,12 +98,15 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
   struct bgp_node *rn;
   struct bgp_nexthop_cache *bnc;
   struct prefix p;
+  int is_bgp_static_route = 0;
 
   if (ri)
     {
       /* This will return TRUE if the global IPv6 NH is a link local addr */
       if (make_prefix(afi, ri, &p) < 0)
        return 1;
+      is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
+                            (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
     }
   else if (peer)
     {
@@ -133,7 +139,10 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
   else
     return 0;
 
-  rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
+  if (is_bgp_static_route)
+    rn = bgp_node_get (bgp_import_check_table[afi], &p);
+  else
+    rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
 
   if (!rn->info)
     {
@@ -142,13 +151,11 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
       bnc->node = rn;
       bnc->bgp = bgp;
       bgp_lock_node(rn);
-      if (connected)
-       SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
       if (BGP_DEBUG(nht, NHT))
         {
           char buf[INET6_ADDRSTRLEN];
 
-          zlog_debug("Allocated bnc %s peer %p",
+           zlog_debug("Allocated bnc %s peer %p",
                      bnc_str(bnc, buf, INET6_ADDRSTRLEN), peer);
         }
     }
@@ -156,8 +163,41 @@ bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
   bnc = rn->info;
   bgp_unlock_node (rn);
 
+  if (is_bgp_static_route)
+    {
+      SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
+
+      /* If we're toggling the type, re-register */
+      if ((bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) &&
+         !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
+       {
+         SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
+         UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+         UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+       }
+      else if ((!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH)) &&
+              CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
+       {
+         UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
+         UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+         UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+       }
+    }
+  else if (connected && ! CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+    {
+      SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+    }
+  else if (!connected && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+    {
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+      UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+    }
+
   if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
-    register_nexthop(bnc);
+    register_zebra_rnh(bnc, is_bgp_static_route);
 
   if (ri)
     {
@@ -231,7 +271,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer)
       if (BGP_DEBUG(nht, NHT))
         zlog_debug("Freeing connected NHT node %p for peer %s",
                     bnc,  peer->host);
-      unregister_nexthop(bnc);
+      unregister_zebra_rnh(bnc, 0);
       bnc->node->info = NULL;
       bgp_unlock_node(bnc->node);
       bnc_free(bnc);
@@ -239,7 +279,7 @@ bgp_delete_connected_nexthop (afi_t afi, struct peer *peer)
 }
 
 void
-bgp_parse_nexthop_update (void)
+bgp_parse_nexthop_update (int command)
 {
   struct stream *s;
   struct bgp_node *rn;
@@ -270,7 +310,11 @@ bgp_parse_nexthop_update (void)
       break;
     }
 
-  rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
+  if (command == ZEBRA_NEXTHOP_UPDATE)
+    rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
+  else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
+    rn = bgp_node_lookup(bgp_import_check_table[family2afi(p.family)], &p);
+
   if (!rn || !rn->info)
     {
       if (BGP_DEBUG(nht, NHT))
@@ -398,13 +442,25 @@ bgp_parse_nexthop_update (void)
 static int
 make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
 {
+
+  int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) &&
+                      (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
+
   memset (p, 0, sizeof (struct prefix));
   switch (afi)
     {
     case AFI_IP:
       p->family = AF_INET;
-      p->prefixlen = IPV4_MAX_BITLEN;
-      p->u.prefix4 = ri->attr->nexthop;
+      if (is_bgp_static)
+       {
+         p->u.prefix4 = ri->net->p.u.prefix4;
+         p->prefixlen = ri->net->p.prefixlen;
+       }
+      else
+       {
+         p->u.prefix4 = ri->attr->nexthop;
+         p->prefixlen = IPV4_MAX_BITLEN;
+       }
       break;
 #ifdef HAVE_IPV6
     case AFI_IP6:
@@ -414,8 +470,17 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
        return -1;
 
       p->family = AF_INET6;
-      p->prefixlen = IPV6_MAX_BITLEN;
-      p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
+
+      if (is_bgp_static)
+       {
+         p->u.prefix6 = ri->net->p.u.prefix6;
+         p->prefixlen = ri->net->p.prefixlen;
+       }
+      else
+       {
+         p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
+         p->prefixlen = IPV6_MAX_BITLEN;
+       }
       break;
 #endif
     default:
@@ -430,16 +495,16 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
 }
 
 /**
- * sendmsg_nexthop -- Format and send a nexthop register/Unregister
+ * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
  *   command to Zebra.
  * ARGUMENTS:
  *   struct bgp_nexthop_cache *bnc -- the nexthop structure.
- *   int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
+ *   int command -- command to send to zebra
  * RETURNS:
  *   void.
  */
 static void
-sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
+sendmsg_zebra_rnh (struct bgp_nexthop_cache *bnc, int command)
 {
   struct stream *s;
   struct prefix *p;
@@ -457,7 +522,8 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
   s = zclient->obuf;
   stream_reset (s);
   zclient_create_header (s, command);
-  if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+  if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) ||
+      CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
     stream_putc(s, 1);
   else
     stream_putc(s, 0);
@@ -484,45 +550,53 @@ sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
   if (ret < 0)
     zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
 
-  if (command == ZEBRA_NEXTHOP_REGISTER)
+  if ((command == ZEBRA_NEXTHOP_REGISTER) ||
+      (command == ZEBRA_IMPORT_ROUTE_REGISTER))
     SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
-  else if (command == ZEBRA_NEXTHOP_UNREGISTER)
+  else if ((command == ZEBRA_NEXTHOP_UNREGISTER) ||
+          (command == ZEBRA_IMPORT_ROUTE_UNREGISTER))
     UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
   return;
 }
 
 /**
- * register_nexthop - register a nexthop with Zebra for notification
- *    when the route to the nexthop changes.
+ * register_zebra_rnh - register a NH/route with Zebra for notification
+ *    when the route or the route to the nexthop changes.
  * ARGUMENTS:
- *   struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ *   struct bgp_nexthop_cache *bnc
  * RETURNS:
  *   void.
  */
 static void
-register_nexthop (struct bgp_nexthop_cache *bnc)
+register_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
 {
   /* Check if we have already registered */
   if (bnc->flags & BGP_NEXTHOP_REGISTERED)
     return;
-  sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
+  if (is_bgp_import_route)
+    sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER);
+  else
+    sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER);
 }
 
 /**
- * unregister_nexthop -- Unregister the nexthop from Zebra.
+ * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
  * ARGUMENTS:
- *   struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ *   struct bgp_nexthop_cache *bnc
  * RETURNS:
  *   void.
  */
 static void
-unregister_nexthop (struct bgp_nexthop_cache *bnc)
+unregister_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
 {
   /* Check if we have already registered */
   if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
     return;
 
-  sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
+  if (is_bgp_import_route)
+    sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER);
+  else
+    sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER);
 }
 
 /**
@@ -544,7 +618,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
   LIST_FOREACH(path, &(bnc->paths), nh_thread)
     {
       if (!(path->type == ZEBRA_ROUTE_BGP &&
-           path->sub_type == BGP_ROUTE_NORMAL))
+           (path->sub_type == BGP_ROUTE_NORMAL) ||
+           (path->sub_type == BGP_ROUTE_STATIC)))
        continue;
 
       rn = path->net;
index 963dd00f27c9be8077a0e72285c0579a74f7ba86..952268789f8c25f4b156176ca5a7f420838c3352 100644 (file)
@@ -25,7 +25,7 @@
 /**
  * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra.
  */
-extern void bgp_parse_nexthop_update();
+extern void bgp_parse_nexthop_update(int command);
 
 /**
  * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object
index b29d6ea884ec47fd065f06d2bb8b9cd58565283f..55c2f13927c58e655864c1726c093310e707187b 100644 (file)
@@ -4461,7 +4461,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
   if (ri)
        {
       if (attrhash_cmp (ri->attr, attr_new) &&
-         !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+         !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) &&
+         !bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS))
         {
           bgp_unlock_node (rn);
           bgp_attr_unintern (&attr_new);
@@ -4491,13 +4492,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
                  if (BGP_DEBUG(nht, NHT))
                    {
                      char buf1[INET6_ADDRSTRLEN];
-                     inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
-                               buf1, INET6_ADDRSTRLEN);
-                     zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+                     inet_ntop (p->family, &p->u.prefix, buf1,
+                                INET6_ADDRSTRLEN);
+                     zlog_debug("%s(%s): Route not in table, not advertising",
+                                __FUNCTION__, buf1);
                    }
                  bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
                }
            }
+         else
+           {
+             /* Delete the NHT structure if any, if we're toggling between
+              * enabling/disabling import check. We deregister the route
+              * from NHT to avoid overloading NHT and the process interaction
+              */
+             bgp_unlink_nexthop(ri);
+             bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
+           }
           /* Process change. */
           bgp_process (bgp, rn, afi, safi);
           bgp_unlock_node (rn);
@@ -4520,15 +4531,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
          if (BGP_DEBUG(nht, NHT))
            {
              char buf1[INET6_ADDRSTRLEN];
-             inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
-                       buf1, INET6_ADDRSTRLEN);
-             zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+             inet_ntop(p->family, &p->u.prefix, buf1,
+                       INET6_ADDRSTRLEN);
+             zlog_debug("%s(%s): Route not in table, not advertising", __FUNCTION__,
+                        buf1);
            }
          bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
        }
     }
   else
-    bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+    {
+      /* Delete the NHT structure if any, if we're toggling between
+       * enabling/disabling import check. We deregister the route
+       * from NHT to avoid overloading NHT and the process interaction
+       */
+      bgp_unlink_nexthop(new);
+      bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+    }
 
   /* Register new BGP information. */
   bgp_info_add (rn, new);
@@ -4608,7 +4627,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   if (ri)
     {
       if (attrhash_cmp (ri->attr, attr_new) &&
-         !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+         !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) &&
+         !bgp_flag_check(bgp, BGP_FLAG_FORCE_STATIC_PROCESS))
        {
          bgp_unlock_node (rn);
          bgp_attr_unintern (&attr_new);
@@ -4640,13 +4660,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
                  if (BGP_DEBUG(nht, NHT))
                    {
                      char buf1[INET6_ADDRSTRLEN];
-                     inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
-                               buf1, INET6_ADDRSTRLEN);
-                     zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+                     inet_ntop(p->family, &p->u.prefix, buf1,
+                               INET6_ADDRSTRLEN);
+                     zlog_debug("%s(%s): Route not in table, not advertising",
+                                __FUNCTION__, buf1);
                    }
                  bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
                }
            }
+         else
+           {
+             /* Delete the NHT structure if any, if we're toggling between
+              * enabling/disabling import check. We deregister the route
+              * from NHT to avoid overloading NHT and the process interaction
+              */
+             bgp_unlink_nexthop(ri);
+             bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
+           }
          /* Process change. */
          bgp_aggregate_increment (bgp, p, ri, afi, safi);
          bgp_process (bgp, rn, afi, safi);
@@ -4670,15 +4700,24 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
          if (BGP_DEBUG(nht, NHT))
            {
              char buf1[INET6_ADDRSTRLEN];
-             inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1,
+             inet_ntop(p->family, &p->u.prefix, buf1,
                        INET6_ADDRSTRLEN);
-             zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+             zlog_debug("%s(%s): Route not in table, not advertising",
+                        __FUNCTION__, buf1);
            }
          bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
        }
     }
   else
-    bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+    {
+      /* Delete the NHT structure if any, if we're toggling between
+       * enabling/disabling import check. We deregister the route
+       * from NHT to avoid overloading NHT and the process interaction
+       */
+      bgp_unlink_nexthop(new);
+
+      bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+    }
 
   /* Aggregate address increment. */
   bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -5005,6 +5044,29 @@ bgp_static_delete (struct bgp *bgp)
          }
 }
 
+void
+bgp_static_redo_import_check (struct bgp *bgp)
+{
+  afi_t afi;
+  safi_t safi;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_table *table;
+  struct bgp_static *bgp_static;
+
+  /* Use this flag to force reprocessing of the route */
+  bgp_flag_set(bgp, BGP_FLAG_FORCE_STATIC_PROCESS);
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
+       if (rn->info != NULL)
+         {
+           bgp_static = rn->info;
+           bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
+         }
+  bgp_flag_unset(bgp, BGP_FLAG_FORCE_STATIC_PROCESS);
+}
+
 int
 bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str,
                      const char *tag_str)
index d7714580513a0d3b3158cd71ee98f5183a825dd0..c15b824061193b705b3c6364a094955dffaefa80 100644 (file)
@@ -250,6 +250,7 @@ extern void bgp_redistribute_delete (struct prefix *, u_char, u_short);
 extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int, u_short);
 
 extern void bgp_static_delete (struct bgp *);
+extern void bgp_static_redo_import_check (struct bgp *);
 extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *,
                        afi_t, safi_t);
 extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);
index 7852371fc316778158ef022dfdeddacce16ae1ed..4152b8cd2ea60e322555908e44da15c3f247cfe2 100644 (file)
@@ -2114,21 +2114,45 @@ DEFUN (bgp_default_ipv4_unicast,
 /* "bgp import-check" configuration.  */
 DEFUN (bgp_network_import_check,
        bgp_network_import_check_cmd,
-       "bgp network import-check",
+       "bgp network import-check {exact}",
        "BGP specific commands\n"
        "BGP network command\n"
-       "Check BGP network route exists in IGP\n")
+       "Check BGP network route exists in IGP\n"
+       "Match route precisely")
 {
   struct bgp *bgp;
+  int trigger = 0;
 
   bgp = vty->index;
-  bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
+  if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK))
+    {
+      bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
+      trigger = 1;
+    }
+
+  if (argv[0] != NULL)
+    {
+      if (!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
+       {
+         bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
+         trigger = 1;
+       }
+    }
+  else if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
+    {
+      bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
+      trigger = 1;
+    }
+
+  if (trigger)
+    bgp_static_redo_import_check(bgp);
+
   return CMD_SUCCESS;
 }
 
 DEFUN (no_bgp_network_import_check,
        no_bgp_network_import_check_cmd,
-       "no bgp network import-check",
+       "no bgp network import-check {exact}",
        NO_STR
        "BGP specific commands\n"
        "BGP network command\n"
@@ -2137,7 +2161,12 @@ DEFUN (no_bgp_network_import_check,
   struct bgp *bgp;
 
   bgp = vty->index;
-  bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
+  if (bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK))
+    {
+      bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK);
+      bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH);
+      bgp_static_redo_import_check(bgp);
+    }
   return CMD_SUCCESS;
 }
 
index 16f61d03faa69e029dac8f1ac3756ad880419e13..2983024d579939760093b4cd60c0a80e6cf922d7 100644 (file)
@@ -119,7 +119,15 @@ static int
 bgp_read_nexthop_update (int command, struct zclient *zclient,
                         zebra_size_t length)
 {
-  bgp_parse_nexthop_update();
+  bgp_parse_nexthop_update(command);
+  return 0;
+}
+
+static int
+bgp_read_import_check_update(int command, struct zclient *zclient,
+                            zebra_size_t length)
+{
+  bgp_parse_nexthop_update(command);
   return 0;
 }
 
@@ -1665,6 +1673,7 @@ bgp_zebra_init (void)
   zclient->ipv6_route_delete = zebra_read_ipv6;
 #endif /* HAVE_IPV6 */
   zclient->nexthop_update = bgp_read_nexthop_update;
+  zclient->import_check_update = bgp_read_import_check_update;
 
   /* Interface related init. */
   if_init ();
index dce10886bb7850e59a709174342c849ddc3bf7ed..eb61d8b4010db7462cf217167eeb47e5745b18c2 100644 (file)
@@ -6408,7 +6408,9 @@ bgp_config_write (struct vty *vty)
        }
 
       /* BGP network import check. */
-      if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+      if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK_EXACT_MATCH))
+       vty_out (vty, " bgp network import-check exact%s", VTY_NEWLINE);
+      else if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
        vty_out (vty, " bgp network import-check%s", VTY_NEWLINE);
 
       /* BGP flag dampening. */
index ed555051b5d38855a3e579ce7897b98390419b77..fc8683f2bd4ffff47779f4eb891530c7eb3585c1 100644 (file)
@@ -239,6 +239,8 @@ struct bgp
 #define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
 #define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 16)
 #define BGP_FLAG_MULTIPATH_RELAX_NO_AS_SET (1 << 17)
+#define BGP_FLAG_FORCE_STATIC_PROCESS     (1 << 18)
+#define BGP_FLAG_IMPORT_CHECK_EXACT_MATCH (1 << 19)
 
   /* BGP Per AF flags */
   u_int16_t af_flags[AFI_MAX][SAFI_MAX];
index 4acc0cab83e81d7bfa6972ead93376a70a766b61..e15f3d50df05f19e479357c32b5805bfdacd9ab5 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -835,6 +835,7 @@ static const struct zebra_desc_table command_types[] = {
   DESC_ENTRY   (ZEBRA_NEXTHOP_UPDATE),
   DESC_ENTRY   (ZEBRA_INTERFACE_NBR_ADDRESS_ADD),
   DESC_ENTRY   (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE),
+  DESC_ENTRY    (ZEBRA_IMPORT_CHECK_UPDATE),
 };
 #undef DESC_ENTRY
 
index 29f568f2ad943eda6c556397cab51e9186a6e509..f6ac924573e155f0f9d977a10f09bcb9cc056b7f 100644 (file)
@@ -134,42 +134,6 @@ redist_del_instance (struct redist_proto *red, u_short instance)
     }
 }
 
-/* Initialize zebra client.  Argument redist_default is unwanted
-   redistribute route type. */
-void
-zclient_init (struct zclient *zclient, int redist_default, u_short instance)
-{
-  int afi, i;
-  
-  /* Enable zebra client connection by default. */
-  zclient->enable = 1;
-
-  /* Set -1 to the default socket value. */
-  zclient->sock = -1;
-
-  /* Clear redistribution flags. */
-  for (afi = AFI_IP; afi < AFI_MAX; afi++)
-    for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-      memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto));
-
-  /* Set unwanted redistribute route.  bgpd does not need BGP route
-     redistribution. */
-  zclient->redist_default = redist_default;
-  zclient->instance = instance;
-  /* Pending: make afi(s) an arg. */
-  for (afi = AFI_IP; afi < AFI_MAX; afi++)
-    redist_add_instance (&zclient->redist[afi][redist_default], instance);
-
-  /* Set default-information redistribute to zero. */
-  zclient->default_information = 0;
-
-  /* Schedule first zclient connection. */
-  if (zclient_debug)
-    zlog_debug ("zclient start scheduled");
-
-  zclient_event (ZCLIENT_SCHEDULE, zclient);
-}
-
 /* Stop zebra client services. */
 void
 zclient_stop (struct zclient *zclient)
@@ -405,13 +369,6 @@ zclient_start (struct zclient *zclient)
   int i;
   afi_t afi;
 
-  if (zclient_debug)
-    zlog_debug ("zclient_start is called");
-
-  /* zclient is disabled. */
-  if (! zclient->enable)
-    return 0;
-
   /* If already connected to the zebra. */
   if (zclient->sock >= 0)
     return 0;
@@ -420,34 +377,6 @@ zclient_start (struct zclient *zclient)
   if (zclient->t_connect)
     return 0;
 
-  if (zclient_socket_connect(zclient) < 0)
-    {
-      if (zclient_debug)
-       zlog_debug ("zclient connection fail");
-      zclient->fail++;
-      zclient_event (ZCLIENT_CONNECT, zclient);
-      return -1;
-    }
-
-  if (set_nonblocking(zclient->sock) < 0)
-    zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock);
-
-  /* Clear fail count. */
-  zclient->fail = 0;
-  if (zclient_debug)
-    zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
-      
-  /* Create read thread. */
-  zclient_event (ZCLIENT_READ, zclient);
-
-  zebra_hello_send (zclient);
-
-  /* We need router-id information. */
-  zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD);
-
-  /* We need interface information. */
-  zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
-
   /* Flush all redistribute request. */
   for (afi = AFI_IP; afi < AFI_MAX; afi++)
     for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
@@ -484,6 +413,73 @@ zclient_connect (struct thread *t)
   return zclient_start (zclient);
 }
 
+/* Initialize zebra client.  Argument redist_default is unwanted
+   redistribute route type. */
+void
+zclient_init (struct zclient *zclient, int redist_default, u_short instance)
+{
+  int afi, i;
+  
+  /* Enable zebra client connection by default. */
+  zclient->enable = 1;
+
+  /* Set -1 to the default socket value. */
+  zclient->sock = -1;
+
+  /* Clear redistribution flags. */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+      memset(&zclient->redist[afi][i], 0, sizeof(struct redist_proto));
+
+  /* Set unwanted redistribute route.  bgpd does not need BGP route
+     redistribution. */
+  zclient->redist_default = redist_default;
+  zclient->instance = instance;
+  /* Pending: make afi(s) an arg. */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    redist_add_instance (&zclient->redist[afi][redist_default], instance);
+
+  /* Set default-information redistribute to zero. */
+  zclient->default_information = 0;
+
+  if (zclient_debug)
+    zlog_debug ("zclient_start is called");
+
+  /* zclient is disabled. */
+  if (! zclient->enable)
+    return;
+
+  if (zclient_socket_connect(zclient) < 0)
+    {
+      if (zclient_debug)
+       zlog_debug ("zclient connection fail");
+      zclient->fail++;
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return;
+    }
+
+  if (set_nonblocking(zclient->sock) < 0)
+    zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock);
+
+  /* Clear fail count. */
+  zclient->fail = 0;
+  if (zclient_debug)
+    zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
+
+  /* Create read thread. */
+  zclient_event (ZCLIENT_READ, zclient);
+
+  zebra_hello_send (zclient);
+
+  /* We need router-id information. */
+  zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD);
+
+  /* We need interface information. */
+  zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
+
+  zclient_event (ZCLIENT_SCHEDULE, zclient);
+}
+
  /* 
   * "xdr_encode"-like interface that allows daemon (client) to send
   * a message to zebra server for a route that needs to be
@@ -1212,6 +1208,12 @@ zclient_read (struct thread *thread)
       if (zclient->nexthop_update)
        (*zclient->nexthop_update) (command, zclient, length);
       break;
+    case ZEBRA_IMPORT_CHECK_UPDATE:
+      if (zclient_debug)
+       zlog_debug("zclient rcvd import check update\n");
+      if (zclient->import_check_update)
+       (*zclient->import_check_update) (command, zclient, length);
+      break;
     default:
       break;
     }
index f73145db000341fcd93d54ad1b35c532764abebe..bb8a87b1456e61bfe4a974fa7dcd381db54d620a 100644 (file)
@@ -93,6 +93,7 @@ struct zclient
   int (*ipv6_route_add) (int, struct zclient *, uint16_t);
   int (*ipv6_route_delete) (int, struct zclient *, uint16_t);
   int (*nexthop_update) (int, struct zclient *, uint16_t);
+  int (*import_check_update) (int, struct zclient *, uint16_t);
 };
 
 /* Zebra API message flag. */
index 8b0248a3b6b1872287f56375ba9649c180bec4d7..05e7013c568260a41a3884c81c868031ec99b618 100644 (file)
@@ -430,7 +430,10 @@ struct in_pktinfo
 #define ZEBRA_INTERFACE_NBR_ADDRESS_ADD   27
 #define ZEBRA_INTERFACE_NBR_ADDRESS_DELETE 28
 #define ZEBRA_INTERFACE_BFD_DEST_DOWN    29
-#define ZEBRA_MESSAGE_MAX                30
+#define ZEBRA_IMPORT_ROUTE_REGISTER       30
+#define ZEBRA_IMPORT_ROUTE_UNREGISTER     31
+#define ZEBRA_IMPORT_CHECK_UPDATE         32
+#define ZEBRA_MESSAGE_MAX                 33
 
 /* Marker value used in new Zserv, in the byte location corresponding
  * the command value in the old zserv header. To allow old and new
index 58d3315a9e4ae7cd29aa74ef3e9466d5739385fa..038fe447567f874c9ac826053cbfcca45fea50b8 100644 (file)
@@ -301,6 +301,9 @@ struct vrf
   /* Recursive Nexthop table */
   struct route_table *rnh_table[AFI_MAX];
 
+  /* Import check table (used mostly by BGP */
+  struct route_table *import_check_table[AFI_MAX];
+
   /* Routing tables off of main table for redistribute table */
   struct route_table *other_table[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
 };
index 76c26c19ba333f74217261b6c4519556f5854153..f1a44fdda21475435ceb7a80cb2d96b87114c32d 100644 (file)
@@ -123,6 +123,9 @@ vrf_alloc (const char *name)
   vrf->rnh_table[AFI_IP] = route_table_init();
   vrf->rnh_table[AFI_IP6] = route_table_init();
 
+  vrf->import_check_table[AFI_IP] = route_table_init();
+  vrf->import_check_table[AFI_IP6] = route_table_init();
+
   return vrf;
 }
 
@@ -1753,9 +1756,11 @@ process_subq (struct list * subq, u_char qindex)
 static void
 meta_queue_process_complete (struct work_queue *dummy)
 {
-  zebra_evaluate_rnh_table(0, AF_INET, 0);
+  zebra_evaluate_rnh(0, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL);
+  zebra_evaluate_rnh(0, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, NULL);
 #ifdef HAVE_IPV6
-  zebra_evaluate_rnh_table(0, AF_INET6, 0);
+  zebra_evaluate_rnh(0, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL);
+  zebra_evaluate_rnh(0, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, NULL);
 #endif /* HAVE_IPV6 */
 }
 
index f698e62e9c855f17c9b66ca0493f53a16dc7eb7e..7d9c958f6424b5108d81aa4ef944a1c98aada486 100644 (file)
 #include "zebra/debug.h"
 #include "zebra/zebra_rnh.h"
 
-#define lookup_rnh_table(v, f)                  \
-({                                              \
-  struct vrf *vrf;                               \
-  struct route_table *t = NULL;                  \
-  vrf = vrf_lookup(v);                           \
-  if (vrf)                                       \
-    t = vrf->rnh_table[family2afi(f)];          \
-  t;                                             \
-})
-
 /* Default rtm_table for all clients */
 extern struct zebra_t zebrad;
 
 static void free_state(struct rib *rib, struct route_node *rn);
-static void copy_state(struct rnh *rnh, struct rib *rib, struct route_node *rn);
+static void copy_state(struct rnh *rnh, struct rib *rib,
+                      struct route_node *rn);
 static int compare_state(struct rib *r1, struct rib *r2);
-static int send_client(struct rnh *rnh, struct zserv *client);
+static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type);
 static void print_rnh(struct route_node *rn, struct vty *vty);
 
 int zebra_rnh_ip_default_route = 0;
 int zebra_rnh_ipv6_default_route = 0;
 
-char *
-rnh_str (struct rnh *rnh, char *buf, int size)
+static inline struct route_table *get_rnh_table(int vrfid, int family,
+                                               rnh_type_t type)
+{
+  struct vrf *vrf;
+  struct route_table *t = NULL;
+
+  vrf = vrf_lookup(vrfid);
+  if (vrf)
+    switch (type)
+      {
+      case RNH_NEXTHOP_TYPE:
+       t = vrf->rnh_table[family2afi(family)];
+       break;
+      case RNH_IMPORT_CHECK_TYPE:
+       t = vrf->import_check_table[family2afi(family)];
+       break;
+      }
+
+  return t;
+}
+
+char *rnh_str (struct rnh *rnh, char *buf, int size)
 {
   prefix2str(&(rnh->node->p), buf, size);
   return buf;
 }
 
 struct rnh *
-zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
+zebra_add_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -86,7 +97,7 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
       prefix2str(p, buf, INET6_ADDRSTRLEN);
       zlog_debug("add rnh %s in vrf %d", buf, vrfid);
     }
-  table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
+  table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
   if (!table)
     {
       zlog_debug("add_rnh: rnh table not found\n");
@@ -114,12 +125,12 @@ zebra_add_rnh (struct prefix *p, u_int32_t vrfid)
 }
 
 struct rnh *
-zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid)
+zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid, rnh_type_t type)
 {
   struct route_table *table;
   struct route_node *rn;
 
-  table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
+  table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type);
   if (!table)
     return NULL;
 
@@ -136,7 +147,7 @@ zebra_lookup_rnh (struct prefix *p, u_int32_t vrfid)
 }
 
 void
-zebra_delete_rnh (struct rnh *rnh)
+zebra_delete_rnh (struct rnh *rnh, rnh_type_t type)
 {
   struct route_node *rn;
 
@@ -160,7 +171,7 @@ zebra_delete_rnh (struct rnh *rnh)
 }
 
 void
-zebra_add_rnh_client (struct rnh *rnh, struct zserv *client)
+zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
 {
   if (IS_ZEBRA_DEBUG_NHT)
     {
@@ -172,12 +183,11 @@ 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);
     }
 }
 
 void
-zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
+zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
 {
   if (IS_ZEBRA_DEBUG_NHT)
     {
@@ -189,7 +199,7 @@ 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))
-    zebra_delete_rnh(rnh);
+    zebra_delete_rnh(rnh, type);
 }
 
 void
@@ -197,7 +207,7 @@ zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
 {
   struct rnh *rnh;
 
-  rnh = zebra_add_rnh(nh, 0);
+  rnh = zebra_add_rnh(nh, 0, RNH_NEXTHOP_TYPE);
   if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn))
     {
       listnode_add(rnh->zebra_static_route_list, static_rn);
@@ -209,7 +219,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
 {
   struct rnh *rnh;
 
-  rnh = zebra_lookup_rnh(nh, 0);
+  rnh = zebra_lookup_rnh(nh, 0, RNH_NEXTHOP_TYPE);
   if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED))
     return;
 
@@ -217,7 +227,7 @@ zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
 
   if (list_isempty(rnh->client_list) &&
       list_isempty(rnh->zebra_static_route_list))
-    zebra_delete_rnh(rnh);
+    zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
 }
 
 static inline int
@@ -276,12 +286,13 @@ zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn,
 }
 
 int
-zebra_evaluate_rnh_table (int vrfid, int family, int force)
+zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type,
+                   struct prefix *p)
 {
   struct route_table *ptable;
   struct route_table *ntable;
-  struct route_node *prn;
-  struct route_node *nrn;
+  struct route_node *prn = NULL;
+  struct route_node *nrn = NULL;
   struct rnh *rnh;
   struct zserv *client;
   struct listnode *node;
@@ -292,9 +303,10 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
   char bufp[INET6_ADDRSTRLEN];
   char bufs[INET6_ADDRSTRLEN];
   struct route_node *static_rn;
-  struct nexthop *nexthop;
+  struct nexthop *nexthop, *tnexthop;
+  int recursing;
 
-  ntable = lookup_rnh_table(vrfid, family);
+  ntable = get_rnh_table(vrfid, family, type);
   if (!ntable)
     {
       zlog_debug("evaluate_rnh_table: rnh table not found\n");
@@ -308,17 +320,38 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
       return -1;
     }
 
-  for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
+  if (p)
+    nrn = route_node_lookup(ntable, p);
+  else
+    nrn = route_top (ntable);
+
+  while (nrn != NULL)
     {
       if (!nrn->info)
-         continue;
+       goto loopend;
 
       rnh = nrn->info;
       at_least_one = 0;
 
+      /* free stale stuff first */
+      if (prn)
+       route_unlock_node(prn);
+
       prn = route_node_match(ptable, &nrn->p);
-      if (!prn || (zebra_rnh_is_default_route(&prn->p) &&
-                  !zebra_rnh_resolve_via_default(prn->p.family)))
+
+      /* Do not resolve over default route unless allowed &&
+       * match route to be exact if so specified
+       */
+      if (!prn)
+       rib = NULL;
+      else if ((type == RNH_NEXTHOP_TYPE) &&
+              (zebra_rnh_is_default_route(&prn->p) &&
+               !zebra_rnh_resolve_via_default(prn->p.family)))
+       rib = NULL;
+      else if ((type == RNH_IMPORT_CHECK_TYPE) &&
+              ((zebra_rnh_is_default_route(&prn->p)) ||
+               ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) &&
+                !prefix_same(&nrn->p, &prn->p))))
        rib = NULL;
       else
        {
@@ -333,6 +366,9 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
                      if (rib->type == ZEBRA_ROUTE_CONNECT)
                        break;
                    }
+                 else if ((type == RNH_IMPORT_CHECK_TYPE) &&
+                          (rib->type == ZEBRA_ROUTE_BGP))
+                   continue;
                  else
                    break;
                }
@@ -341,6 +377,42 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
 
       state_changed = 0;
 
+      /* Handle import check first as its simpler */
+      if (type == RNH_IMPORT_CHECK_TYPE)
+       {
+         if (rib && (rnh->state == NULL))
+           {
+             for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+               if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+                 {
+                   state_changed = 1;
+                   break;
+                 }
+           }
+         else if (!rib && (rnh->state != NULL))
+           state_changed = 1;
+
+         if (compare_state(rib, rnh->state))
+           copy_state(rnh, rib, nrn);
+
+         if (state_changed || force)
+           {
+             if (IS_ZEBRA_DEBUG_NHT)
+               {
+                 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
+                 zlog_debug("rnh import check %s for %s, notifying clients\n",
+                            rnh->state ? "passed" : "failed", bufn);
+               }
+             /* state changed, notify clients */
+             for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
+               {
+                 send_client(rnh, client, RNH_IMPORT_CHECK_TYPE);
+               }
+           }
+
+         goto loopend;
+       }
+
       /* Ensure prefixes we're resolving over have stayed the same */
       if (!prefix_same(&rnh->resolved_route, &prn->p))
        {
@@ -401,7 +473,7 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
                           at_least_one ? "":"(filtered)", bufn, bufp,
                           rib ? "reachable" : "unreachable");
 
-             send_client(rnh, client); /* Route-map passed */
+             send_client(rnh, client, RNH_NEXTHOP_TYPE); /* Route-map passed */
            }
 
          /* Now evaluate static client */
@@ -482,18 +554,34 @@ zebra_evaluate_rnh_table (int vrfid, int family, int force)
                }
            }
        }
+    loopend:
+      if (p)
+       {
+         route_unlock_node(nrn);
+         nrn = NULL;
+       }
+      else
+       {
+         /* route_next takes care of unlocking nrn */
+         nrn = route_next(nrn);
+       }
     }
+
+  if (prn)
+    route_unlock_node(prn);
+
   return 1;
 }
 
 int
-zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client)
+zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client,
+                         rnh_type_t type)
 {
   struct route_table *ntable;
   struct route_node *nrn;
   struct rnh *rnh;
 
-  ntable = lookup_rnh_table(vrfid, family);
+  ntable = get_rnh_table(vrfid, family, type);
   if (!ntable)
     {
       zlog_debug("dispatch_rnh_table: rnh table not found\n");
@@ -514,18 +602,18 @@ zebra_dispatch_rnh_table (int vrfid, int family, struct zserv *client)
                     rnh->state ? "reachable" : "unreachable",
                     zebra_route_string(client->proto));
        }
-      send_client(rnh, client);
+      send_client(rnh, client, RNH_NEXTHOP_TYPE);
     }
   return 1;
 }
 
 void
-zebra_print_rnh_table (int vrfid, int af, struct vty *vty)
+zebra_print_rnh_table (int vrfid, int af, struct vty *vty, rnh_type_t type)
 {
   struct route_table *table;
   struct route_node *rn;
 
-  table = lookup_rnh_table(vrfid, af);
+  table = get_rnh_table(vrfid, af, type);
   if (!table)
     {
       zlog_debug("print_rnhs: rnh table not found\n");
@@ -538,13 +626,14 @@ zebra_print_rnh_table (int vrfid, int af, struct vty *vty)
 }
 
 int
-zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client)
+zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client,
+                         rnh_type_t type)
 {
   struct route_table *ntable;
   struct route_node *nrn;
   struct rnh *rnh;
 
-  ntable = lookup_rnh_table(vrfid, family);
+  ntable = get_rnh_table(vrfid, family, type);
   if (!ntable)
     {
       zlog_debug("cleanup_rnh_client: rnh table not found\n");
@@ -564,7 +653,7 @@ zebra_cleanup_rnh_client (int vrfid, int family, struct zserv *client)
          zlog_debug("rnh %s - cleaning state for client %s", bufn,
                     zebra_route_string(client->proto));
        }
-      zebra_remove_rnh_client(rnh, client);
+      zebra_remove_rnh_client(rnh, client, type);
     }
   return 1;
 }
@@ -631,7 +720,7 @@ compare_state (struct rib *r1, struct rib *r2)
 }
 
 static int
-send_client (struct rnh *rnh, struct zserv *client)
+send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type)
 {
   struct stream *s;
   struct rib *rib;
@@ -639,6 +728,8 @@ send_client (struct rnh *rnh, struct zserv *client)
   u_char num;
   struct nexthop *nexthop;
   struct route_node *rn;
+  int cmd = (type == RNH_IMPORT_CHECK_TYPE)
+    ? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE;
 
   rn = rnh->node;
   rib = rnh->state;
@@ -647,11 +738,23 @@ send_client (struct rnh *rnh, struct zserv *client)
   s = client->obuf;
   stream_reset (s);
 
-  zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE);
-
+  zserv_create_header (s, cmd);
   stream_putw(s, rn->p.family);
-  stream_put_prefix (s, &rn->p);
-
+  switch (rn->p.family)
+    {
+    case AF_INET:
+      stream_putc(s, rn->p.prefixlen);
+      stream_put_in_addr(s, &rn->p.u.prefix4);
+      break;
+    case AF_INET6:
+      stream_putc(s, rn->p.prefixlen);
+      stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
+      break;
+    default:
+      zlog_err("%s: Unknown family (%d) notification attempted\n",
+              __FUNCTION__, rn->p.family);
+      break;
+    }
   if (rib)
     {
       stream_putl (s, rib->metric);
@@ -704,7 +807,7 @@ send_client (struct rnh *rnh, struct zserv *client)
   stream_putw_at (s, 0, stream_get_endp (s));
 
   client->nh_last_upd_time = quagga_time(NULL);
-  client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
+  client->last_write_cmd = cmd;
   return zebra_server_send_message(client);
 }
 
index 2ef16bdf802568e494cfb7e0d81f45b067c803f8..494be8366ca219795055543b2a7585f5e0c7418c 100644 (file)
 struct rnh
 {
   u_char flags;
+
 #define ZEBRA_NHT_CONNECTED    0x1
 #define ZEBRA_NHT_DELETED       0x2
+#define ZEBRA_NHT_EXACT_MATCH   0x4
+
   struct rib *state;
   struct prefix resolved_route;
   struct list *client_list;
@@ -40,19 +43,30 @@ struct rnh
   int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */
 };
 
+typedef enum
+  {
+    RNH_NEXTHOP_TYPE,
+    RNH_IMPORT_CHECK_TYPE
+  } rnh_type_t;
+
 extern int zebra_rnh_ip_default_route;
 extern int zebra_rnh_ipv6_default_route;
 
-extern struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid);
-extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid);
-extern void zebra_delete_rnh(struct rnh *rnh);
-extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client);
+extern struct rnh *zebra_add_rnh(struct prefix *p, u_int32_t vrfid,
+                                rnh_type_t type);
+extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid,
+                                   rnh_type_t type);
+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);
 extern void zebra_register_rnh_static_nh(struct prefix *, struct route_node *);
 extern void zebra_deregister_rnh_static_nh(struct prefix *, struct route_node *);
-extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
-extern int zebra_evaluate_rnh_table(int vrfid, int family, int force);
-extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl);
-extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty);
+extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
+                                   rnh_type_t type);
+extern int zebra_evaluate_rnh(int vrfid, int family, int force, rnh_type_t type,
+                             struct prefix *p);
+extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl, rnh_type_t);
+extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty, rnh_type_t);
 extern char *rnh_str(struct rnh *rnh, char *buf, int size);
-extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client);
+extern int zebra_cleanup_rnh_client(int vrf, int family, struct zserv *client,
+                                   rnh_type_t type);
 #endif /*_ZEBRA_RNH_H */
index 205382b4824125ea350502ed39f520625ee53d31..5bd00a3ecdd428f906c9498751ee903e37a5aef3 100644 (file)
@@ -6,10 +6,12 @@
 int zebra_rnh_ip_default_route = 0;
 int zebra_rnh_ipv6_default_route = 0;
 
-int zebra_evaluate_rnh_table (int vrfid, int family, int force)
+int zebra_evaluate_rnh (int vrfid, int family, int force, rnh_type_t type,
+                       struct prefix *p)
 { return 0; }
 
-void zebra_print_rnh_table (int vrfid, int family, struct vty *vty)
+void zebra_print_rnh_table (int vrfid, int family, struct vty *vty,
+                           rnh_type_t type)
 {}
 
 void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn)
index 6ec28d73a87c3068b16375a4dfda37ca952781e7..8ac08960a6a78b6af0bb8abfcb5d179fe5500b0e 100644 (file)
@@ -846,7 +846,7 @@ DEFUN (ip_protocol_nht_rmap,
     }
 
   nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
-  zebra_evaluate_rnh_table(0, AF_INET, 1);
+  zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
 
   return CMD_SUCCESS;
 }
@@ -879,7 +879,7 @@ DEFUN (no_ip_protocol_nht_rmap,
     {
       XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
       nht_rm[AFI_IP][i] = NULL;
-      zebra_evaluate_rnh_table(0, AF_INET, 1);
+      zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
     }
   return CMD_SUCCESS;
 }
@@ -944,7 +944,7 @@ DEFUN (ipv6_protocol_nht_rmap,
   if (nht_rm[AFI_IP6][i])
     XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
   nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
-  zebra_evaluate_rnh_table(0, AF_INET6, 1);
+  zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
 
   return CMD_SUCCESS;
 }
@@ -977,7 +977,7 @@ DEFUN (no_ipv6_protocol_nht_rmap,
     {
       XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
       nht_rm[AFI_IP6][i] = NULL;
-      zebra_evaluate_rnh_table(0, AF_INET6, 1);
+      zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
     }
 
   return CMD_SUCCESS;
@@ -1446,8 +1446,8 @@ zebra_route_map_update_timer (struct thread *thread)
     zlog_debug("Event driven route-map update triggered");
 
   rib_update();
-  zebra_evaluate_rnh_table(0, AF_INET, 1);
-  zebra_evaluate_rnh_table(0, AF_INET6, 1);
+  zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
+  zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
 
   return (0);
 }
index 3c80c9ffabefab1cda238f2fe1c9963710a1364b..ab6e5ec7b568647f71e25c84c663702205ef1e33 100644 (file)
@@ -1180,7 +1180,7 @@ DEFUN (show_ip_nht,
        IP_STR
        "IP nexthop tracking table\n")
 {
-  zebra_print_rnh_table(0, AF_INET, vty);
+  zebra_print_rnh_table(0, AF_INET, vty, RNH_NEXTHOP_TYPE);
   return CMD_SUCCESS;
 }
 
@@ -1191,7 +1191,7 @@ DEFUN (show_ipv6_nht,
        IP_STR
        "IPv6 nexthop tracking table\n")
 {
-  zebra_print_rnh_table(0, AF_INET6, vty);
+  zebra_print_rnh_table(0, AF_INET6, vty, RNH_NEXTHOP_TYPE);
   return CMD_SUCCESS;
 }
 
@@ -1206,7 +1206,7 @@ DEFUN (ip_nht_default_route,
     return CMD_SUCCESS;
 
   zebra_rnh_ip_default_route = 1;
-  zebra_evaluate_rnh_table(0, AF_INET, 1);
+  zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
   return CMD_SUCCESS;
 }
 
@@ -1222,7 +1222,7 @@ DEFUN (no_ip_nht_default_route,
     return CMD_SUCCESS;
 
   zebra_rnh_ip_default_route = 0;
-  zebra_evaluate_rnh_table(0, AF_INET, 1);
+  zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
   return CMD_SUCCESS;
 }
 
@@ -1237,7 +1237,7 @@ DEFUN (ipv6_nht_default_route,
     return CMD_SUCCESS;
 
   zebra_rnh_ipv6_default_route = 1;
-  zebra_evaluate_rnh_table(0, AF_INET6, 1);
+  zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
   return CMD_SUCCESS;
 }
 
@@ -1253,7 +1253,7 @@ DEFUN (no_ipv6_nht_default_route,
     return CMD_SUCCESS;
 
   zebra_rnh_ipv6_default_route = 0;
-  zebra_evaluate_rnh_table(0, AF_INET6, 1);
+  zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
   return CMD_SUCCESS;
 }
 
index 960514319ffdab70c76e8ea12c09344086111416..fb138c11bbccbd7c4b11dc15d73bb4f113dc45e6 100644 (file)
@@ -786,69 +786,114 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
 
 /* Nexthop register */
 static int
-zserv_nexthop_register (struct zserv *client, int sock, u_short length)
+zserv_rnh_register (struct zserv *client, int sock, u_short length,
+                   rnh_type_t type)
 {
   struct rnh *rnh;
   struct stream *s;
   struct prefix p;
   u_short l = 0;
-  u_char connected;
+  u_char flags = 0;
 
   if (IS_ZEBRA_DEBUG_NHT)
-    zlog_debug("nexthop_register msg from client %s: length=%d\n",
-              zebra_route_string(client->proto), length);
+    zlog_debug("rnh_register msg from client %s: length=%d, type=%s\n",
+              zebra_route_string(client->proto), length,
+              (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route");
 
   s = client->ibuf;
 
+  client->nh_reg_time = quagga_time(NULL);
+
   while (l < length)
     {
-      connected = stream_getc(s);
+      flags = stream_getc(s);
       p.family = stream_getw(s);
       p.prefixlen = stream_getc(s);
       l += 4;
-      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
-      l += PSIZE(p.prefixlen);
-      rnh = zebra_add_rnh(&p, 0);
-      if (connected)
-       SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
-
-      client->nh_reg_time = quagga_time(NULL);
-      zebra_add_rnh_client(rnh, client);
+      if (p.family == AF_INET)
+       {
+         p.u.prefix4.s_addr = stream_get_ipv4(s);
+         l += IPV4_MAX_BYTELEN;
+       }
+      else if (p.family == AF_INET6)
+       {
+         stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
+         l += IPV6_MAX_BYTELEN;
+       }
+      else
+       {
+         zlog_err("rnh_register: Received unknown family type %d\n",
+                  p.family);
+         return -1;
+       }
+      rnh = zebra_add_rnh(&p, 0, type);
+      if (type == RNH_NEXTHOP_TYPE)
+       {
+         if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+           SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
+         else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+           UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
+       }
+      else if (type == RNH_IMPORT_CHECK_TYPE)
+       {
+         if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
+           SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
+         else if (!flags && CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
+           UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
+       }
+
+      zebra_add_rnh_client(rnh, client, type);
+      /* Anything not AF_INET/INET6 has been filtered out above */
+      zebra_evaluate_rnh(0, p.family, 1, type, &p);
     }
-  zebra_evaluate_rnh_table(0, AF_INET, 0);
-  zebra_evaluate_rnh_table(0, AF_INET6, 0);
   return 0;
 }
 
 /* Nexthop register */
 static int
-zserv_nexthop_unregister (struct zserv *client, int sock, u_short length)
+zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
+                     rnh_type_t type)
 {
   struct rnh *rnh;
   struct stream *s;
   struct prefix p;
   u_short l = 0;
-  u_char connected;
+  u_char flags;
+  u_char exact_match;
 
   if (IS_ZEBRA_DEBUG_NHT)
-    zlog_debug("nexthop_unregister msg from client %s: length=%d\n",
+    zlog_debug("rnh_unregister msg from client %s: length=%d\n",
               zebra_route_string(client->proto), length);
 
   s = client->ibuf;
 
   while (l < length)
     {
-      connected = stream_getc(s);
+      flags = stream_getc(s);
       p.family = stream_getw(s);
       p.prefixlen = stream_getc(s);
       l += 4;
-      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
-      l += PSIZE(p.prefixlen);
-      rnh = zebra_lookup_rnh(&p, 0);
+      if (p.family == AF_INET)
+       {
+         p.u.prefix4.s_addr = stream_get_ipv4(s);
+         l += IPV4_MAX_BYTELEN;
+       }
+      else if (p.family == AF_INET6)
+       {
+         stream_get(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
+         l += IPV6_MAX_BYTELEN;
+       }
+      else
+       {
+         zlog_err("rnh_register: Received unknown family type %d\n",
+                  p.family);
+         return -1;
+       }
+      rnh = zebra_lookup_rnh(&p, 0, type);
       if (rnh)
        {
          client->nh_dereg_time = quagga_time(NULL);
-         zebra_remove_rnh_client(rnh, client);
+         zebra_remove_rnh_client(rnh, client, type);
        }
     }
   return 0;
@@ -1496,8 +1541,10 @@ zread_hello (struct zserv *client)
 static void
 zebra_client_close (struct zserv *client)
 {
-  zebra_cleanup_rnh_client(0, AF_INET, client);
-  zebra_cleanup_rnh_client(0, AF_INET6, client);
+  zebra_cleanup_rnh_client(0, AF_INET, client, RNH_NEXTHOP_TYPE);
+  zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_NEXTHOP_TYPE);
+  zebra_cleanup_rnh_client(0, AF_INET, client, RNH_IMPORT_CHECK_TYPE);
+  zebra_cleanup_rnh_client(0, AF_INET6, client, RNH_IMPORT_CHECK_TYPE);
 
   /* Close file descriptor. */
   if (client->sock)
@@ -1721,10 +1768,16 @@ zebra_client_read (struct thread *thread)
       zread_hello (client);
       break;
     case ZEBRA_NEXTHOP_REGISTER:
-      zserv_nexthop_register(client, sock, length);
+      zserv_rnh_register(client, sock, length, RNH_NEXTHOP_TYPE);
       break;
     case ZEBRA_NEXTHOP_UNREGISTER:
-      zserv_nexthop_unregister(client, sock, length);
+      zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE);
+      break;
+    case ZEBRA_IMPORT_ROUTE_REGISTER:
+      zserv_rnh_register(client, sock, length, RNH_IMPORT_CHECK_TYPE);
+      break;
+    case ZEBRA_IMPORT_ROUTE_UNREGISTER:
+      zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE);
       break;
     default:
       zlog_info ("Zebra received unknown command %d", command);