ip: Replace Sematics for Interface IP addresses
[vpp.git] / src / plugins / gbp / gbp_endpoint.c
index 9cae2ab..e1a810c 100644 (file)
 #include <plugins/gbp/gbp_policy_dpo.h>
 #include <plugins/gbp/gbp_vxlan.h>
 
-#include <vnet/ethernet/arp.h>
 #include <vnet/l2/l2_input.h>
 #include <vnet/l2/l2_output.h>
 #include <vnet/l2/feat_bitmap.h>
 #include <vnet/l2/l2_fib.h>
 #include <vnet/fib/fib_table.h>
-#include <vnet/ip/ip_neighbor.h>
+#include <vnet/ip-neighbor/ip_neighbor.h>
 #include <vnet/fib/fib_walk.h>
+#include <vnet/vxlan-gbp/vxlan_gbp.h>
 
 static const char *gbp_endpoint_attr_names[] = GBP_ENDPOINT_ATTR_NAMES;
 
@@ -40,9 +40,10 @@ static const char *gbp_endpoint_attr_names[] = GBP_ENDPOINT_ATTR_NAMES;
  */
 gbp_ep_db_t gbp_ep_db;
 
-fib_node_type_t gbp_endpoint_fib_type;
-
-vlib_log_class_t gbp_ep_logger;
+static fib_source_t gbp_fib_source_hi;
+static fib_source_t gbp_fib_source_low;
+static fib_node_type_t gbp_endpoint_fib_type;
+static vlib_log_class_t gbp_ep_logger;
 
 #define GBP_ENDPOINT_DBG(...)                           \
     vlib_log_debug (gbp_ep_logger, __VA_ARGS__);
@@ -100,6 +101,16 @@ gbp_endpoint_is_external (const gbp_endpoint_t * ge)
   return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_EXTERNAL));
 }
 
+int
+gbp_endpoint_is_learnt (const gbp_endpoint_t * ge)
+{
+  if (0 == vec_len (ge->ge_locs))
+    return 0;
+
+  /* DP is the highest source so if present it will be first */
+  return (ge->ge_locs[0].gel_src == GBP_ENDPOINT_SRC_DP);
+}
+
 static void
 gbp_endpoint_extract_key_mac_itf (const clib_bihash_kv_16_8_t * key,
                                  mac_address_t * mac, u32 * sw_if_index)
@@ -196,12 +207,6 @@ gbp_endpoint_index (const gbp_endpoint_t * ge)
   return (ge - gbp_endpoint_pool);
 }
 
