gbp: Ownership of dynamically created vxlan-gbp tunnels managed via gbp_itf 43/20543/7
authorNeale Ranns <nranns@cisco.com>
Fri, 5 Jul 2019 07:53:45 +0000 (00:53 -0700)
committerNeale Ranns <nranns@cisco.com>
Tue, 9 Jul 2019 15:45:52 +0000 (15:45 +0000)
Type: fix

This solves the ownership of vxlan-gbp tunnels. When the last reference of these goes away they need to be deleted. Currently there are two owners; gbp_itf via gef_itf and the lock held by the gbp_endpoint_location_t. The problem is that the
loc removes its reference whilst the fwd still holds the gbp_itf, and things go wrong.
This change moves the lifecycle management of the vxlan-gbp tunnel to the gbp_itf. When the last lock of the gbp_itf goes, so does the tunnel. now both the EP's loc and fwd can hold a lock on the gbp_itf and it's only removed when required.
The other change is the management of the 'user' of the gbp_itf. Since each user can enable and disable different features, it's the job of the gbp_itf to apply the combined set. determining a unique 'uesr' from the caller was near impossible, so I moved that to the gbp_itf, and return the allocated user, hence the 'handle' that encodes both user and interface.

The hash table maps from sw_if_index to pool index.

Change-Id: I4c7bf4c0e5dcf33d1c545f262365e69151febcf4
Signed-off-by: Neale Ranns <nranns@cisco.com>
21 files changed:
src/plugins/gbp/gbp_api.c
src/plugins/gbp/gbp_bridge_domain.c
src/plugins/gbp/gbp_bridge_domain.h
src/plugins/gbp/gbp_contract.c
src/plugins/gbp/gbp_endpoint.c
src/plugins/gbp/gbp_endpoint.h
src/plugins/gbp/gbp_endpoint_group.c
src/plugins/gbp/gbp_endpoint_group.h
src/plugins/gbp/gbp_ext_itf.c
src/plugins/gbp/gbp_ext_itf.h
src/plugins/gbp/gbp_itf.c
src/plugins/gbp/gbp_itf.h
src/plugins/gbp/gbp_learn.c
src/plugins/gbp/gbp_learn.h
src/plugins/gbp/gbp_learn_node.c
src/plugins/gbp/gbp_recirc.c
src/plugins/gbp/gbp_recirc.h
src/plugins/gbp/gbp_route_domain.h
src/plugins/gbp/gbp_vxlan.c
src/plugins/gbp/gbp_vxlan.h
test/test_gbp.py

index 7c7026a..0945547 100644 (file)
@@ -240,7 +240,8 @@ gbp_endpoint_send_details (index_t gei, void *args)
     }
   else
     {
-      mp->endpoint.sw_if_index = ntohl (gef->gef_itf);
+      mp->endpoint.sw_if_index =
+       ntohl (gbp_itf_get_sw_if_index (gef->gef_itf));
     }
   mp->endpoint.sclass = ntohs (ge->ge_fwd.gef_sclass);
   mp->endpoint.n_ips = n_ips;
@@ -588,7 +589,8 @@ gbp_bridge_domain_send_details (gbp_bridge_domain_t * gb, void *args)
   mp->bd.rd_id = ntohl (gr->grd_id);
   mp->bd.bvi_sw_if_index = ntohl (gb->gb_bvi_sw_if_index);
   mp->bd.uu_fwd_sw_if_index = ntohl (gb->gb_uu_fwd_sw_if_index);
-  mp->bd.bm_flood_sw_if_index = ntohl (gb->gb_bm_flood_sw_if_index);
+  mp->bd.bm_flood_sw_if_index =
+    ntohl (gbp_itf_get_sw_if_index (gb->gb_bm_flood_itf));
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
@@ -763,7 +765,7 @@ gbp_ext_itf_send_details (gbp_ext_itf_t * gx, void *args)
   mp->ext_itf.flags = ntohl (gx->gx_flags);
   mp->ext_itf.bd_id = ntohl (gbp_bridge_domain_get_bd_id (gx->gx_bd));
   mp->ext_itf.rd_id = ntohl (gbp_route_domain_get_rd_id (gx->gx_rd));
-  mp->ext_itf.sw_if_index = ntohl (gx->gx_itf);
+  mp->ext_itf.sw_if_index = ntohl (gbp_itf_get_sw_if_index (gx->gx_itf));
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
index 3e6d7ef..f2a56d7 100644 (file)
@@ -17,6 +17,7 @@
 #include <plugins/gbp/gbp_route_domain.h>
 #include <plugins/gbp/gbp_endpoint.h>
 #include <plugins/gbp/gbp_learn.h>
+#include <plugins/gbp/gbp_itf.h>
 
 #include <vnet/dpo/dvr_dpo.h>
 #include <vnet/fib/fib_table.h>
@@ -149,13 +150,14 @@ format_gbp_bridge_domain_ptr (u8 * s, va_list * args)
   vnet_main_t *vnm = vnet_get_main ();
 
   if (NULL != gb)
-    s = format (s, "[%d] bd:[%d,%d], bvi:%U uu-flood:%U flags:%U locks:%d",
-               gb - gbp_bridge_domain_pool,
-               gb->gb_bd_id,
-               gb->gb_bd_index,
-               format_vnet_sw_if_index_name, vnm, gb->gb_bvi_sw_if_index,
-               format_vnet_sw_if_index_name, vnm, gb->gb_uu_fwd_sw_if_index,
-               format_gbp_bridge_domain_flags, gb->gb_flags, gb->gb_locks);
+    s =
+      format (s,
+             "[%d] bd:[%d,%d], bvi:%U uu-flood:%U bm-flood:%U flags:%U locks:%d",
+             gb - gbp_bridge_domain_pool, gb->gb_bd_id, gb->gb_bd_index,
+             format_vnet_sw_if_index_name, vnm, gb->gb_bvi_sw_if_index,
+             format_vnet_sw_if_index_name, vnm, gb->gb_uu_fwd_sw_if_index,
+             format_gbp_itf_hdl, gb->gb_bm_flood_itf,
+             format_gbp_bridge_domain_flags, gb->gb_flags, gb->gb_locks);
   else
     s = format (s, "NULL");
 
@@ -174,28 +176,6 @@ format_gbp_bridge_domain (u8 * s, va_list * args)
   return (s);
 }
 
