GBP: learn from ARP and L2 packets 40/18040/3
authorNeale Ranns <nranns@cisco.com>
Mon, 4 Mar 2019 22:08:11 +0000 (14:08 -0800)
committerNeale Ranns <nranns@cisco.com>
Wed, 6 Mar 2019 10:31:38 +0000 (10:31 +0000)
Change-Id: I8af7bca566ec7c9bd2b72529d49e04c6e649b44a
Signed-off-by: Neale Ranns <nranns@cisco.com>
15 files changed:
extras/vom/vom/gbp_vxlan.cpp
extras/vom/vom/gbp_vxlan.hpp
extras/vom/vom/gbp_vxlan_cmds.cpp
extras/vom/vom/gbp_vxlan_cmds.hpp
src/plugins/gbp/gbp.api
src/plugins/gbp/gbp_api.c
src/plugins/gbp/gbp_bridge_domain.c
src/plugins/gbp/gbp_bridge_domain.h
src/plugins/gbp/gbp_endpoint.c
src/plugins/gbp/gbp_learn_node.c
src/plugins/gbp/gbp_vxlan.c
src/plugins/gbp/gbp_vxlan.h
src/vnet/vxlan-gbp/vxlan_gbp.h
test/test_gbp.py
test/vpp_papi_provider.py

index af4467a..76826c2 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "vom/gbp_vxlan.hpp"
+#include "vom/api_types.hpp"
 #include "vom/gbp_vxlan_cmds.hpp"
 #include "vom/interface.hpp"
 #include "vom/singular_db_funcs.hpp"
@@ -29,22 +30,28 @@ singular_db<gbp_vxlan::key_t, gbp_vxlan> gbp_vxlan::m_db;
 
 gbp_vxlan::event_handler gbp_vxlan::m_evh;
 
-gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_route_domain& grd)
+gbp_vxlan::gbp_vxlan(uint32_t vni,
+                     const gbp_route_domain& grd,
+                     const boost::asio::ip::address_v4& src)
   : interface(mk_name(vni),
               interface::type_t::UNKNOWN,
               interface::admin_state_t::UP)
   , m_vni(vni)
   , m_gbd()
   , m_grd(grd.singular())
+  , m_src(src)
 {
 }
-gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd)
+gbp_vxlan::gbp_vxlan(uint32_t vni,
+                     const gbp_bridge_domain& gbd,
+                     const boost::asio::ip::address_v4& src)
   : interface(mk_name(vni),
               interface::type_t::UNKNOWN,
               interface::admin_state_t::UP)
   , m_vni(vni)
   , m_gbd(gbd.singular())
   , m_grd()
+  , m_src(src)
 {
 }
 
@@ -53,6 +60,7 @@ gbp_vxlan::gbp_vxlan(const gbp_vxlan& vt)
   , m_vni(vt.m_vni)
   , m_gbd(vt.m_gbd)
   , m_grd(vt.m_grd)
+  , m_src(vt.m_src)
 {
 }
 
@@ -75,7 +83,7 @@ gbp_vxlan::key() const
 bool
 gbp_vxlan::operator==(const gbp_vxlan& vt) const
 {
-  return (m_vni == vt.m_vni);
+  return (m_vni == vt.m_vni && m_src == vt.m_src);
 }
 
 void
@@ -92,11 +100,11 @@ gbp_vxlan::replay()
 {
   if (rc_t::OK == m_hdl) {
     if (m_grd)
-      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
-                                                 m_grd->id()));
+      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_src, m_vni,
+                                                 false, m_grd->id()));
     else if (m_gbd)
-      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
-                                                 m_gbd->id()));
+      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_src, m_vni,
+                                                 true, m_gbd->id()));
   }
 }
 
@@ -129,11 +137,11 @@ gbp_vxlan::update(const gbp_vxlan& desired)
    */
   if (rc_t::OK != m_hdl) {
     if (m_grd)
-      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
-                                                 m_grd->id()));
+      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_src, m_vni,
+                                                 false, m_grd->id()));
     else if (m_gbd)
-      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
-                                                 m_gbd->id()));
+      HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_src, m_vni,
+                                                 true, m_gbd->id()));
   }
 }
 