-static ip46_type_t
-ip46_address_get_type (const ip46_address_t * a)
-{
-  return (ip46_address_is_ip4 (a) ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
-}
-
 static int
 gbp_endpoint_ip_is_equal (const fib_prefix_t * fp, const ip46_address_t * ip)
 {
@@ -253,7 +258,8 @@ gbp_endpoint_alloc (const ip46_address_t * ips,
   fib_node_init (&ge->ge_node, gbp_endpoint_fib_type);
   gei = gbp_endpoint_index (ge);
   ge->ge_key.gek_gbd =
-    ge->ge_key.gek_grd = ge->ge_fwd.gef_itf = INDEX_INVALID;
+    ge->ge_key.gek_grd = ge->ge_fwd.gef_fib_index = INDEX_INVALID;
+  gbp_itf_hdl_reset (&ge->ge_fwd.gef_itf);
   ge->ge_last_time = vlib_time_now (vlib_get_main ());
   ge->ge_key.gek_gbd = gbp_bridge_domain_index (gbd);
 
@@ -324,11 +330,7 @@ static void
 gbp_endpoint_loc_destroy (gbp_endpoint_loc_t * gel)
 {
   gbp_endpoint_group_unlock (gel->gel_epg);
-
-  if (gel->gel_flags & GBP_ENDPOINT_FLAG_REMOTE)
-    {
-      vxlan_gbp_tunnel_unlock (gel->gel_sw_if_index);
-    }
+  gbp_itf_unlock (&gel->gel_itf);
 }
 
 static gbp_endpoint_loc_t *
@@ -337,7 +339,7 @@ gbp_endpoint_loc_find_or_add (gbp_endpoint_t * ge, gbp_endpoint_src_t src)
   gbp_endpoint_loc_t gel = {
     .gel_src = src,
     .gel_epg = INDEX_INVALID,
-    .gel_sw_if_index = INDEX_INVALID,
+    .gel_itf = GBP_ITF_HDL_INVALID,
     .gel_locks = 0,
   };
   u32 pos;
@@ -472,7 +474,9 @@ gbp_endpoint_n_learned (int n)
 }
 
 static void
-gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
+gbp_endpoint_loc_update (const gbp_endpoint_t * ge,
+                        gbp_endpoint_loc_t * gel,
+                        const gbp_bridge_domain_t * gb,
                         u32 sw_if_index,
                         index_t ggi,
                         gbp_endpoint_flags_t flags,
@@ -488,18 +492,12 @@ gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
 
   gbp_endpoint_n_learned (is_learnt - was_learnt);
 
-  if (INDEX_INVALID == gel->gel_epg)
-    {
-      gel->gel_epg = ggi;
-      if (INDEX_INVALID != gel->gel_epg)
-       {
-         gbp_endpoint_group_lock (gel->gel_epg);
-       }
-    }
-  else
-    {
-      ASSERT (gel->gel_epg == ggi);
-    }
+  /*
+   * update the EPG
+   */
+  gbp_endpoint_group_lock (ggi);
+  gbp_endpoint_group_unlock (gel->gel_epg);
+  gel->gel_epg = ggi;
 
   if (gel->gel_flags & GBP_ENDPOINT_FLAG_REMOTE)
     {
@@ -508,34 +506,52 @@ gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
       if (NULL != tun_dst)
        ip46_address_copy (&gel->tun.gel_dst, tun_dst);
 
+      if (ip46_address_is_multicast (&gel->tun.gel_src))
+       {
+         /*
+          * we learnt the EP from the multicast tunnel.
+          * Create a unicast TEP from the packet's source
+          * and the fixed address of the BD's parent tunnel
+          */
+         const gbp_vxlan_tunnel_t *gt;
+
+         gt = gbp_vxlan_tunnel_get (gb->gb_vni);
+
+         if (NULL != gt)
+           {
+             ip46_address_copy (&gel->tun.gel_src, &gt->gt_src);
+             sw_if_index = gt->gt_sw_if_index;
+           }
+       }
+
       /*
        * the input interface may be the parent GBP-vxlan interface,
        * create a child vlxan-gbp tunnel and use that as the endpoint's
        * interface.
        */
-      if (~0 != gel->gel_sw_if_index)
-       vxlan_gbp_tunnel_unlock (gel->gel_sw_if_index);
+      gbp_itf_hdl_t old = gel->gel_itf;
 
       switch (gbp_vxlan_tunnel_get_type (sw_if_index))
        {
        case GBP_VXLAN_TEMPLATE_TUNNEL:
          gel->tun.gel_parent_sw_if_index = sw_if_index;
-         gel->gel_sw_if_index =
-           gbp_vxlan_tunnel_clone_and_lock (sw_if_index,
-                                            &gel->tun.gel_src,
-                                            &gel->tun.gel_dst);
+         gel->gel_itf = gbp_vxlan_tunnel_clone_and_lock (sw_if_index,
+                                                         &gel->tun.gel_src,
+                                                         &gel->tun.gel_dst);
          break;
        case VXLAN_GBP_TUNNEL:
          gel->tun.gel_parent_sw_if_index =
            vxlan_gbp_tunnel_get_parent (sw_if_index);
-         gel->gel_sw_if_index = sw_if_index;
-         vxlan_gbp_tunnel_lock (gel->gel_sw_if_index);
+         gel->gel_itf = vxlan_gbp_tunnel_lock_itf (sw_if_index);
          break;
        }
+
+      gbp_itf_unlock (&old);
     }
   else
     {
-      gel->gel_sw_if_index = sw_if_index;
+      gel->gel_itf = gbp_itf_l2_add_and_lock (sw_if_index,
+                                             ge->ge_key.gek_gbd);
     }
 }
 
@@ -547,9 +563,7 @@ gbb_endpoint_fwd_reset (gbp_endpoint_t * ge)
   gbp_endpoint_fwd_t *gef;
   const fib_prefix_t *pfx;
   index_t *ai;
-  index_t gei;
 
-  gei = gbp_endpoint_index (ge);
   gbd = gbp_bridge_domain_get (ge->ge_key.gek_gbd);
   gef = &ge->ge_fwd;
 
@@ -568,36 +582,33 @@ gbb_endpoint_fwd_reset (gbp_endpoint_t * ge)
      */
     if (gbp_endpoint_is_remote (ge))
       {
-       fib_table_entry_special_remove (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
+       fib_table_entry_special_remove (fib_index, pfx, gbp_fib_source_hi);
       }
 
-    fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_LOW);
+    fib_table_entry_delete (fib_index, pfx, gbp_fib_source_low);
   }
   vec_foreach (ai, gef->gef_adjs)
   {
     adj_unlock (*ai);
   }
 
-  if (INDEX_INVALID != gef->gef_itf)
+  if (gbp_itf_hdl_is_valid (gef->gef_itf))
     {
       l2fib_del_entry (ge->ge_key.gek_mac.bytes,
-                      gbd->gb_bd_index, gef->gef_itf);
-      gbp_itf_set_l2_input_feature (gef->gef_itf, gei, (L2INPUT_FEAT_NONE));
-      gbp_itf_set_l2_output_feature (gef->gef_itf, gei, L2OUTPUT_FEAT_NONE);
-
-      gbp_itf_unlock (gef->gef_itf);
-      gef->gef_itf = INDEX_INVALID;
+                      gbd->gb_bd_index,
+                      gbp_itf_get_sw_if_index (gef->gef_itf));
     }
 