-void
-gbp_bridge_domain_itf_add (u32 sw_if_index, u32 bd_index,
-                          l2_bd_port_type_t type)
-{
-  set_int_l2_mode (vlib_get_main (), vnet_get_main (), MODE_L2_BRIDGE,
-                  sw_if_index, bd_index, type, 0, 0);
-  /*
-   * adding an interface to the bridge enable learning on the
-   * interface. Disable learning on the interface by default for gbp
-   * interfaces
-   */
-  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_LEARN, 0);
-}
-
-void
-gbp_bridge_domain_itf_del (u32 sw_if_index, u32 bd_index,
-                          l2_bd_port_type_t type)
-{
-  set_int_l2_mode (vlib_get_main (), vnet_get_main (), MODE_L3, sw_if_index,
-                  bd_index, type, 0, 0);
-}
-
 int
 gbp_bridge_domain_add_and_lock (u32 bd_id,
                                u32 rd_id,
@@ -228,11 +208,12 @@ gbp_bridge_domain_add_and_lock (u32 bd_id,
       pool_get (gbp_bridge_domain_pool, gb);
       memset (gb, 0, sizeof (*gb));
 
+      gbi = gb - gbp_bridge_domain_pool;
       gb->gb_bd_id = bd_id;
       gb->gb_bd_index = bd_index;
       gb->gb_uu_fwd_sw_if_index = uu_fwd_sw_if_index;
       gb->gb_bvi_sw_if_index = bvi_sw_if_index;
-      gb->gb_bm_flood_sw_if_index = bm_flood_sw_if_index;
+      gbp_itf_hdl_reset (&gb->gb_bm_flood_itf);
       gb->gb_locks = 1;
       gb->gb_flags = flags;
       gb->gb_rdi = gbp_route_domain_find_and_lock (rd_id);
@@ -247,20 +228,21 @@ gbp_bridge_domain_add_and_lock (u32 bd_id,
       /*
        * Set the BVI and uu-flood interfaces into the BD
        */
-      gbp_bridge_domain_itf_add (gb->gb_bvi_sw_if_index, bd_index,
+      gbp_bridge_domain_itf_add (gbi, gb->gb_bvi_sw_if_index,
                                 L2_BD_PORT_TYPE_BVI);
 
-      if ((!(flags & GBP_BD_FLAG_UU_FWD_DROP)
-          || (flags & GBP_BD_FLAG_UCAST_ARP))
-         && ~0 != gb->gb_uu_fwd_sw_if_index)
-       gbp_bridge_domain_itf_add (gb->gb_uu_fwd_sw_if_index, bd_index,
+      if ((!(flags & GBP_BD_FLAG_UU_FWD_DROP) ||
+          (flags & GBP_BD_FLAG_UCAST_ARP)) &&
+         ~0 != gb->gb_uu_fwd_sw_if_index)
+       gbp_bridge_domain_itf_add (gbi, gb->gb_uu_fwd_sw_if_index,
                                   L2_BD_PORT_TYPE_UU_FWD);
-      if (!(flags & GBP_BD_FLAG_MCAST_DROP)
-         && ~0 != gb->gb_bm_flood_sw_if_index)
+
+      if (!(flags & GBP_BD_FLAG_MCAST_DROP) && ~0 != bm_flood_sw_if_index)
        {
-         gbp_bridge_domain_itf_add (gb->gb_bm_flood_sw_if_index, bd_index,
-                                    L2_BD_PORT_TYPE_NORMAL);
-         gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
+         gb->gb_bm_flood_itf =
+           gbp_itf_l2_add_and_lock (bm_flood_sw_if_index, gbi);
+         gbp_itf_l2_set_input_feature (gb->gb_bm_flood_itf,
+                                       L2INPUT_FEAT_GBP_LEARN);
        }
 
       /*
@@ -297,11 +279,41 @@ gbp_bridge_domain_add_and_lock (u32 bd_id,
 }
 
 void
-gbp_bridge_domain_unlock (index_t index)
+gbp_bridge_domain_itf_add (index_t gbdi,
+                          u32 sw_if_index, l2_bd_port_type_t type)
+{
+  gbp_bridge_domain_t *gb;
+
+  gb = gbp_bridge_domain_get (gbdi);
+
+  set_int_l2_mode (vlib_get_main (), vnet_get_main (), MODE_L2_BRIDGE,
+                  sw_if_index, gb->gb_bd_index, type, 0, 0);
+  /*
+   * adding an interface to the bridge enables learning on the
+   * interface. Disable learning on the interface by default for gbp
+   * interfaces
+   */
+  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_LEARN, 0);
+}
+
+void
+gbp_bridge_domain_itf_del (index_t gbdi,
+                          u32 sw_if_index, l2_bd_port_type_t type)
 {
   gbp_bridge_domain_t *gb;
 
-  gb = gbp_bridge_domain_get (index);
+  gb = gbp_bridge_domain_get (gbdi);
+
+  set_int_l2_mode (vlib_get_main (), vnet_get_main (), MODE_L3, sw_if_index,
+                  gb->gb_bd_index, type, 0, 0);
+}
+
+void
+gbp_bridge_domain_unlock (index_t gbdi)
+{
+  gbp_bridge_domain_t *gb;
+
+  gb = gbp_bridge_domain_get (gbdi);
 
   gb->gb_locks--;
 
@@ -313,17 +325,12 @@ gbp_bridge_domain_unlock (index_t index)
                       (vnet_get_main (), gb->gb_bvi_sw_if_index),
                       gb->gb_bd_index, gb->gb_bvi_sw_if_index);
 
-      gbp_bridge_domain_itf_del (gb->gb_bvi_sw_if_index, gb->gb_bd_index,
+      gbp_bridge_domain_itf_del (gbdi, gb->gb_bvi_sw_if_index,
                                 L2_BD_PORT_TYPE_BVI);
       if (~0 != gb->gb_uu_fwd_sw_if_index)
-       gbp_bridge_domain_itf_del (gb->gb_uu_fwd_sw_if_index, gb->gb_bd_index,
+       gbp_bridge_domain_itf_del (gbdi, gb->gb_uu_fwd_sw_if_index,
                                   L2_BD_PORT_TYPE_UU_FWD);
-      if (~0 != gb->gb_bm_flood_sw_if_index)
-       {
-         gbp_bridge_domain_itf_del (gb->gb_bm_flood_sw_if_index,
-                                    gb->gb_bd_index, L2_BD_PORT_TYPE_NORMAL);
-         gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
-       }
+      gbp_itf_unlock (&gb->gb_bm_flood_itf);
 
       gbp_bridge_domain_db_remove (gb);
       gbp_route_domain_unlock (gb->gb_rdi);
index 6704368..0449240 100644 (file)
@@ -17,6 +17,7 @@
 #define __GBP_BRIDGE_DOMAIN_H__
 
 #include <plugins/gbp/gbp_types.h>
+#include <plugins/gbp/gbp_itf.h>
 
 #include <vnet/fib/fib_types.h>
 #include <vnet/l2/l2_bd.h>
@@ -70,7 +71,7 @@ typedef struct gbp_bridge_domain_t_
   /**
    * The BD's interface to sned Broadcast and multicast packets
    */
-  u32 gb_bm_flood_sw_if_index;
+  gbp_itf_hdl_t gb_bm_flood_itf;
 
   /**
    * The index of the BD's VNI interface on which packets from
@@ -85,9 +86,11 @@ typedef struct gbp_bridge_domain_t_
   u32 gb_locks;
 } gbp_bridge_domain_t;
 
-extern void gbp_bridge_domain_itf_add (u32 sw_if_index, u32 bd_index,
+extern void gbp_bridge_domain_itf_add (index_t gbdi,
+                                      u32 sw_if_index,
                                       l2_bd_port_type_t type);
-extern void gbp_bridge_domain_itf_del (u32 sw_if_index, u32 bd_index,
+extern void gbp_bridge_domain_itf_del (index_t gbdi,
+                                      u32 sw_if_index,
                                       l2_bd_port_type_t type);
 
 extern int gbp_bridge_domain_add_and_lock (u32 bd_id,
index c7c2378..452c5a5 100644 (file)
@@ -275,7 +275,10 @@ gbp_contract_mk_adj (gbp_next_hop_t * gnh, fib_protocol_t fproto)
   gnh->gnh_ai[fproto] =
     adj_nbr_add_or_lock_w_rewrite (fproto,
                                   fib_proto_to_link (fproto),
-                                  &gnh->gnh_ip, ge->ge_fwd.gef_itf, rewrite);
+                                  &gnh->gnh_ip,
+                                  gbp_itf_get_sw_if_index (ge->
+                                                           ge_fwd.gef_itf),
+                                  rewrite);
 
   adj_unlock (old_ai);
 }
index d759da2..836930a 100644 (file)
@@ -264,8 +264,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 = ge->ge_fwd.gef_fib_index = 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);
 
@@ -336,11 +336,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 *
@@ -349,7 +345,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;
@@ -484,7 +480,8 @@ 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,
@@ -544,29 +541,29 @@ gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
        * 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);
     }
 }
 
@@ -578,9 +575,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;
 
@@ -609,26 +604,23 @@ gbb_endpoint_fwd_reset (gbp_endpoint_t * ge)
     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;
@@ -654,12 +646,11 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
       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))
        {
@@ -667,18 +658,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)
@@ -716,7 +708,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);
@@ -786,7 +778,8 @@ 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);
+           gbp_endpoint_add_itf (gbp_itf_get_sw_if_index (gef->gef_itf),
+                                 gei);
            if (FIB_PROTOCOL_IP4 == pfx->fp_proto)
              send_ip4_garp_w_addr (vlib_get_main (),
                                    &pfx->fp_addr.ip4,
@@ -801,7 +794,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
 
   if (gbp_endpoint_is_external (ge))
     {
-      gbp_itf_set_l2_input_feature (gef->gef_itf, gei,
+      gbp_itf_l2_set_input_feature (gef->gef_itf,
                                    L2INPUT_FEAT_GBP_LPM_CLASSIFY);
     }
   else if (gbp_endpoint_is_local (ge))
@@ -817,7 +810,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);
     }
 
   /*
@@ -901,8 +894,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, gbd, 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)
     {
@@ -1193,7 +1186,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);
@@ -1227,10 +1220,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)
     {
index 27df644..3155e7b 100644 (file)
@@ -17,6 +17,7 @@
 #define __GBP_ENDPOINT_H__
 
 #include <plugins/gbp/gbp_types.h>
+#include <plugins/gbp/gbp_itf.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ethernet/mac_address.h>
 
@@ -122,7 +123,7 @@ typedef struct gbp_endpoint_loc_t_
   /**
    * The interface on which the EP is connected
    */
-  u32 gel_sw_if_index;
+  gbp_itf_hdl_t gel_itf;
 
   /**
    * Endpoint flags
@@ -158,7 +159,7 @@ typedef struct gbp_endpoint_fwd_t_
   /**
    * The interface on which the EP is connected
    */
-  index_t gef_itf;
+  gbp_itf_hdl_t gef_itf;
 
   /**
    * The L3 adj, if created
index bacbb0c..19c05f9 100644 (file)
@@ -19,6 +19,7 @@
 #include <plugins/gbp/gbp_endpoint.h>
 #include <plugins/gbp/gbp_bridge_domain.h>
 #include <plugins/gbp/gbp_route_domain.h>
+#include <plugins/gbp/gbp_itf.h>
 
 #include <vnet/dpo/dvr_dpo.h>
 #include <vnet/fib/fib_table.h>
@@ -87,7 +88,6 @@ gbp_endpoint_group_add_and_lock (vnid_t vnid,
 
   if (INDEX_INVALID == ggi)
     {
-      gbp_bridge_domain_t *gb;
       fib_protocol_t fproto;
       index_t gbi, grdi;
 
@@ -104,16 +104,14 @@ gbp_endpoint_group_add_and_lock (vnid_t vnid,
          return (VNET_API_ERROR_NO_SUCH_FIB);
        }
 
-      gb = gbp_bridge_domain_get (gbi);
-
       pool_get_zero (gbp_endpoint_group_pool, gg);
 
       gg->gg_vnid = vnid;
       gg->gg_rd = grdi;
       gg->gg_gbd = gbi;
-      gg->gg_bd_index = gb->gb_bd_index;
 
       gg->gg_uplink_sw_if_index = uplink_sw_if_index;
+      gbp_itf_hdl_reset (&gg->gg_uplink_itf);
       gg->gg_locks = 1;
       gg->gg_sclass = sclass;
       gg->gg_retention = *retention;
@@ -138,10 +136,11 @@ gbp_endpoint_group_add_and_lock (vnid_t vnid,
           * Add the uplink to the BD
           * packets direct from the uplink have had policy applied
           */
-         gbp_bridge_domain_itf_add (gg->gg_uplink_sw_if_index,
-                                    gg->gg_bd_index, L2_BD_PORT_TYPE_NORMAL);
-         l2input_intf_bitmap_enable (gg->gg_uplink_sw_if_index,
-                                     L2INPUT_FEAT_GBP_NULL_CLASSIFY, 1);
+         gg->gg_uplink_itf =
+           gbp_itf_l2_add_and_lock (gg->gg_uplink_sw_if_index, gbi);
+
+         gbp_itf_l2_set_input_feature (gg->gg_uplink_itf,
+                                       L2INPUT_FEAT_GBP_NULL_CLASSIFY);
        }
 
       hash_set (gbp_endpoint_group_db.gg_hash_sclass,
@@ -176,13 +175,8 @@ gbp_endpoint_group_unlock (index_t ggi)
 
       gg = pool_elt_at_index (gbp_endpoint_group_pool, ggi);
 
-      if (~0 != gg->gg_uplink_sw_if_index)
-       {
-         gbp_bridge_domain_itf_del (gg->gg_uplink_sw_if_index,
-                                    gg->gg_bd_index, L2_BD_PORT_TYPE_NORMAL);
-         l2input_intf_bitmap_enable (gg->gg_uplink_sw_if_index,
-                                     L2INPUT_FEAT_GBP_NULL_CLASSIFY, 0);
-       }
+      gbp_itf_unlock (&gg->gg_uplink_itf);
+
       FOR_EACH_FIB_IP_PROTOCOL (fproto)
       {
        dpo_reset (&gg->gg_dpo[fproto]);
@@ -332,16 +326,15 @@ u8 *
 format_gbp_endpoint_group (u8 * s, va_list * args)
 {
   gbp_endpoint_group_t *gg = va_arg (*args, gbp_endpoint_group_t*);
-  vnet_main_t *vnm = vnet_get_main ();
 
   if (NULL != gg)
-    s = format (s, "[%d] %d, sclass:%d bd:[%d,%d] rd:[%d] uplink:%U retention:%U locks:%d",
+    s = format (s, "[%d] %d, sclass:%d bd:%d rd:%d uplink:%U retention:%U locks:%d",
                 gg - gbp_endpoint_group_pool,
                 gg->gg_vnid,
                 gg->gg_sclass,
-                gbp_endpoint_group_get_bd_id(gg), gg->gg_bd_index,
+                gg->gg_gbd,
                 gg->gg_rd,
-                format_vnet_sw_if_index_name, vnm, gg->gg_uplink_sw_if_index,
+                format_gbp_itf_hdl, gg->gg_uplink_itf,
                 format_gbp_endpoint_retention, &gg->gg_retention,
                 gg->gg_locks);
   else
index e0d54ea..c5fdff8 100644 (file)
@@ -17,6 +17,7 @@
 #define __GBP_ENDPOINT_GROUP_H__
 
 #include <plugins/gbp/gbp_types.h>
+#include <plugins/gbp/gbp_itf.h>
 
 #include <vnet/fib/fib_types.h>
 
@@ -48,7 +49,6 @@ typedef struct gpb_endpoint_group_t_
    * Bridge-domain ID the EPG is in
    */
   index_t gg_gbd;
-  index_t gg_bd_index;
 
   /**
    * route-domain/IP-table ID the EPG is in
@@ -64,6 +64,7 @@ typedef struct gpb_endpoint_group_t_
    * the uplink interface dedicated to the EPG
    */
   u32 gg_uplink_sw_if_index;
+  gbp_itf_hdl_t gg_uplink_itf;
 
   /**
    * The DPO used in the L3 path for forwarding internal subnets
index f3c54fc..e18bbe9 100644 (file)
@@ -44,7 +44,7 @@ format_gbp_ext_itf (u8 * s, va_list * args)
   gbp_ext_itf_t *gx = va_arg (*args, gbp_ext_itf_t *);
 
   return (format (s, "%U%s in %U",
-                 format_gbp_itf, gx->gx_itf,
+                 format_gbp_itf_hdl, gx->gx_itf,
                  (gx->gx_flags & GBP_EXT_ITF_F_ANON) ? " [anon]" : "",
                  format_gbp_bridge_domain, gx->gx_bd));
 }
@@ -85,7 +85,7 @@ gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id, u32 flags)
 
       gx->gx_bd = gbi;
       gx->gx_rd = gri;
-      gx->gx_itf = sw_if_index;
+      gbp_itf_hdl_reset (&gx->gx_itf);
 
       FOR_EACH_FIB_IP_PROTOCOL (fproto)
       {
@@ -96,14 +96,13 @@ gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id, u32 flags)
       if (flags & GBP_EXT_ITF_F_ANON)
        {
          /* add interface to the BD */
-         index_t itf = gbp_itf_add_and_lock (sw_if_index,
-                                             gbp_bridge_domain_get
-                                             (gbi)->gb_bd_index);
+         gx->gx_itf = gbp_itf_l2_add_and_lock (sw_if_index, gbi);
+
          /* setup GBP L2 features on this interface */
-         gbp_itf_set_l2_input_feature (itf, 0,
+         gbp_itf_l2_set_input_feature (gx->gx_itf,
                                        L2INPUT_FEAT_GBP_LPM_ANON_CLASSIFY |
                                        L2INPUT_FEAT_LEARN);
-         gbp_itf_set_l2_output_feature (itf, 0,
+         gbp_itf_l2_set_output_feature (gx->gx_itf,
                                         L2OUTPUT_FEAT_GBP_POLICY_LPM);
        }
 
@@ -136,9 +135,7 @@ gbp_ext_itf_delete (u32 sw_if_index)
 
       GBP_EXT_ITF_DBG ("del: %U", format_gbp_ext_itf, gx);
 
-      if (gx->gx_flags & GBP_EXT_ITF_F_ANON)
-       gbp_itf_unlock (gx->gx_itf);
-
+      gbp_itf_unlock (&gx->gx_itf);
       gbp_route_domain_unlock (gx->gx_rd);
       gbp_bridge_domain_unlock (gx->gx_bd);
 
index f3829ca..03b1992 100644 (file)
@@ -35,7 +35,7 @@ typedef struct gpb_ext_itf_t_
   /**
    * The interface
    */
-  u32 gx_itf;
+  gbp_itf_hdl_t gx_itf;
 
   /**
    * The BD this external interface is a member of
index 59c9629..a9e9225 100644 (file)
 
 #include <plugins/gbp/gbp_itf.h>
 #include <plugins/gbp/gbp_bridge_domain.h>
+#include <plugins/gbp/gbp_route_domain.h>
+
+#define foreach_gbp_itf_mode  \
+  _(L2, "l2")                 \
+  _(L3, "L3")
+
+typedef enum gbp_ift_mode_t_
+{
+#define _(s,v)  GBP_ITF_MODE_##s,
+  foreach_gbp_itf_mode
+#undef _
+} gbp_itf_mode_t;
 
 /**
  * Attributes and configurations attached to interfaces by GBP
@@ -26,100 +38,371 @@ typedef struct gbp_itf_t_
    */
   u32 gi_locks;
 
+  /**
+   * The interface this wrapper is managing
+   */
   u32 gi_sw_if_index;
-  u32 gi_bd_index;
+
+  /**
+   * The mode of the interface
+   */
+  gbp_itf_mode_t gi_mode;
+
+  /**
+   * Users of this interface - this is encoded in the user's handle
+   */
+  u32 *gi_users;
 
   /**
    * L2/L3 Features configured by each user
    */
-  u32 *gi_l2_input_fbs;
-  u32 gi_l2_input_fb;
-  u32 *gi_l2_output_fbs;
-  u32 gi_l2_output_fb;
+  u32 *gi_input_fbs;
+  u32 gi_input_fb;
+  u32 *gi_output_fbs;
+  u32 gi_output_fb;
+
+  /**
+   * function to call when the interface is deleted.
+   */
+  gbp_itf_free_fn_t gi_free_fn;
+
+  union
+  {
+    /**
+     * GBP BD or RD index
+     */
+    u32 gi_gbi;
+    index_t gi_gri;
+  };
 } gbp_itf_t;
 
-static gbp_itf_t *gbp_itfs;
+static gbp_itf_t *gbp_itf_pool;
+static uword *gbp_itf_db;
+
+static const char *gbp_itf_feat_bit_pos_to_arc[] = {
+#define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = a,
+  foreach_gdb_l3_feature
+#undef _
+};
+
+static const char *gbp_itf_feat_bit_pos_to_feat[] = {
+#define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = v,
+  foreach_gdb_l3_feature
+#undef _
+};
+
+u8 *
+format_gbp_itf_l3_feat (u8 * s, va_list * args)
+{
+  gbp_itf_l3_feat_t flags = va_arg (*args, gbp_itf_l3_feat_t);
+
+#define _(a, b, c)                              \
+  if (flags & GBP_ITF_L3_FEAT_##a)              \
+    s = format (s, "%s ", b);
+  foreach_gdb_l3_feature
+#undef _
+    return (s);
+}
+
+void
+gbp_itf_hdl_reset (gbp_itf_hdl_t * gh)
+{
+  *gh = GBP_ITF_HDL_INVALID;
+}
+
+bool
+gbp_itf_hdl_is_valid (gbp_itf_hdl_t gh)
+{
+  return (gh.gh_which != GBP_ITF_HDL_INVALID.gh_which);
+}
 
 static gbp_itf_t *
 gbp_itf_get (index_t gii)
 {
-  vec_validate (gbp_itfs, gii);
+  if (pool_is_free_index (gbp_itf_pool, gii))
+    return (NULL);
 
-  return (&gbp_itfs[gii]);
+  return (pool_elt_at_index (gbp_itf_pool, gii));
 }
 
-static index_t
-gbp_itf_get_itf (u32 sw_if_index)
+static gbp_itf_t *
+gbp_itf_find (u32 sw_if_index)
 {
-  return (sw_if_index);
+  uword *p;
+
+  p = hash_get (gbp_itf_db, sw_if_index);
+
+  if (NULL != p)
+    return (gbp_itf_get (p[0]));
+
+  return (NULL);
+}
+
+static gbp_itf_t *
+gbp_itf_find_hdl (gbp_itf_hdl_t gh)
+{
+  return (gbp_itf_find (gh.gh_which));
 }
 
-index_t
-gbp_itf_add_and_lock (u32 sw_if_index, u32 bd_index)
+u32
+gbp_itf_get_sw_if_index (gbp_itf_hdl_t hdl)
+{
+  return (hdl.gh_which);
+}
+
+static gbp_itf_hdl_t
+gbp_itf_mk_hdl (gbp_itf_t * gi)
+{
+  gbp_itf_hdl_t gh;
+  u32 *useri;
+
+  pool_get (gi->gi_users, useri);
+  *useri = 0;
+
+  gh.gh_who = useri - gi->gi_users;
+  gh.gh_which = gi->gi_sw_if_index;
+
+  return (gh);
+}
+
+static gbp_itf_hdl_t
+gbp_itf_l2_add_and_lock_i (u32 sw_if_index, index_t gbi, gbp_itf_free_fn_t ff)
 {
   gbp_itf_t *gi;
 
-  gi = gbp_itf_get (gbp_itf_get_itf (sw_if_index));
+  gi = gbp_itf_find (sw_if_index);
 
-  if (0 == gi->gi_locks)
+  if (NULL == gi)
     {
+      pool_get_zero (gbp_itf_pool, gi);
+
       gi->gi_sw_if_index = sw_if_index;
-      gi->gi_bd_index = bd_index;
+      gi->gi_gbi = gbi;
+      gi->gi_mode = GBP_ITF_MODE_L2;
+      gi->gi_free_fn = ff;
 
-      if (~0 != gi->gi_bd_index)
-       gbp_bridge_domain_itf_add (sw_if_index, bd_index,
-                                  L2_BD_PORT_TYPE_NORMAL);
+      gbp_bridge_domain_itf_add (gi->gi_gbi, gi->gi_sw_if_index,
+                                L2_BD_PORT_TYPE_NORMAL);
+
+      hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool);
     }
 
   gi->gi_locks++;
 
-  return (sw_if_index);
+  return (gbp_itf_mk_hdl (gi));
+}
+
+gbp_itf_hdl_t
+gbp_itf_l2_add_and_lock (u32 sw_if_index, index_t gbi)
+{
+  return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, NULL));
+}
+
+gbp_itf_hdl_t
+gbp_itf_l2_add_and_lock_w_free (u32 sw_if_index,
+                               index_t gbi, gbp_itf_free_fn_t ff)
+{
+  return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, ff));
+}
+
+gbp_itf_hdl_t
+gbp_itf_l3_add_and_lock_i (u32 sw_if_index, index_t gri, gbp_itf_free_fn_t ff)
+{
+  gbp_itf_t *gi;
+
+  gi = gbp_itf_find (sw_if_index);
+
+  if (NULL == gi)
+    {
+      const gbp_route_domain_t *grd;
+      fib_protocol_t fproto;
+
+      pool_get_zero (gbp_itf_pool, gi);
+
+      gi->gi_sw_if_index = sw_if_index;
+      gi->gi_mode = GBP_ITF_MODE_L3;
+      gi->gi_gri = gri;
+      gi->gi_free_fn = ff;
+
+      grd = gbp_route_domain_get (gi->gi_gri);
+
+      ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 1);
+      ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 1);
+
+      FOR_EACH_FIB_IP_PROTOCOL (fproto)
+       ip_table_bind (fproto, gi->gi_sw_if_index,
+                      grd->grd_table_id[fproto], 1);
+
+      hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool);
+    }
+
+  gi->gi_locks++;
+
+  return (gbp_itf_mk_hdl (gi));
+}
+
+gbp_itf_hdl_t
+gbp_itf_l3_add_and_lock (u32 sw_if_index, index_t gri)
+{
+  return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, NULL));
+}
+
+gbp_itf_hdl_t
+gbp_itf_l3_add_and_lock_w_free (u32 sw_if_index,
+                               index_t gri, gbp_itf_free_fn_t ff)
+{
+  return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, ff));
 }
 
 void