@@ -176,11 +184,13 @@ gbp_vxlan::event_handler::handle_populate(const client_db::key_t& key)
   for (auto& record : *cmd) {
     auto& payload = record.get_payload();
 
+    boost::asio::ip::address_v4 src = from_api(payload.tunnel.src);
+
     if (GBP_VXLAN_TUNNEL_MODE_L3 == payload.tunnel.mode) {
       auto rd = gbp_route_domain::find(payload.tunnel.bd_rd_id);
 
       if (rd) {
-        gbp_vxlan vt(payload.tunnel.vni, *rd);
+        gbp_vxlan vt(payload.tunnel.vni, *rd, src);
         OM::commit(key, vt);
         VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
       }
@@ -188,7 +198,7 @@ gbp_vxlan::event_handler::handle_populate(const client_db::key_t& key)
       auto bd = gbp_bridge_domain::find(payload.tunnel.bd_rd_id);
 
       if (bd) {
-        gbp_vxlan vt(payload.tunnel.vni, *bd);
+        gbp_vxlan vt(payload.tunnel.vni, *bd, src);
         OM::commit(key, vt);
         VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
       }
index cae67d8..8aa4b6b 100644 (file)
@@ -38,8 +38,12 @@ public:
   /**
    * Construct a new object matching the desried state
    */
-  gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd);
-  gbp_vxlan(uint32_t vni, const gbp_route_domain& grd);
+  gbp_vxlan(uint32_t vni,
+            const gbp_bridge_domain& gbd,
+            const boost::asio::ip::address_v4& src);
+  gbp_vxlan(uint32_t vni,
+            const gbp_route_domain& grd,
+            const boost::asio::ip::address_v4& src);
 
   /*
    * Destructor
@@ -161,6 +165,7 @@ private:
   uint32_t m_vni;
   std::shared_ptr<gbp_bridge_domain> m_gbd;
   std::shared_ptr<gbp_route_domain> m_grd;
+  boost::asio::ip::address_v4 m_src;
 
   /**
    * A map of all VLAN tunnela against thier key
index a356590..86b61c1 100644 (file)
  */
 
 #include "vom/gbp_vxlan_cmds.hpp"
+#include "vom/api_types.hpp"
 
 namespace VOM {
 namespace gbp_vxlan_cmds {
 create_cmd::create_cmd(HW::item<handle_t>& item,
                        const std::string& name,
+                       const boost::asio::ip::address_v4& src,
                        uint32_t vni,
                        bool is_l2,
                        uint32_t bd_rd)
   : interface::create_cmd<vapi::Gbp_vxlan_tunnel_add>(item, name)
+  , m_src(src)
   , m_vni(vni)
   , m_is_l2(is_l2)
   , m_bd_rd(bd_rd)
@@ -42,6 +45,7 @@ create_cmd::issue(connection& con)
     payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L2;
   else
     payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L3;
+  to_api(m_src, payload.tunnel.src);
 
   VAPI_CALL(req.execute());
 
index a42a653..6422357 100644 (file)
@@ -35,6 +35,7 @@ public:
    */
   create_cmd(HW::item<handle_t>& item,
              const std::string& name,
+             const boost::asio::ip::address_v4& src,
              uint32_t vni,
              bool is_l2,
              uint32_t bd_rd);
@@ -54,6 +55,7 @@ public:
   bool operator==(const create_cmd& i) const;
 
 private:
+  boost::asio::ip::address_v4 m_src;
   uint32_t m_vni;
   bool m_is_l2;
   uint32_t m_bd_rd;
index 3478551..8343e22 100644 (file)
@@ -344,6 +344,7 @@ typedef gbp_vxlan_tunnel
   u32 vni;
   vl_api_gbp_vxlan_tunnel_mode_t mode;
   u32 bd_rd_id;
+  vl_api_ip4_address_t src;
 };
 
 define gbp_vxlan_tunnel_add
index 7c36da6..ffdae28 100644 (file)
@@ -1036,9 +1036,11 @@ vl_api_gbp_vxlan_tunnel_add_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
 {
   vl_api_gbp_vxlan_tunnel_add_reply_t *rmp;
   gbp_vxlan_tunnel_layer_t layer;
+  ip4_address_t src;
   u32 sw_if_index;
   int rv = 0;
 
+  ip4_address_decode (mp->tunnel.src, &src);
   rv = gbp_vxlan_tunnel_mode_2_layer (mp->tunnel.mode, &layer);
 
   if (0 != rv)
@@ -1046,7 +1048,7 @@ vl_api_gbp_vxlan_tunnel_add_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
 
   rv = gbp_vxlan_tunnel_add (ntohl (mp->tunnel.vni),
                             layer,
-                            ntohl (mp->tunnel.bd_rd_id), &sw_if_index);
+                            ntohl (mp->tunnel.bd_rd_id), &src, &sw_if_index);
 
 out:
   /* *INDENT-OFF* */
index 261b568..24bfb25 100644 (file)
@@ -16,6 +16,7 @@
 #include <plugins/gbp/gbp_bridge_domain.h>
 #include <plugins/gbp/gbp_endpoint.h>
 #include <plugins/gbp/gbp_sclass.h>
+#include <plugins/gbp/gbp_learn.h>
 
 #include <vnet/dpo/dvr_dpo.h>
 #include <vnet/fib/fib_table.h>
@@ -125,7 +126,7 @@ format_gbp_bridge_domain_flags (u8 * s, va_list * args)
     }
   else
     {
-      s = format (s, "noe");
+      s = format (s, "none");
     }
   return (s);
 }