+  gbp_itf_unlock (&gef->gef_itf);
   vec_free (gef->gef_adjs);
 }
 
 static void
 gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
 {
-  const gbp_route_domain_t *grd;
   const gbp_bridge_domain_t *gbd;
   const gbp_endpoint_group_t *gg;
+  const gbp_route_domain_t *grd;
   gbp_endpoint_loc_t *gel;
   gbp_endpoint_fwd_t *gef;
   const fib_prefix_t *pfx;
@@ -616,19 +627,18 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
   if (INDEX_INVALID != gel->gel_epg)
     {
       gg = gbp_endpoint_group_get (gel->gel_epg);
-      gef->gef_epg_id = gg->gg_id;
+      gef->gef_sclass = gg->gg_sclass;
     }
   else
     {
       gg = NULL;
     }
 
-  gef->gef_itf = gbp_itf_add_and_lock (gel->gel_sw_if_index,
-                                      gbd->gb_bd_index);
+  gef->gef_itf = gbp_itf_clone_and_lock (gel->gel_itf);
 
   if (!mac_address_is_zero (&ge->ge_key.gek_mac))
     {
-      gbp_itf_set_l2_input_feature (gef->gef_itf, gei, L2INPUT_FEAT_GBP_FWD);
+      gbp_itf_l2_set_input_feature (gef->gef_itf, L2INPUT_FEAT_GBP_FWD);
 
       if (gbp_endpoint_is_remote (ge) || gbp_endpoint_is_external (ge))
        {
@@ -636,18 +646,19 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
           * bridged packets to external endpoints should be classifed
           * based on the EP's/BD's EPG
           */
-         gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
+         gbp_itf_l2_set_output_feature (gef->gef_itf,
                                         L2OUTPUT_FEAT_GBP_POLICY_MAC);
        }
       else
        {
-         gbp_endpoint_add_itf (gef->gef_itf, gei);
-         gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
+         gbp_endpoint_add_itf (gbp_itf_get_sw_if_index (gef->gef_itf), gei);
+         gbp_itf_l2_set_output_feature (gef->gef_itf,
                                         L2OUTPUT_FEAT_GBP_POLICY_PORT);
        }
       l2fib_add_entry (ge->ge_key.gek_mac.bytes,
                       gbd->gb_bd_index,
-                      gef->gef_itf, L2FIB_ENTRY_RESULT_FLAG_STATIC);
+                      gbp_itf_get_sw_if_index (gef->gef_itf),
+                      L2FIB_ENTRY_RESULT_FLAG_STATIC);
     }
 
   vec_foreach (pfx, ge->ge_key.gek_ips)
@@ -661,6 +672,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
     rewrite = NULL;
     grd = gbp_route_domain_get (ge->ge_key.gek_grd);
     fib_index = grd->grd_fib_index[pfx->fp_proto];
+    gef->gef_fib_index = fib_index;
 
     bd_add_del_ip_mac (gbd->gb_bd_index, fib_proto_to_ip46 (pfx->fp_proto),
                       &pfx->fp_addr, &ge->ge_key.gek_mac, 1);
@@ -684,7 +696,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
         * tunnel since the BD will not contain the EP's MAC since it was
         * L3 learned. The dst MAC address used is the 'BD's MAC'.
         */