-gbp_itf_unlock (index_t gii)
+gbp_itf_lock (gbp_itf_hdl_t gh)
 {
   gbp_itf_t *gi;
 
-  gi = gbp_itf_get (gii);
+  if (!gbp_itf_hdl_is_valid (gh))
+    return;
+
+  gi = gbp_itf_find_hdl (gh);
+
+  gi->gi_locks++;
+}
+
+gbp_itf_hdl_t
+gbp_itf_clone_and_lock (gbp_itf_hdl_t gh)
+{
+  gbp_itf_t *gi;
+
+  if (!gbp_itf_hdl_is_valid (gh))
+    return (GBP_ITF_HDL_INVALID);
+
+  gi = gbp_itf_find_hdl (gh);
+
+  gi->gi_locks++;
+
+  return (gbp_itf_mk_hdl (gi));
+}
+
+void
+gbp_itf_unlock (gbp_itf_hdl_t * gh)
+{
+  gbp_itf_t *gi;
+
+  if (!gbp_itf_hdl_is_valid (*gh))
+    return;
+
+  gi = gbp_itf_find_hdl (*gh);
   ASSERT (gi->gi_locks > 0);
   gi->gi_locks--;
 
   if (0 == gi->gi_locks)
     {
-      if (~0 != gi->gi_bd_index)
-       gbp_bridge_domain_itf_del (gi->gi_sw_if_index, gi->gi_bd_index,
-                                  L2_BD_PORT_TYPE_NORMAL);
-      vec_free (gi->gi_l2_input_fbs);
-      vec_free (gi->gi_l2_output_fbs);
+      if (GBP_ITF_MODE_L2 == gi->gi_mode)
+       {
+         gbp_itf_l2_set_input_feature (*gh, L2INPUT_FEAT_NONE);
+         gbp_itf_l2_set_output_feature (*gh, L2OUTPUT_FEAT_NONE);
+         gbp_bridge_domain_itf_del (gi->gi_gbi,
+                                    gi->gi_sw_if_index,
+                                    L2_BD_PORT_TYPE_NORMAL);
+       }
+      else
+       {
+         fib_protocol_t fproto;
+
+         gbp_itf_l3_set_input_feature (*gh, GBP_ITF_L3_FEAT_NONE);
+         FOR_EACH_FIB_IP_PROTOCOL (fproto)
+           ip_table_bind (fproto, gi->gi_sw_if_index, 0, 0);
+
+         ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
+         ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 0);
+       }
+
+      hash_unset (gbp_itf_db, gi->gi_sw_if_index);
+
+      if (gi->gi_free_fn)
+       gi->gi_free_fn (gi->gi_sw_if_index);
+
+      pool_free (gi->gi_users);
+      vec_free (gi->gi_input_fbs);
+      vec_free (gi->gi_output_fbs);
 
       memset (gi, 0, sizeof (*gi));
     }