@@ -218,6 +219,7 @@ gbp_bridge_domain_add_and_lock (u32 bd_id,
                           MODE_L2_BRIDGE, gb->gb_bm_flood_sw_if_index,
                           bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
          gbp_sclass_enable_l2 (gb->gb_bm_flood_sw_if_index);
+         gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
        }
 
       /*
@@ -275,6 +277,7 @@ gbp_bridge_domain_unlock (index_t index)
                           MODE_L3, gb->gb_bm_flood_sw_if_index,
                           gb->gb_bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
          gbp_sclass_disable_l2 (gb->gb_bm_flood_sw_if_index);
+         gbp_learn_enable (gb->gb_bm_flood_sw_if_index, GBP_LEARN_MODE_L2);
        }
 
       gbp_bridge_domain_db_remove (gb);
index 25498ee..8e6146c 100644 (file)
@@ -63,10 +63,10 @@ typedef struct gbp_bridge_domain_t_
   u32 gb_bm_flood_sw_if_index;
 
   /**
-   * The BD's VNI interface on which packets from unkown endpoints
-   * arrive
+   * The index of the BD's VNI interface on which packets from
+   * unkown endpoints arrive
    */
-  u32 gb_vni_sw_if_index;
+  u32 gb_vni;
 
   /**
    * locks/references to the BD so it does not get deleted (from the API)
index 9cae2ab..4bd726f 100644 (file)
@@ -32,6 +32,7 @@
 #include <vnet/fib/fib_table.h>
 #include <vnet/ip/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;
 
@@ -473,6 +474,7 @@ gbp_endpoint_n_learned (int n)
 
 static void
 gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
+                        const gbp_bridge_domain_t * gb,
                         u32 sw_if_index,
                         index_t ggi,
                         gbp_endpoint_flags_t flags,
@@ -508,6 +510,24 @@ 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
@@ -862,7 +882,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 (gel, gbd, sw_if_index, ggi, flags, tun_src,
+                          tun_dst);
 
   if (src <= best)
     {
index ebb1217..461d209 100644 (file)
@@ -22,6 +22,7 @@
 #include <vnet/l2/l2_input.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
+#include <vnet/ethernet/arp_packet.h>
 
 #define GBP_LEARN_DBG(...)                                      \
     vlib_log_debug (gbp_learn_main.gl_logger, __VA_ARGS__);
@@ -72,10 +73,8 @@ gbp_learn_l2_cp (const gbp_learn_l2_t * gl2)
                 format_mac_address_t, &gl2->mac,
                 format_ip46_address, &gl2->ip, IP46_TYPE_ANY, gl2->epg);
 
-  vec_add1 (ips, gl2->ip);
-
-  ASSERT (!ip46_address_is_zero (&gl2->outer_src));
-  ASSERT (!ip46_address_is_zero (&gl2->outer_dst));
+  if (!ip46_address_is_zero (&gl2->ip))
+    vec_add1 (ips, gl2->ip);
 
   /*
    * flip the source and dst, since that's how it was received, this API
@@ -107,9 +106,6 @@ gbp_learn_l2_ip4_dp (const u8 * mac, const ip4_address_t * ip,
   };
   mac_address_from_bytes (&gl2.mac, mac);
 
-  ASSERT (!ip46_address_is_zero (&gl2.outer_src));
-  ASSERT (!ip46_address_is_zero (&gl2.outer_dst));
-
   vl_api_rpc_call_main_thread (gbp_learn_l2_cp, (u8 *) & gl2, sizeof (gl2));
 }
 
@@ -260,6 +256,12 @@ VLIB_NODE_FN (gbp_learn_l2_node) (vlib_main_t * vm,
                {
                  gbp_learn_get_outer (eh0, &outer_src, &outer_dst);
 
+                 if (outer_src.as_u32 == 0 || outer_dst.as_u32 == 0)
+                   {
+                     t0 = 2;
+                     goto trace;
+                   }
+
                  switch (clib_net_to_host_u16 (eh0->type))
                    {
                    case ETHERNET_TYPE_IP4:
@@ -290,6 +292,19 @@ VLIB_NODE_FN (gbp_learn_l2_node) (vlib_main_t * vm,
 
                        break;
                      }
+                   case ETHERNET_TYPE_ARP:
+                     {
+                       const ethernet_arp_header_t *arp0;
+
+                       arp0 = (ethernet_arp_header_t *) (eh0 + 1);
+
+                       gbp_learn_l2_ip4_dp (eh0->src_address,
+                                            &arp0->ip4_over_ethernet[0].ip4,
+                                            vnet_buffer (b0)->l2.bd_index,
+                                            sw_if_index0, epg0,
+                                            &outer_src, &outer_dst);
+                       break;
+                     }
                    default:
                      gbp_learn_l2_dp (eh0->src_address,
                                       vnet_buffer (b0)->l2.bd_index,
index 846ea0f..c0e88fd 100644 (file)
@@ -465,7 +465,8 @@ VNET_HW_INTERFACE_CLASS (gbp_vxlan_hw_interface_class) = {
 
 int
 gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
-                     u32 bd_rd_id, u32 * sw_if_indexp)
+                     u32 bd_rd_id,
+                     const ip4_address_t * src, u32 * sw_if_indexp)
 {
   gbp_vxlan_tunnel_t *gt;
   index_t gti;
@@ -512,6 +513,7 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
       gt->gt_vni = vni;
       gt->gt_layer = layer;
       gt->gt_bd_rd_id = bd_rd_id;
+      gt->gt_src.ip4.as_u32 = src->as_u32;
       gt->gt_hw_if_index = vnet_register_interface (vnm,
                                                    gbp_vxlan_device_class.index,
                                                    gti,
@@ -534,7 +536,7 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
 
          gt->gt_gbd = gbi;
          gt->gt_bd_index = gb->gb_bd_index;
-         gb->gb_vni_sw_if_index = gt->gt_sw_if_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);
@@ -571,7 +573,8 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
        */
       hash_set (gv_db, vni, gti);
 