-       ip_sw_if_index = gef->gef_itf;
+       ip_sw_if_index = gbp_itf_get_sw_if_index (gef->gef_itf);
 
        mac_address_to_bytes (gbp_route_domain_get_local_mac (),
                              eth->src_address);
@@ -708,7 +720,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
       }
 
     fib_table_entry_path_add (fib_index, pfx,
-                             FIB_SOURCE_PLUGIN_LOW,
+                             gbp_fib_source_low,
                              FIB_ENTRY_FLAG_NONE,
                              fib_proto_to_dpo (pfx->fp_proto),
                              &pfx->fp_addr, ip_sw_if_index,
@@ -737,10 +749,11 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
             * is applied
             */
            gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (pfx->fp_proto),
-                                       gg->gg_id, ~0, &policy_dpo);
+                                       grd->grd_scope,
+                                       gg->gg_sclass, ~0, &policy_dpo);
 
            fib_table_entry_special_dpo_add (fib_index, pfx,
-                                            FIB_SOURCE_PLUGIN_HI,
+                                            gbp_fib_source_hi,
                                             FIB_ENTRY_FLAG_INTERPOSE,
                                             &policy_dpo);
            dpo_reset (&policy_dpo);
@@ -753,20 +766,23 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
         */
        if (gbp_endpoint_is_local (ge) && ~0 != gg->gg_uplink_sw_if_index)
          {
-           gbp_endpoint_add_itf (gef->gef_itf, gei);
-           if (FIB_PROTOCOL_IP4 == pfx->fp_proto)
-             send_ip4_garp_w_addr (vlib_get_main (),
-                                   &pfx->fp_addr.ip4,
-                                   gg->gg_uplink_sw_if_index);
-           else
-             send_ip6_na_w_addr (vlib_get_main (),
-                                 &pfx->fp_addr.ip6,
-                                 gg->gg_uplink_sw_if_index);
+           gbp_endpoint_add_itf (gbp_itf_get_sw_if_index (gef->gef_itf),
+                                 gei);
+           ip_neighbor_advertise (vlib_get_main (),
+                                  (FIB_PROTOCOL_IP4 == pfx->fp_proto ?
+                                   IP46_TYPE_IP4 :
+                                   IP46_TYPE_IP6),
+                                  &pfx->fp_addr, gg->gg_uplink_sw_if_index);
          }
       }
   }
 