+
+  gbp_itf_hdl_reset (gh);
 }
 
 void
-gbp_itf_set_l2_input_feature (index_t gii,
-                             index_t useri, l2input_feat_masks_t feats)
+gbp_itf_l3_set_input_feature (gbp_itf_hdl_t gh, gbp_itf_l3_feat_t feats)
 {
   u32 diff_fb, new_fb, *fb, feat;
   gbp_itf_t *gi;
 
-  gi = gbp_itf_get (gii);
+  gi = gbp_itf_find_hdl (gh);
 
-  if (gi->gi_bd_index == ~0)
+  if (NULL == gi || GBP_ITF_MODE_L3 != gi->gi_mode)
     return;
 
-  vec_validate (gi->gi_l2_input_fbs, useri);
-  gi->gi_l2_input_fbs[useri] = feats;
+  vec_validate (gi->gi_input_fbs, gh.gh_who);
+  gi->gi_input_fbs[gh.gh_who] = feats;
 
   new_fb = 0;
-  vec_foreach (fb, gi->gi_l2_input_fbs)
+  vec_foreach (fb, gi->gi_input_fbs)
   {
     new_fb |= *fb;
   }
 
   /* add new features */
-  diff_fb = (gi->gi_l2_input_fb ^ new_fb) & new_fb;
+  diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
+
+  /* *INDENT-OFF* */
+  foreach_set_bit (feat, diff_fb,
+  ({
+    vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
+                                 gbp_itf_feat_bit_pos_to_feat[feat],
+                                 gi->gi_sw_if_index, 1, 0, 0);
+  }));
+  /* *INDENT-ON* */
+
+  /* remove unneeded features */
+  diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
+
+  /* *INDENT-OFF* */
+  foreach_set_bit (feat, diff_fb,
+  ({
+    vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat],
+                                 gbp_itf_feat_bit_pos_to_feat[feat],
+                                 gi->gi_sw_if_index, 0, 0, 0);
+  }));
+  /* *INDENT-ON* */
+
+  gi->gi_input_fb = new_fb;
+}
+
+void
+gbp_itf_l2_set_input_feature (gbp_itf_hdl_t gh, l2input_feat_masks_t feats)
+{
+  u32 diff_fb, new_fb, *fb, feat;
+  gbp_itf_t *gi;
+
+  gi = gbp_itf_find_hdl (gh);
+
+  if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
+    {
+      ASSERT (0);
+      return;
+    }
+
+  vec_validate (gi->gi_input_fbs, gh.gh_who);
+  gi->gi_input_fbs[gh.gh_who] = feats;
+
+  new_fb = 0;
+  vec_foreach (fb, gi->gi_input_fbs)
+  {
+    new_fb |= *fb;
+  }
+
+  /* add new features */
+  diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb;
 
   /* *INDENT-OFF* */
   foreach_set_bit (feat, diff_fb,
@@ -129,7 +412,7 @@ gbp_itf_set_l2_input_feature (index_t gii,
   /* *INDENT-ON* */
 
   /* remove unneeded features */
-  diff_fb = (gi->gi_l2_input_fb ^ new_fb) & gi->gi_l2_input_fb;
+  diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb;
 
   /* *INDENT-OFF* */
   foreach_set_bit (feat, diff_fb,
@@ -138,32 +421,34 @@ gbp_itf_set_l2_input_feature (index_t gii,
   }));
   /* *INDENT-ON* */
 
-  gi->gi_l2_input_fb = new_fb;
+  gi->gi_input_fb = new_fb;
 }
 
 void
-gbp_itf_set_l2_output_feature (index_t gii,
-                              index_t useri, l2output_feat_masks_t feats)
+gbp_itf_l2_set_output_feature (gbp_itf_hdl_t gh, l2output_feat_masks_t feats)
 {
   u32 diff_fb, new_fb, *fb, feat;
   gbp_itf_t *gi;
 
-  gi = gbp_itf_get (gii);
+  gi = gbp_itf_find_hdl (gh);
 
-  if (gi->gi_bd_index == ~0)
-    return;
+  if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode)
+    {
+      ASSERT (0);
+      return;
+    }
 
-  vec_validate (gi->gi_l2_output_fbs, useri);
-  gi->gi_l2_output_fbs[useri] = feats;
+  vec_validate (gi->gi_output_fbs, gh.gh_who);
+  gi->gi_output_fbs[gh.gh_who] = feats;
 
   new_fb = 0;
-  vec_foreach (fb, gi->gi_l2_output_fbs)
+  vec_foreach (fb, gi->gi_output_fbs)
   {
     new_fb |= *fb;
   }
 
   /* add new features */
-  diff_fb = (gi->gi_l2_output_fb ^ new_fb) & new_fb;
+  diff_fb = (gi->gi_output_fb ^ new_fb) & new_fb;
 
   /* *INDENT-OFF* */
   foreach_set_bit (feat, diff_fb,
@@ -173,7 +458,7 @@ gbp_itf_set_l2_output_feature (index_t gii,
   /* *INDENT-ON* */
 
   /* remove unneeded features */
-  diff_fb = (gi->gi_l2_output_fb ^ new_fb) & gi->gi_l2_output_fb;
+  diff_fb = (gi->gi_output_fb ^ new_fb) & gi->gi_output_fb;
 
   /* *INDENT-OFF* */
   foreach_set_bit (feat, diff_fb,
@@ -182,27 +467,69 @@ gbp_itf_set_l2_output_feature (index_t gii,
   }));
   /* *INDENT-ON* */
 
-  gi->gi_l2_output_fb = new_fb;
+  gi->gi_output_fb = new_fb;
 }
 
-u8 *
+static u8 *
+format_gbp_itf_mode (u8 * s, va_list * args)
+{
+  gbp_itf_mode_t mode = va_arg (*args, gbp_itf_mode_t);
+
+  switch (mode)
+    {
+#define _(a,v)                                  \
+    case GBP_ITF_MODE_##a:                      \
+      return format(s, "%s", v);
+      foreach_gbp_itf_mode
+#undef _
+    }
+  return (s);
+}
+
+static u8 *
 format_gbp_itf (u8 * s, va_list * args)
 {
   index_t gii = va_arg (*args, index_t);
   gbp_itf_t *gi;
 
+  if (INDEX_INVALID == gii)
+    return (format (s, "unset"));
+
   gi = gbp_itf_get (gii);
 
-  s = format (s, "%U locks:%d bd-index:%d input-feats:%U output-feats:%U",
+  s = format (s, "%U locks:%d mode:%U ",
              format_vnet_sw_if_index_name, vnet_get_main (),
              gi->gi_sw_if_index, gi->gi_locks,
-             gi->gi_bd_index,
-             format_l2_input_features, gi->gi_l2_input_fb, 0,
-             format_l2_output_features, gi->gi_l2_output_fb, 0);
+             format_gbp_itf_mode, gi->gi_mode);
+
+  if (GBP_ITF_MODE_L2 == gi->gi_mode)
+    s = format (s, "gbp-bd:%d input-feats:[%U] output-feats:[%U]",
+               gi->gi_gbi,
+               format_l2_input_features, gi->gi_input_fb, 0,
+               format_l2_output_features, gi->gi_output_fb, 0);
+  else
+    s = format (s, "gbp-rd:%d input-feats:[%U] output-feats:[%U]",
+               gi->gi_gbi,
+               format_gbp_itf_l3_feat, gi->gi_input_fb,
+               format_gbp_itf_l3_feat, gi->gi_output_fb);
 
   return (s);
 }
 
+u8 *
+format_gbp_itf_hdl (u8 * s, va_list * args)
+{
+  gbp_itf_hdl_t gh = va_arg (*args, gbp_itf_hdl_t);
+  gbp_itf_t *gi;
+
+  gi = gbp_itf_find_hdl (gh);
+
+  if (NULL == gi)
+    return format (s, "INVALID");
+
+  return (format (s, "%U", format_gbp_itf, gi - gbp_itf_pool));
+}
+
 static clib_error_t *
 gbp_itf_show (vlib_main_t * vm,
              unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -211,10 +538,12 @@ gbp_itf_show (vlib_main_t * vm,
 
   vlib_cli_output (vm, "Interfaces:");
 
-  vec_foreach_index (gii, gbp_itfs)
-  {
+  /* *INDENT-OFF* */
+  pool_foreach_index (gii, gbp_itf_pool,
+  ({
     vlib_cli_output (vm, "  [%d] %U", gii, format_gbp_itf, gii);
-  }
+  }));
+  /* *INDENT-ON* */
 
   return (NULL);
 }
index 6ece7b1..b0c7ed9 100644 (file)
 #include <vnet/l2/l2_input.h>
 #include <vnet/l2/l2_output.h>
 
-extern index_t gbp_itf_add_and_lock (u32 sw_if_index, u32 bd_index);
-extern void gbp_itf_unlock (index_t index);
 
-extern void gbp_itf_set_l2_input_feature (index_t gii,
-                                         index_t useri,
+#define foreach_gdb_l3_feature                  \
+  _(LEARN_IP4, "gbp-learn-ip4", "ip4-unicast") \
+  _(LEARN_IP6, "gbp-learn-ip6", "ip6-unicast")
+
+typedef enum gbp_itf_l3_feat_pos_t_
+{
+#define _(s,v,a) GBP_ITF_L3_FEAT_POS_##s,
+  foreach_gdb_l3_feature
+#undef _
+} gbp_itf_l3_feat_pos_t;
+
+typedef enum gbp_itf_l3_feat_t_
+{
+  GBP_ITF_L3_FEAT_NONE,
+#define _(s,v,a) GBP_ITF_L3_FEAT_##s = (1 << GBP_ITF_L3_FEAT_POS_##s),
+  foreach_gdb_l3_feature
+#undef _
+} gbp_itf_l3_feat_t;
+
+#define GBP_ITF_L3_FEAT_LEARN (GBP_ITF_L3_FEAT_LEARN_IP4|GBP_ITF_L3_FEAT_LEARN_IP6)
+
+typedef struct gbp_itf_hdl_t_
+{
+  union
+  {
+    struct
+    {
+      u32 gh_who;
+      u32 gh_which;
+    };
+  };
+} gbp_itf_hdl_t;
+
+#define GBP_ITF_HDL_INIT {.gh_which = ~0}
+const static gbp_itf_hdl_t GBP_ITF_HDL_INVALID = GBP_ITF_HDL_INIT;
+
+extern void gbp_itf_hdl_reset (gbp_itf_hdl_t * gh);
+extern bool gbp_itf_hdl_is_valid (gbp_itf_hdl_t gh);
+
+typedef void (*gbp_itf_free_fn_t) (u32 sw_if_index);
+
+extern gbp_itf_hdl_t gbp_itf_l2_add_and_lock (u32 sw_if_index, u32 bd_index);
+extern gbp_itf_hdl_t gbp_itf_l3_add_and_lock (u32 sw_if_index, index_t gri);
+extern gbp_itf_hdl_t gbp_itf_l2_add_and_lock_w_free (u32 sw_if_index,
+                                                    u32 bd_index,
+                                                    gbp_itf_free_fn_t ff);
+extern gbp_itf_hdl_t gbp_itf_l3_add_and_lock_w_free (u32 sw_if_index,
+                                                    index_t gri,
+                                                    gbp_itf_free_fn_t ff);
+
+extern void gbp_itf_unlock (gbp_itf_hdl_t * hdl);
+extern void gbp_itf_lock (gbp_itf_hdl_t hdl);
+extern gbp_itf_hdl_t gbp_itf_clone_and_lock (gbp_itf_hdl_t hdl);
+extern u32 gbp_itf_get_sw_if_index (gbp_itf_hdl_t hdl);
+
+extern void gbp_itf_l2_set_input_feature (gbp_itf_hdl_t hdl,
                                          l2input_feat_masks_t feats);
-extern void gbp_itf_set_l2_output_feature (index_t gii,
-                                          index_t useri,
+extern void gbp_itf_l2_set_output_feature (gbp_itf_hdl_t hdl,
                                           l2output_feat_masks_t feats);
 
-extern u8 *format_gbp_itf (u8 * s, va_list * args);
+extern void gbp_itf_l3_set_input_feature (gbp_itf_hdl_t hdl,
+                                         gbp_itf_l3_feat_t feats);
+
+extern u8 *format_gbp_itf_hdl (u8 * s, va_list * args);
 
 #endif
 
index 612af98..af3a6fb 100644 (file)
 gbp_learn_main_t gbp_learn_main;
 
 void
-gbp_learn_enable (u32 sw_if_index, gbb_learn_mode_t mode)
+gbp_learn_enable (u32 sw_if_index)
 {
-  if (GBP_LEARN_MODE_L2 == mode)
-    {
-      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 1);
-    }
-  else
-    {
-      vnet_feature_enable_disable ("ip4-unicast",
-                                  "gbp-learn-ip4", sw_if_index, 1, 0, 0);
-      vnet_feature_enable_disable ("ip6-unicast",
-                                  "gbp-learn-ip6", sw_if_index, 1, 0, 0);
-    }
+  vnet_feature_enable_disable ("ip4-unicast",
+                              "gbp-learn-ip4", sw_if_index, 1, 0, 0);
+  vnet_feature_enable_disable ("ip6-unicast",
+                              "gbp-learn-ip6", sw_if_index, 1, 0, 0);
 }
 
 void
-gbp_learn_disable (u32 sw_if_index, gbb_learn_mode_t mode)
+gbp_learn_disable (u32 sw_if_index)
 {
-  if (GBP_LEARN_MODE_L2 == mode)
-    {
-      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 0);
-    }
-  else
-    {
-      vnet_feature_enable_disable ("ip4-unicast",
-                                  "gbp-learn-ip4", sw_if_index, 0, 0, 0);
-      vnet_feature_enable_disable ("ip6-unicast",
-                                  "gbp-learn-ip6", sw_if_index, 0, 0, 0);
-    }
+  vnet_feature_enable_disable ("ip4-unicast",
+                              "gbp-learn-ip4", sw_if_index, 0, 0, 0);
+  vnet_feature_enable_disable ("ip6-unicast",
+                              "gbp-learn-ip6", sw_if_index, 0, 0, 0);
 }
 
 static clib_error_t *
index 15a9fec..a000905 100644 (file)
  */
 #define GBP_ENDPOINT_HASH_LEARN_RATE (1e-2)
 
-typedef enum gbp_learn_mode_t_
-{
-  GBP_LEARN_MODE_L2,
-  GBP_LEARN_MODE_L3,
-} gbb_learn_mode_t;
-
 /**
  * Grouping of global data for the GBP source EPG classification feature
  */
@@ -53,8 +47,8 @@ typedef struct gbp_learn_main_t_
 
 extern gbp_learn_main_t gbp_learn_main;
 
-extern void gbp_learn_enable (u32 sw_if_index, gbb_learn_mode_t mode);
-extern void gbp_learn_disable (u32 sw_if_index, gbb_learn_mode_t mode);
+extern void gbp_learn_enable (u32 sw_if_index);
+extern void gbp_learn_disable (u32 sw_if_index);
 
 #endif
 
index 42d1ceb..113969a 100644 (file)
@@ -245,8 +245,8 @@ VLIB_NODE_FN (gbp_learn_l2_node) (vlib_main_t * vm,
          /*
           * check for new EP or a moved EP
           */
-         if (NULL == ge0 || ge0->ge_fwd.gef_itf != sw_if_index0)
-
+         if (NULL == ge0 ||
+             gbp_itf_get_sw_if_index (ge0->ge_fwd.gef_itf) != sw_if_index0)
            {
              /*
               * use the last 4 bytes of the mac address as the hash for the EP
index 87d0d05..2b45d48 100644 (file)
@@ -108,7 +108,7 @@ gbp_recirc_add (u32 sw_if_index, sclass_t sclass, u8 is_ext)
       /*
        * bind to the bridge-domain of the EPG
        */
-      gr->gr_itf = gbp_itf_add_and_lock (gr->gr_sw_if_index, gg->gg_bd_index);
+      gr->gr_itf = gbp_itf_l2_add_and_lock (gr->gr_sw_if_index, gg->gg_gbd);
 
       /*
        * set the interface into L2 emulation mode
@@ -211,7 +211,7 @@ gbp_recirc_delete (u32 sw_if_index)
       ip6_sw_interface_enable_disable (gr->gr_sw_if_index, 0);
       l2e_disable (gr->gr_sw_if_index);
 
-      gbp_itf_unlock (gr->gr_itf);
+      gbp_itf_unlock (&gr->gr_itf);
 
       gbp_endpoint_group_unlock (gr->gr_epgi);
       gbp_recirc_db[sw_if_index] = INDEX_INVALID;
index 3af77b4..2f3354b 100644 (file)
@@ -17,6 +17,7 @@
 #define __GBP_RECIRC_H__
 
 #include <plugins/gbp/gbp_types.h>
+#include <plugins/gbp/gbp_itf.h>
 #include <vnet/fib/fib_types.h>
 
 /**
@@ -51,7 +52,7 @@ typedef struct gpb_recirc_t_
   /**
    */
   u32 gr_sw_if_index;
-  u32 gr_itf;
+  gbp_itf_hdl_t gr_itf;
 
   /**
    * The endpoint created to represent the reric interface
index dd7adf0..897c1bd 100644 (file)
@@ -36,12 +36,6 @@ typedef struct gpb_route_domain_t_
   u32 grd_fib_index[FIB_PROTOCOL_IP_MAX];
   u32 grd_table_id[FIB_PROTOCOL_IP_MAX];
 
-  /**
-   * The RD's VNI interface on which packets from unkown endpoints
-   * arrive
-   */
-  u32 grd_vni_sw_if_index;
-
   /**
    * The interfaces on which to send packets to unnknown EPs
    */
index de635d0..643089e 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <plugins/gbp/gbp_vxlan.h>
-#include <plugins/gbp/gbp_itf.h>
 #include <plugins/gbp/gbp_learn.h>
 #include <plugins/gbp/gbp_bridge_domain.h>
 #include <plugins/gbp/gbp_route_domain.h>
@@ -30,9 +29,8 @@
  */
 typedef struct vxlan_tunnel_ref_t_
 {
+  gbp_itf_hdl_t vxr_itf;
   u32 vxr_sw_if_index;
-  index_t vxr_itf;
-  u32 vxr_locks;
   index_t vxr_parent;
   gbp_vxlan_tunnel_layer_t vxr_layer;
 } vxlan_tunnel_ref_t;
@@ -45,27 +43,27 @@ uword *gv_db;
 /**
  * Logger
  */
-vlib_log_class_t gt_logger;
+static vlib_log_class_t gt_logger;
 
 /**
  * Pool of template tunnels
  */
-gbp_vxlan_tunnel_t *gbp_vxlan_tunnel_pool;
+static gbp_vxlan_tunnel_t *gbp_vxlan_tunnel_pool;
 
 /**
  * Pool of child tunnels
  */
-vxlan_tunnel_ref_t *vxlan_tunnel_ref_pool;
+static vxlan_tunnel_ref_t *vxlan_tunnel_ref_pool;
 
 /**
  * DB of template interfaces by SW interface index
  */
-index_t *gbp_vxlan_tunnel_db;
+static index_t *gbp_vxlan_tunnel_db;
 
 /**
  * DB of child interfaces by SW interface index
  */
-index_t *vxlan_tunnel_ref_db;
+static index_t *vxlan_tunnel_ref_db;
 
 /**
  * handle registered with the ;unt infra
@@ -82,7 +80,6 @@ static char *gbp_vxlan_tunnel_layer_strings[] = {
     vlib_log_debug (gt_logger, __VA_ARGS__);
 
 
-
 gbp_vxlan_tunnel_t *
 gbp_vxlan_tunnel_get (index_t gti)
 {
@@ -103,13 +100,37 @@ format_vxlan_tunnel_ref (u8 * s, va_list * args)
 
   vxr = vxlan_tunnel_ref_get (vxri);
 
-  s = format (s, "[%U locks:%d]", format_vnet_sw_if_index_name,
-             vnet_get_main (), vxr->vxr_sw_if_index, vxr->vxr_locks);
+  s = format (s, "[%U]", format_gbp_itf_hdl, vxr->vxr_itf);
 
   return (s);
 }
 
-static u32
+static void
+gdb_vxlan_dep_del (u32 sw_if_index)
+{
+  vxlan_tunnel_ref_t *vxr;
+  gbp_vxlan_tunnel_t *gt;
+  index_t vxri;
+  u32 pos;
+
+  vxr = vxlan_tunnel_ref_get (vxlan_tunnel_ref_db[sw_if_index]);
+  vxri = vxr - vxlan_tunnel_ref_pool;
+  gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
+
+  GBP_VXLAN_TUN_DBG ("del-dep:%U", format_vxlan_tunnel_ref, vxri);
+
+  vxlan_tunnel_ref_db[vxr->vxr_sw_if_index] = INDEX_INVALID;
+  pos = vec_search (gt->gt_tuns, vxri);
+
+  ASSERT (~0 != pos);
+  vec_del1 (gt->gt_tuns, pos);
+
+  vnet_vxlan_gbp_tunnel_del (vxr->vxr_sw_if_index);
+
+  pool_put (vxlan_tunnel_ref_pool, vxr);
+}
+
+static gbp_itf_hdl_t
 gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
                   const ip46_address_t * src, const ip46_address_t * dst)
 {
@@ -136,7 +157,7 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
       vxri = vxlan_tunnel_ref_db[sw_if_index];
 
       vxr = vxlan_tunnel_ref_get (vxri);
-      vxr->vxr_locks++;
+      gbp_itf_lock (vxr->vxr_itf);
     }
   else if (0 == rv)
     {
@@ -151,7 +172,6 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
       vxri = (vxr - vxlan_tunnel_ref_pool);
       vxr->vxr_parent = gt - gbp_vxlan_tunnel_pool;
       vxr->vxr_sw_if_index = sw_if_index;
-      vxr->vxr_locks = 1;
       vxr->vxr_layer = gt->gt_layer;
 
       /*
@@ -170,8 +190,8 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
          gbp_bridge_domain_t *gbd;
 
          gbd = gbp_bridge_domain_get (gt->gt_gbd);
-         vxr->vxr_itf = gbp_itf_add_and_lock (vxr->vxr_sw_if_index,
-                                              gt->gt_bd_index);
+         vxr->vxr_itf = gbp_itf_l2_add_and_lock_w_free
+           (vxr->vxr_sw_if_index, gt->gt_gbd, gdb_vxlan_dep_del);
 
          ofeat = L2OUTPUT_FEAT_GBP_POLICY_MAC;
          ifeat = L2INPUT_FEAT_NONE;
@@ -179,27 +199,23 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
          if (!(gbd->gb_flags & GBP_BD_FLAG_DO_NOT_LEARN))
            ifeat |= L2INPUT_FEAT_GBP_LEARN;
 
-         gbp_itf_set_l2_output_feature (vxr->vxr_itf,
-                                        vxr->vxr_sw_if_index, ofeat);
-         gbp_itf_set_l2_input_feature (vxr->vxr_itf,
-                                       vxr->vxr_sw_if_index, ifeat);
+         gbp_itf_l2_set_output_feature (vxr->vxr_itf, ofeat);
+         gbp_itf_l2_set_input_feature (vxr->vxr_itf, ifeat);
        }
       else
        {
-         const gbp_route_domain_t *grd;
-         fib_protocol_t fproto;
-
-         grd = gbp_route_domain_get (gt->gt_grd);
+         vxr->vxr_itf = gbp_itf_l3_add_and_lock_w_free
+           (vxr->vxr_sw_if_index, gt->gt_grd, gdb_vxlan_dep_del);
 
-         FOR_EACH_FIB_IP_PROTOCOL (fproto)
-           ip_table_bind (fproto, vxr->vxr_sw_if_index,
-                          grd->grd_table_id[fproto], 1);
-
-         gbp_learn_enable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
+         gbp_itf_l3_set_input_feature (vxr->vxr_itf, GBP_ITF_L3_FEAT_LEARN);
        }
     }
+  else
+    {
+      return (GBP_ITF_HDL_INVALID);
+    }
 
-  return (sw_if_index);
+  return (vxr->vxr_itf);
 }
 
 u32
@@ -217,6 +233,22 @@ vxlan_gbp_tunnel_get_parent (u32 sw_if_index)
   return (gt->gt_sw_if_index);
 }
 
+gbp_itf_hdl_t
+vxlan_gbp_tunnel_lock_itf (u32 sw_if_index)
+{
+  ASSERT ((sw_if_index < vec_len (vxlan_tunnel_ref_db)) &&
+         (INDEX_INVALID != vxlan_tunnel_ref_db[sw_if_index]));
+
+  vxlan_tunnel_ref_t *vxr;
+
+  vxr = vxlan_tunnel_ref_get (vxlan_tunnel_ref_db[sw_if_index]);
+
+  gbp_itf_lock (vxr->vxr_itf);
+
+  return (vxr->vxr_itf);
+}
+
+
 gbp_vxlan_tunnel_type_t
 gbp_vxlan_tunnel_get_type (u32 sw_if_index)
 {
@@ -235,7 +267,7 @@ gbp_vxlan_tunnel_get_type (u32 sw_if_index)
   return (GBP_VXLAN_TEMPLATE_TUNNEL);
 }
 
-u32
+gbp_itf_hdl_t
 gbp_vxlan_tunnel_clone_and_lock (u32 sw_if_index,
                                 const ip46_address_t * src,
                                 const ip46_address_t * dst)
@@ -246,84 +278,26 @@ gbp_vxlan_tunnel_clone_and_lock (u32 sw_if_index,
   gti = gbp_vxlan_tunnel_db[sw_if_index];
 
   if (INDEX_INVALID == gti)
-    return (~0);
+    return (GBP_ITF_HDL_INVALID);
 
   gt = pool_elt_at_index (gbp_vxlan_tunnel_pool, gti);
 
   return (gdb_vxlan_dep_add (gt, src, dst));
 }
 
-static void
-gdb_vxlan_dep_del (index_t vxri)
-{
-  vxlan_tunnel_ref_t *vxr;
-  gbp_vxlan_tunnel_t *gt;
-  u32 pos;
-
-  vxr = vxlan_tunnel_ref_get (vxri);
-  gt = gbp_vxlan_tunnel_get (vxr->vxr_parent);
-
-  GBP_VXLAN_TUN_DBG ("del-dep:%U", format_vxlan_tunnel_ref, vxri);
-
-  vxlan_tunnel_ref_db[vxr->vxr_sw_if_index] = INDEX_INVALID;
-  pos = vec_search (gt->gt_tuns, vxri);
-
-  ASSERT (~0 != pos);
-  vec_del1 (gt->gt_tuns, pos);
-
-  if (GBP_VXLAN_TUN_L2 == vxr->vxr_layer)
-    {
-      gbp_itf_set_l2_output_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
-                                    L2OUTPUT_FEAT_NONE);
-      gbp_itf_set_l2_input_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
-                                   L2INPUT_FEAT_NONE);
-      gbp_itf_unlock (vxr->vxr_itf);
-    }
-  else
-    {
-      fib_protocol_t fproto;
-
-      FOR_EACH_FIB_IP_PROTOCOL (fproto)
-       ip_table_bind (fproto, vxr->vxr_sw_if_index, 0, 0);
-      gbp_learn_disable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
-    }
-
-  vnet_vxlan_gbp_tunnel_del (vxr->vxr_sw_if_index);
-
-  pool_put (vxlan_tunnel_ref_pool, vxr);
-}
-
 void
 vxlan_gbp_tunnel_unlock (u32 sw_if_index)
 {
-  vxlan_tunnel_ref_t *vxr;
-  index_t vxri;
+  /* vxlan_tunnel_ref_t *vxr; */
+  /* index_t vxri; */
 
-  vxri = vxlan_tunnel_ref_db[sw_if_index];
+  /* vxri = vxlan_tunnel_ref_db[sw_if_index]; */
 
-  ASSERT (vxri != INDEX_INVALID);
+  /* ASSERT (vxri != INDEX_INVALID); */
 
-  vxr = vxlan_tunnel_ref_get (vxri);
-  vxr->vxr_locks--;
+  /* vxr = vxlan_tunnel_ref_get (vxri); */
 
-  if (0 == vxr->vxr_locks)
-    {
-      gdb_vxlan_dep_del (vxri);
-    }
-}
-
-void
-vxlan_gbp_tunnel_lock (u32 sw_if_index)
-{
-  vxlan_tunnel_ref_t *vxr;
-  index_t vxri;
-
-  vxri = vxlan_tunnel_ref_db[sw_if_index];
-
-  ASSERT (vxri != INDEX_INVALID);
-
-  vxr = vxlan_tunnel_ref_get (vxri);
-  vxr->vxr_locks++;
+  /* gdb_vxlan_dep_del (vxri); */
 }
 
 void
@@ -374,23 +348,20 @@ format_gbp_vxlan_tunnel (u8 * s, va_list * args)
   gbp_vxlan_tunnel_t *gt = gbp_vxlan_tunnel_get (dev_instance);
   index_t *vxri;
 
-  s = format (s, "GBP VXLAN tunnel: hw:%d sw:%d vni:%d %U",
-             gt->gt_hw_if_index, gt->gt_sw_if_index, gt->gt_vni,
+  s = format (s, " [%d] gbp-vxlan-tunnel: hw:%d sw:%d vni:%d %U",
+             dev_instance, gt->gt_hw_if_index,
+             gt->gt_sw_if_index, gt->gt_vni,
              format_gbp_vxlan_tunnel_layer, gt->gt_layer);
   if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
-    s = format (s, " BD:%d bd-index:%d", gt->gt_bd_rd_id, gt->gt_bd_index);
+    s = format (s, " BD:%d gbd-index:%d", gt->gt_bd_rd_id, gt->gt_gbd);
   else
-    s = format (s, " RD:%d fib-index:[%d,%d]",
-               gt->gt_bd_rd_id,
-               gt->gt_fib_index[FIB_PROTOCOL_IP4],
-               gt->gt_fib_index[FIB_PROTOCOL_IP6]);
+    s = format (s, " RD:%d grd-index:%d", gt->gt_bd_rd_id, gt->gt_grd);
 
-  s = format (s, " children:[");
+  s = format (s, "   dependents:");
   vec_foreach (vxri, gt->gt_tuns)
   {
-    s = format (s, "%U, ", format_vxlan_tunnel_ref, *vxri);
+    s = format (s, "\n    %U, ", format_vxlan_tunnel_ref, *vxri);
   }
-  s = format (s, "]");
 
   return s;
 }
@@ -536,35 +507,18 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
          gb = gbp_bridge_domain_get (gbi);
 
          gt->gt_gbd = gbi;
-         gt->gt_bd_index = gb->gb_bd_index;
          gb->gb_vni = gti;
          /* set it up as a GBP interface */
-         gt->gt_itf = gbp_itf_add_and_lock (gt->gt_sw_if_index,
-                                            gt->gt_bd_index);
-         gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
+         gt->gt_itf = gbp_itf_l2_add_and_lock (gt->gt_sw_if_index,
+                                               gt->gt_gbd);
+         gbp_itf_l2_set_input_feature (gt->gt_itf, L2INPUT_FEAT_GBP_LEARN);
        }
       else
        {
-         gbp_route_domain_t *grd;
-         fib_protocol_t fproto;
-
-         grd = gbp_route_domain_get (grdi);
-
          gt->gt_grd = grdi;
-         grd->grd_vni_sw_if_index = gt->gt_sw_if_index;
-
-         gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
-
-         ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
-         ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
-
-         FOR_EACH_FIB_IP_PROTOCOL (fproto)
-         {
-           gt->gt_fib_index[fproto] = grd->grd_fib_index[fproto];
-
-           ip_table_bind (fproto, gt->gt_sw_if_index,
-                          grd->grd_table_id[fproto], 1);
-         }
+         gt->gt_itf = gbp_itf_l3_add_and_lock (gt->gt_sw_if_index,
+                                               gt->gt_grd);
+         gbp_itf_l3_set_input_feature (gt->gt_itf, GBP_ITF_L3_FEAT_LEARN);
        }
 
       /*
@@ -616,23 +570,14 @@ gbp_vxlan_tunnel_del (u32 vni)
       ASSERT (0 == vec_len (gt->gt_tuns));
       vec_free (gt->gt_tuns);
 
+      gbp_itf_unlock (&gt->gt_itf);
+
       if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
        {
-         gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
-         gbp_itf_unlock (gt->gt_itf);
          gbp_bridge_domain_unlock (gt->gt_gbd);
        }
       else
        {
-         fib_protocol_t fproto;
-
-         FOR_EACH_FIB_IP_PROTOCOL (fproto)
-           ip_table_bind (fproto, gt->gt_sw_if_index, 0, 0);
-
-         ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
-         ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
-
-         gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
          gbp_route_domain_unlock (gt->gt_grd);
        }
 
@@ -654,6 +599,9 @@ static clib_error_t *
 gbp_vxlan_show (vlib_main_t * vm,
                unformat_input_t * input, vlib_cli_command_t * cmd)
 {
+
+  vlib_cli_output (vm, "GBP-VXLAN Interfaces:");
+
   gbp_vxlan_walk (gbp_vxlan_tunnel_show_one, vm);
 
   return (NULL);
index 908abc2..6e01dc1 100644 (file)
@@ -17,6 +17,7 @@
 #define __GBP_VXLAN_H__
 
 #include <vnet/fib/fib_types.h>
+#include <plugins/gbp/gbp_itf.h>
 
 #define forecah_gbp_vxlan_tunnel_layer          \
   _(L2, "l2")                                   \
@@ -51,10 +52,6 @@ typedef struct gbp_vxlan_tunnel_t_
   {
     struct
     {
-      /**
-       * BD index (if L2)
-       */
-      u32 gt_bd_index;
       /**
        * Reference to the GPB-BD
        */
@@ -62,10 +59,6 @@ typedef struct gbp_vxlan_tunnel_t_
     };
     struct
     {
-      /**
-       * FIB inidices (if L3)
-       */
-      u32 gt_fib_index[FIB_PROTOCOL_IP_MAX];
       /**
        * References to the GBP-RD
        */
@@ -76,7 +69,7 @@ typedef struct gbp_vxlan_tunnel_t_
   /**
    * gbp-itf config for this interface
    */
-  index_t gt_itf;
+  gbp_itf_hdl_t gt_itf;
 
   /**
    * list of child vxlan-gbp tunnels built from this template
@@ -115,13 +108,14 @@ extern int gbp_vxlan_tunnel_del (u32 vni);
 
 extern gbp_vxlan_tunnel_type_t gbp_vxlan_tunnel_get_type (u32 sw_if_index);
 
-extern u32 gbp_vxlan_tunnel_clone_and_lock (u32 parent_tunnel,
-                                           const ip46_address_t * src,
-                                           const ip46_address_t * dst);
+extern gbp_itf_hdl_t gbp_vxlan_tunnel_clone_and_lock (u32 parent_tunnel,
+                                                     const ip46_address_t *
+                                                     src,
+                                                     const ip46_address_t *
+                                                     dst);
 
-extern void vxlan_gbp_tunnel_lock (u32 sw_if_index);
-extern void vxlan_gbp_tunnel_unlock (u32 sw_if_index);
 extern u32 vxlan_gbp_tunnel_get_parent (u32 sw_if_index);
+extern gbp_itf_hdl_t vxlan_gbp_tunnel_lock_itf (u32 sw_if_index);
 
 typedef walk_rc_t (*gbp_vxlan_cb_t) (gbp_vxlan_tunnel_t * gt, void *ctx);
 extern void gbp_vxlan_walk (gbp_vxlan_cb_t cb, void *ctx);
index 8b62540..9cf1817 100644 (file)
@@ -1969,10 +1969,10 @@ class TestGBP(VppTestCase):
                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
                 []),
-                VppGbpContractRule(
-                    VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
-                    VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
-                    [])],
+             VppGbpContractRule(
+                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
+                 [])],
             [ETH_P_IP, ETH_P_IPV6])
         c1.add_vpp_config()
 
@@ -1987,8 +1987,8 @@ class TestGBP(VppTestCase):
         #
         # send UU packets from the local EP
         #
-        self.logger.info(self.vapi.cli("sh bridge 1 detail"))
         self.logger.info(self.vapi.cli("sh gbp bridge"))
+        self.logger.info(self.vapi.cli("sh bridge-domain 1 detail"))
         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
                 IP(dst="10.0.0.133", src=ep.ip4.address) /
                 UDP(sport=1234, dport=1234) /
@@ -2015,6 +2015,26 @@ class TestGBP(VppTestCase):
             self.assertFalse(rx[VXLAN].gpflags.A)
             self.assertFalse(rx[VXLAN].gpflags.D)
 
+        acl = VppGbpAcl(self)
+        rule = acl.create_rule(permit_deny=1, proto=17)
+        rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
+        acl_index = acl.add_vpp_config([rule, rule2])
+        c2 = VppGbpContract(
+            self, 401, epg_330.sclass, epg_220.sclass, acl_index,
+            [VppGbpContractRule(
+                VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
+                []),
+                VppGbpContractRule(
+                    VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                    VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
+                    [])],
+            [ETH_P_IP, ETH_P_IPV6])
+        c2.add_vpp_config()
+
+        for l in learnt:
+            self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
+                                     mac=l['mac'])
         #
         # Check v6 Endpoints learning
         #
@@ -2025,17 +2045,53 @@ class TestGBP(VppTestCase):
                  IP(src=self.pg2.remote_hosts[1].ip4,
                     dst=self.pg2.local_ip4) /
                  UDP(sport=1234, dport=48879) /
-                 VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
+                 VXLAN(vni=99, gpid=113, flags=0x88) /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
                  UDP(sport=1234, dport=1234) /
                  Raw('\xa5' * 100))
 
             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
+            rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
 
-            self.assertTrue(find_gbp_endpoint(self,
-                                              vx_tun_l2_1.sw_if_index,
-                                              mac=l['mac']))
+            self.assertTrue(find_gbp_endpoint(
+                self,
+                vx_tun_l2_1.sw_if_index,
+                ip=l['ip6'],
+                tep=[self.pg2.local_ip4,
+                     self.pg2.remote_hosts[1].ip4]))
+
+        self.logger.info(self.vapi.cli("sh int"))
+        self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
+        self.logger.info(self.vapi.cli("sh gbp vxlan"))
+        self.logger.info(self.vapi.cli("sh gbp endpoint"))
+        self.logger.info(self.vapi.cli("sh gbp interface"))
+
+        #
+        # EP moves to a different TEP
+        #
+        for l in learnt:
+            # a packet with an sclass from a known EPG
+            p = (Ether(src=self.pg2.remote_mac,
+                       dst=self.pg2.local_mac) /
+                 IP(src=self.pg2.remote_hosts[2].ip4,
+                    dst=self.pg2.local_ip4) /
+                 UDP(sport=1234, dport=48879) /
+                 VXLAN(vni=99, gpid=113, flags=0x88) /
+                 Ether(src=l['mac'], dst=ep.mac) /
+                 IPv6(src=l['ip6'], dst=ep.ip6.address) /
+                 UDP(sport=1234, dport=1234) /
+                 Raw('\xa5' * 100))
+
+            rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
+            rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
+
+            self.assertTrue(find_gbp_endpoint(
+                self,
+                vx_tun_l2_1.sw_if_index,
+                mac=l['mac'],
+                tep=[self.pg2.local_ip4,
+                     self.pg2.remote_hosts[2].ip4]))
 
         #
         # v6 remote EP reachability
@@ -2050,7 +2106,7 @@ class TestGBP(VppTestCase):
 
             for rx in rxs:
                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
-                self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
+                self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
                 self.assertEqual(rx[VXLAN].gpid, 112)
@@ -2071,9 +2127,6 @@ class TestGBP(VppTestCase):
         self.pg3.unconfig_ip4()
         self.pg4.unconfig_ip4()
 
-        self.logger.info(self.vapi.cli("sh int"))
-        self.logger.info(self.vapi.cli("sh gbp vxlan"))
-
     def test_gbp_contract(self):
         """ GBP Contracts """
 
@@ -3819,9 +3872,6 @@ class TestGBP(VppTestCase):
         vlan_144.admin_up()
         # vlan_102 is not poped
 
-        ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
-        ext_itf.add_vpp_config()
-
         #
         # an unicast vxlan-gbp for inter-RD traffic
         #
@@ -4592,9 +4642,6 @@ class TestGBP(VppTestCase):
         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
 
-        ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
-        ext_itf.add_vpp_config()
-
         #
         # vlan_100 and vlan_101 are anonymous l3-out interfaces
         #