-      vec_validate (gbp_vxlan_tunnel_db, gt->gt_sw_if_index);
+      vec_validate_init_empty (gbp_vxlan_tunnel_db,
+                              gt->gt_sw_if_index, INDEX_INVALID);
       gbp_vxlan_tunnel_db[gt->gt_sw_if_index] = gti;
 
       if (sw_if_indexp)
index acf5f4b..908abc2 100644 (file)
@@ -82,6 +82,11 @@ typedef struct gbp_vxlan_tunnel_t_
    * list of child vxlan-gbp tunnels built from this template
    */
   index_t *gt_tuns;
+
+  /**
+   * The source address to use for child tunnels
+   */
+  ip46_address_t gt_src;
 } gbp_vxlan_tunnel_t;
 
 /**
@@ -103,7 +108,9 @@ typedef enum gbp_vxlan_tunnel_type_t_
 } gbp_vxlan_tunnel_type_t;
 
 extern int gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
-                                u32 bd_rd_id, u32 * sw_if_indexp);
+                                u32 bd_rd_id,
+                                const ip4_address_t * src,
+                                u32 * sw_if_indexp);
 extern int gbp_vxlan_tunnel_del (u32 vni);
 
 extern gbp_vxlan_tunnel_type_t gbp_vxlan_tunnel_get_type (u32 sw_if_index);
index 66f0cff..6dc6225 100644 (file)
@@ -221,8 +221,6 @@ int vnet_vxlan_gbp_tunnel_del (u32 sw_if_indexp);
 void vnet_int_vxlan_gbp_bypass_mode (u32 sw_if_index, u8 is_ip6,
                                     u8 is_enable);
 
-u32 vnet_vxlan_gbp_get_tunnel_index (u32 sw_if_index);
-
 #endif /* included_vnet_vxlan_gbp_h */
 
 /*
index d716ab2..1b23cff 100644 (file)
@@ -505,18 +505,20 @@ class VppGbpVxlanTunnel(VppInterface):
     GBP VXLAN tunnel
     """
 
-    def __init__(self, test, vni, bd_rd_id, mode):
+    def __init__(self, test, vni, bd_rd_id, mode, src):
         super(VppGbpVxlanTunnel, self).__init__(test)
         self._test = test
         self.vni = vni
         self.bd_rd_id = bd_rd_id
         self.mode = mode
+        self.src = src
 
     def add_vpp_config(self):
         r = self._test.vapi.gbp_vxlan_tunnel_add(
             self.vni,
             self.bd_rd_id,
-            self.mode)
+            self.mode,
+            self.src)
         self.set_sw_if_index(r.sw_if_index)
         self._test.registry.register(self, self._test.logger)
 
@@ -527,7 +529,7 @@ class VppGbpVxlanTunnel(VppInterface):
         return self.object_id()
 
     def object_id(self):
-        return "gbp-vxlan:%d" % (self.vni)
+        return "gbp-vxlan:%d" % (self.sw_if_index)
 
     def query_vpp_config(self):
         return find_gbp_vxlan(self._test, self.vni)
@@ -1538,7 +1540,8 @@ class TestGBP(VppTestCase):
         #
         vx_tun_l2_1 = VppGbpVxlanTunnel(
             self, 99, bd1.bd_id,
-            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
+            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
+            self.pg2.local_ip4)
         vx_tun_l2_1.add_vpp_config()
 
         #
@@ -1580,6 +1583,9 @@ class TestGBP(VppTestCase):
         # epg is not learnt, becasue the EPG is unknwon
         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
 
+        #
+        # Learn new EPs from IP packets
+        #
         for ii, l in enumerate(learnt):
             # a packet with an sclass from a knwon EPG
             # arriving on an unknown TEP
@@ -1617,7 +1623,7 @@ class TestGBP(VppTestCase):
 
         self.logger.info(self.vapi.cli("show gbp endpoint"))
         self.logger.info(self.vapi.cli("show gbp vxlan"))
-        self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
+        self.logger.info(self.vapi.cli("show ip mfib"))
 
         #
         # If we sleep for the threshold time, the learnt endpoints should
@@ -1627,6 +1633,95 @@ class TestGBP(VppTestCase):
             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
                                      mac=l['mac'])
 
+        #
+        # Learn new EPs from GARP packets received on the BD's mcast tunnel
+        #
+        for ii, l in enumerate(learnt):
+            # a packet with an sclass from a knwon EPG
+            # arriving on an unknown TEP
+            p = (Ether(src=self.pg2.remote_mac,
+                       dst=self.pg2.local_mac) /
+                 IP(src=self.pg2.remote_hosts[1].ip4,
+                    dst="239.1.1.1") /
+                 UDP(sport=1234, dport=48879) /
+                 VXLAN(vni=88, gpid=112, flags=0x88) /
+                 Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
+                 ARP(op="who-has",
+                     psrc=l['ip'], pdst=l['ip'],
+                     hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
+
+            rx = self.send_and_expect(self.pg4, [p], self.pg0)
+
+            # the new TEP
+            tep1_sw_if_index = find_vxlan_gbp_tunnel(
+                self,
+                self.pg2.local_ip4,
+                self.pg2.remote_hosts[1].ip4,
+                99)
+            self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+            #
+            # the EP is learnt via the learnt TEP
+            # both from its MAC and its IP
+            #
+            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['ip']))
+
+        #
+        # wait for the learnt endpoints to age out
+        #
+        for l in learnt:
+            self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
+                                     mac=l['mac'])
+
+        #
+        # Learn new EPs from L2 packets
+        #
+        for ii, l in enumerate(learnt):
+            # a packet with an sclass from a knwon EPG
+            # arriving on an unknown TEP
+            p = (Ether(src=self.pg2.remote_mac,
+                       dst=self.pg2.local_mac) /
+                 IP(src=self.pg2.remote_hosts[1].ip4,
+                    dst=self.pg2.local_ip4) /
+                 UDP(sport=1234, dport=48879) /
+                 VXLAN(vni=99, gpid=112, flags=0x88) /
+                 Ether(src=l['mac'], dst=ep.mac) /
+                 Raw('\xa5' * 100))
+
+            rx = self.send_and_expect(self.pg2, [p], self.pg0)
+
+            # the new TEP
+            tep1_sw_if_index = find_vxlan_gbp_tunnel(
+                self,
+                self.pg2.local_ip4,
+                self.pg2.remote_hosts[1].ip4,
+                99)
+            self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+            #
+            # the EP is learnt via the learnt TEP
+            # both from its MAC and its IP
+            #
+            self.assertTrue(find_gbp_endpoint(self,
+                                              vx_tun_l2_1.sw_if_index,
+                                              mac=l['mac']))
+
+        self.logger.info(self.vapi.cli("show gbp endpoint"))
+        self.logger.info(self.vapi.cli("show gbp vxlan"))
+        self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
+
+        #
+        # wait for the learnt endpoints to age out
+        #
+        for l in learnt:
+            self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
+                                     mac=l['mac'])
+
         #
         # repeat. the do not learn bit is set so the EPs are not learnt
         #
@@ -1934,7 +2029,8 @@ class TestGBP(VppTestCase):
         #
         vx_tun_l2_1 = VppGbpVxlanTunnel(
             self, 99, bd1.bd_id,
-            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
+            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
+            self.pg2.local_ip4)
         vx_tun_l2_1.add_vpp_config()
 
         #
@@ -2109,7 +2205,8 @@ class TestGBP(VppTestCase):
         #
         vx_tun_l3 = VppGbpVxlanTunnel(
             self, 101, rd1.rd_id,
-            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
+            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
+            self.pg2.local_ip4)
         vx_tun_l3.add_vpp_config()
 
         #
@@ -2905,7 +3002,8 @@ class TestGBP(VppTestCase):
         #
         vx_tun_l3 = VppGbpVxlanTunnel(
             self, 444, rd1.rd_id,
-            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
+            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
+            self.pg2.local_ip4)
         vx_tun_l3.add_vpp_config()
 
         c4 = VppGbpContract(
@@ -3114,7 +3212,8 @@ class TestGBP(VppTestCase):
         #
         vx_tun_l3 = VppGbpVxlanTunnel(
             self, 444, rd1.rd_id,
-            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
+            VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
+            self.pg2.local_ip4)
         vx_tun_l3.add_vpp_config()
 
         #
index 2188ed3..9955518 100644 (file)
@@ -3715,14 +3715,15 @@ class VppPapiProvider(object):
         """ GBP contract Dump """
         return self.api(self.papi.gbp_contract_dump, {})
 
-    def gbp_vxlan_tunnel_add(self, vni, bd_rd_id, mode):
+    def gbp_vxlan_tunnel_add(self, vni, bd_rd_id, mode, src):
         """ GBP VXLAN tunnel add """
         return self.api(self.papi.gbp_vxlan_tunnel_add,
                         {
                             'tunnel': {
                                 'vni': vni,
                                 'mode': mode,
-                                'bd_rd_id': bd_rd_id
+                                'bd_rd_id': bd_rd_id,
+                                'src': src
                             }
                         })