-  if (gbp_endpoint_is_local (ge) && !gbp_endpoint_is_external (ge))
+  if (gbp_endpoint_is_external (ge))
+    {
+      gbp_itf_l2_set_input_feature (gef->gef_itf,
+                                   L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+    }
+  else if (gbp_endpoint_is_local (ge))
     {
       /*
        * non-remote endpoints (i.e. those not arriving on iVXLAN
@@ -779,7 +795,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
 
       if (NULL != gg && ~0 != gg->gg_uplink_sw_if_index)
        feats |= L2INPUT_FEAT_GBP_FWD;
-      gbp_itf_set_l2_input_feature (gef->gef_itf, gei, feats);
+      gbp_itf_l2_set_input_feature (gef->gef_itf, feats);
     }
 
   /*
@@ -798,7 +814,8 @@ gbp_endpoint_update_and_lock (gbp_endpoint_src_t src,
                              u32 sw_if_index,
                              const ip46_address_t * ips,
                              const mac_address_t * mac,
-                             index_t gbdi, index_t grdi, epg_id_t epg_id,
+                             index_t gbdi, index_t grdi,
+                             sclass_t sclass,
                              gbp_endpoint_flags_t flags,
                              const ip46_address_t * tun_src,
                              const ip46_address_t * tun_dst, u32 * handle)
@@ -822,9 +839,9 @@ gbp_endpoint_update_and_lock (gbp_endpoint_src_t src,
    * we need to determine the bridge-domain, either from the EPG or
    * the BD passed
    */
-  if (EPG_INVALID != epg_id)
+  if (SCLASS_INVALID != sclass)
     {
-      ggi = gbp_endpoint_group_find (epg_id);
+      ggi = gbp_endpoint_group_find (sclass);
 
       if (INDEX_INVALID == ggi)
        return (VNET_API_ERROR_NO_SUCH_ENTRY);
@@ -862,7 +879,8 @@ gbp_endpoint_update_and_lock (gbp_endpoint_src_t src,
   gei = gbp_endpoint_index (ge);
   gel = gbp_endpoint_loc_find_or_add (ge, src);
 
-  gbp_endpoint_loc_update (gel, sw_if_index, ggi, flags, tun_src, tun_dst);
+  gbp_endpoint_loc_update (ge, gel, gbd, sw_if_index, ggi, flags,
+                          tun_src, tun_dst);
 
   if (src <= best)
     {
@@ -1053,9 +1071,10 @@ gbp_endpoint_cli (vlib_main_t * vm,
   ip46_address_t ip = ip46_address_initializer, *ips = NULL;
   mac_address_t mac = ZERO_MAC_ADDRESS;
   vnet_main_t *vnm = vnet_get_main ();
-  u32 epg_id = EPG_INVALID;
+  u32 sclass = SCLASS_INVALID;
   u32 handle = INDEX_INVALID;
   u32 sw_if_index = ~0;
+  u32 flags = GBP_ENDPOINT_FLAG_NONE;
   u8 add = 1;
   int rv;
 
@@ -1070,7 +1089,7 @@ gbp_endpoint_cli (vlib_main_t * vm,
        add = 1;
       else if (unformat (input, "del"))
        add = 0;
-      else if (unformat (input, "epg %d", &epg_id))
+      else if (unformat (input, "sclass %d", &sclass))
        ;
       else if (unformat (input, "handle %d", &handle))
        ;
@@ -1080,6 +1099,8 @@ gbp_endpoint_cli (vlib_main_t * vm,
        vec_add1 (ips, ip);
       else if (unformat (input, "mac %U", unformat_mac_address, &mac))
        ;
+      else if (unformat (input, "flags 0x%x", &flags))
+       ;
       else
        break;
     }
@@ -1088,16 +1109,14 @@ gbp_endpoint_cli (vlib_main_t * vm,
     {
       if (~0 == sw_if_index)
        return clib_error_return (0, "interface must be specified");
-      if (EPG_INVALID == epg_id)
-       return clib_error_return (0, "EPG-ID must be specified");
+      if (SCLASS_INVALID == sclass)
+       return clib_error_return (0, "SCLASS must be specified");
 
       rv =
        gbp_endpoint_update_and_lock (GBP_ENDPOINT_SRC_CP,
                                      sw_if_index, ips, &mac,
                                      INDEX_INVALID, INDEX_INVALID,
-                                     epg_id,
-                                     GBP_ENDPOINT_FLAG_NONE,
-                                     NULL, NULL, &handle);
+                                     sclass, flags, NULL, NULL, &handle);
 
       if (rv)
        return clib_error_return (0, "GBP Endpoint update returned %d", rv);
@@ -1121,13 +1140,13 @@ gbp_endpoint_cli (vlib_main_t * vm,
  * Configure a GBP Endpoint
  *
  * @cliexpar
- * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
+ * @cliexstart{gbp endpoint del <handle> | [add] <interface> sclass <SCLASS> ip <IP> mac <MAC> [flags <flags>]}
  * @cliexend
  ?*/
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
   .path = "gbp endpoint",
-  .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
+  .short_help = "gbp endpoint del <handle> | [add] <interface> sclass <SCLASS> ip <IP> mac <MAC> [flags <flags>]",
   .function = gbp_endpoint_cli,
 };
 /* *INDENT-ON* */
@@ -1153,7 +1172,7 @@ format_gbp_endpoint_fwd (u8 * s, va_list * args)
   gbp_endpoint_fwd_t *gef = va_arg (*args, gbp_endpoint_fwd_t *);
 
   s = format (s, "fwd:");
-  s = format (s, "\n   itf:[%U]", format_gbp_itf, gef->gef_itf);
+  s = format (s, "\n   itf:[%U]", format_gbp_itf_hdl, gef->gef_itf);
   if (GBP_ENDPOINT_FLAG_NONE != gef->gef_flags)
     {
       s = format (s, " flags:%U", format_gbp_endpoint_flags, gef->gef_flags);
@@ -1187,10 +1206,8 @@ format_gbp_endpoint_loc (u8 * s, va_list * args)
   gbp_endpoint_loc_t *gel = va_arg (*args, gbp_endpoint_loc_t *);
 
   s = format (s, "%U", format_gbp_endpoint_src, gel->gel_src);
-  s =
-    format (s, "\n    %U", format_vnet_sw_if_index_name, vnet_get_main (),
-           gel->gel_sw_if_index);
-  s = format (s, " EPG:%d", gel->gel_epg);
+  s = format (s, "\n    EPG:%d [%U]", gel->gel_epg,
+             format_gbp_itf_hdl, gel->gel_itf);
 
   if (GBP_ENDPOINT_FLAG_NONE != gel->gel_flags)
     {
@@ -1241,8 +1258,8 @@ gbp_endpoint_show_one (index_t gei, void *ctx)
   return (WALK_CONTINUE);
 }
 
-static void
-gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
+static int
+gbp_endpoint_walk_ip_itf (clib_bihash_kv_24_8_t * kvp, void *arg)
 {
   ip46_address_t ip;
   vlib_main_t *vm;
@@ -1256,10 +1273,11 @@ gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
                   format_ip46_address, &ip, IP46_TYPE_ANY,
                   format_vnet_sw_if_index_name, vnet_get_main (),
                   sw_if_index, kvp->value);
+  return (BIHASH_WALK_CONTINUE);
 }
 
-static void
-gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
+static int
+gbp_endpoint_walk_mac_itf (clib_bihash_kv_16_8_t * kvp, void *arg)
 {
   mac_address_t mac;
   vlib_main_t *vm;
@@ -1273,6 +1291,7 @@ gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
                   format_mac_address_t, &mac,
                   format_vnet_sw_if_index_name, vnet_get_main (),
                   sw_if_index, kvp->value);
+  return (BIHASH_WALK_CONTINUE);
 }
 
 static clib_error_t *
@@ -1359,6 +1378,9 @@ gbp_endpoint_scan_l2 (vlib_main_t * vm)
   f64 last_start, start_time, delta_t;
   int i, j, k;
 
+  if (!gte_table->instantiated)
+    return;
+
   delta_t = 0;
   last_start = start_time = vlib_time_now (vm);
 
@@ -1376,8 +1398,8 @@ gbp_endpoint_scan_l2 (vlib_main_t * vm)
          last_start = vlib_time_now (vm);
        }
 
-      b = &gte_table->buckets[i];
-      if (b->offset == 0)
+      b = clib_bihash_get_bucket_16_8 (gte_table, i);
+      if (clib_bihash_bucket_is_empty_16_8 (b))
        continue;
       v = clib_bihash_get_value_16_8 (gte_table, b->offset);
 
@@ -1394,7 +1416,7 @@ gbp_endpoint_scan_l2 (vlib_main_t * vm)
               * Note: we may have just freed the bucket's backing
               * storage, so check right here...
               */
-             if (b->offset == 0)
+             if (clib_bihash_bucket_is_empty_16_8 (b))
                goto doublebreak;
            }
          v++;
@@ -1411,6 +1433,9 @@ gbp_endpoint_scan_l3 (vlib_main_t * vm)
   f64 last_start, start_time, delta_t;
   int i, j, k;
 
+  if (!gte_table->instantiated)
+    return;
+
   delta_t = 0;
   last_start = start_time = vlib_time_now (vm);
 
@@ -1428,8 +1453,8 @@ gbp_endpoint_scan_l3 (vlib_main_t * vm)
          last_start = vlib_time_now (vm);
        }
 
-      b = &gte_table->buckets[i];
-      if (b->offset == 0)
+      b = clib_bihash_get_bucket_24_8 (gte_table, i);
+      if (clib_bihash_bucket_is_empty_24_8 (b))
        continue;
       v = clib_bihash_get_value_24_8 (gte_table, b->offset);
 
@@ -1446,7 +1471,7 @@ gbp_endpoint_scan_l3 (vlib_main_t * vm)
               * Note: we may have just freed the bucket's backing
               * storage, so check right here...
               */
-             if (b->offset == 0)
+             if (clib_bihash_bucket_is_empty_24_8 (b))
                goto doublebreak;
            }
          v++;
@@ -1544,6 +1569,12 @@ gbp_endpoint_init (vlib_main_t * vm)
 
   gbp_ep_logger = vlib_log_register_class ("gbp", "ep");
   gbp_endpoint_fib_type = fib_node_register_new_type (&gbp_endpoint_vft);
+  gbp_fib_source_hi = fib_source_allocate ("gbp-endpoint-hi",
+                                          FIB_SOURCE_PRIORITY_HI,
+                                          FIB_SOURCE_BH_SIMPLE);
+  gbp_fib_source_low = fib_source_allocate ("gbp-endpoint-low",
+                                           FIB_SOURCE_PRIORITY_LOW,
+                                           FIB_SOURCE_BH_SIMPLE);
 
   return (NULL);
 }