GBP: Sclass to src-epg conversions 52/16952/3
authorNeale Ranns <nranns@cisco.com>
Tue, 22 Jan 2019 07:34:18 +0000 (23:34 -0800)
committerDamjan Marion <dmarion@me.com>
Tue, 22 Jan 2019 14:37:51 +0000 (14:37 +0000)
Change-Id: Ica88268fd6a6ee01da7e9219bb4e81f22ed2fd4b
Signed-off-by: Neale Ranns <nranns@cisco.com>
28 files changed:
extras/vom/vom/gbp_bridge_domain.cpp
extras/vom/vom/gbp_bridge_domain.hpp
extras/vom/vom/gbp_bridge_domain_cmds.cpp
extras/vom/vom/gbp_bridge_domain_cmds.hpp
extras/vom/vom/gbp_endpoint_group.cpp
extras/vom/vom/gbp_endpoint_group.hpp
extras/vom/vom/gbp_endpoint_group_cmds.cpp
extras/vom/vom/gbp_endpoint_group_cmds.hpp
src/plugins/gbp/CMakeLists.txt
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_group.c
src/plugins/gbp/gbp_endpoint_group.h
src/plugins/gbp/gbp_learn.c
src/plugins/gbp/gbp_route_domain.c
src/plugins/gbp/gbp_sclass.c [new file with mode: 0644]
src/plugins/gbp/gbp_sclass.h [new file with mode: 0644]
src/plugins/gbp/gbp_types.h
src/plugins/gbp/gbp_vxlan.c
src/vnet/buffer.h
src/vnet/l2/l2_input.h
src/vnet/l2/l2_output.h
src/vnet/vxlan-gbp/decap.c
src/vnet/vxlan-gbp/encap.c
test/test_gbp.py
test/vpp_papi_provider.py

index 101209f..e370a6a 100644 (file)
@@ -47,6 +47,8 @@ gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
   : m_id(bd.id())
   , m_bd(bd.singular())
   , m_bvi(bvi.singular())
+  , m_uu_fwd()
+  , m_bm_flood()
   , m_flags(flags)
 {
 }
@@ -54,11 +56,13 @@ gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
 gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
                                      const interface& bvi,
                                      const interface& uu_fwd,
+                                     const interface& bm_flood,
                                      const flags_t& flags)
   : m_id(bd.id())
   , m_bd(bd.singular())
   , m_bvi(bvi.singular())
   , m_uu_fwd(uu_fwd.singular())
+  , m_bm_flood(bm_flood.singular())
   , m_flags(flags)
 {
 }
@@ -66,11 +70,13 @@ gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
 gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
                                      const std::shared_ptr<interface> bvi,
                                      const std::shared_ptr<interface> uu_fwd,
+                                     const std::shared_ptr<interface> bm_flood,
                                      const flags_t& flags)
   : m_id(bd.id())
   , m_bd(bd.singular())
-  , m_bvi(bvi->singular())
-  , m_uu_fwd(uu_fwd->singular())
+  , m_bvi(bvi)
+  , m_uu_fwd(uu_fwd)
+  , m_bm_flood(bm_flood)
   , m_flags(flags)
 {
 }
@@ -78,11 +84,13 @@ gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
 gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
                                      const interface& bvi,
                                      const std::shared_ptr<interface> uu_fwd,
+                                     const std::shared_ptr<interface> bm_flood,
                                      const flags_t& flags)
   : m_id(bd.id())
   , m_bd(bd.singular())
   , m_bvi(bvi.singular())
-  , m_uu_fwd(uu_fwd->singular())
+  , m_uu_fwd(uu_fwd)
+  , m_bm_flood(bm_flood)
   , m_flags(flags)
 {
 }
@@ -92,6 +100,7 @@ gbp_bridge_domain::gbp_bridge_domain(const gbp_bridge_domain& bd)
   , m_bd(bd.m_bd)
   , m_bvi(bd.m_bvi)
   , m_uu_fwd(bd.m_uu_fwd)
+  , m_bm_flood(bd.m_bm_flood)
   , m_flags(bd.m_flags)
 {
 }
@@ -139,6 +148,13 @@ gbp_bridge_domain::operator==(const gbp_bridge_domain& b) const
   else
     equal = false;
 
+  if (m_bm_flood && b.m_bm_flood)
+    equal &= (m_bm_flood->key() == b.m_bm_flood->key());
+  else if (!m_bm_flood && !b.m_bm_flood)
+    ;
+  else
+    equal = false;
+
   return ((m_bd->key() == b.m_bd->key()) && equal);
 }
 
@@ -157,7 +173,8 @@ gbp_bridge_domain::replay()
   if (rc_t::OK == m_id.rc()) {
     HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
       m_id, (m_bvi ? m_bvi->handle() : handle_t::INVALID),
-      (m_uu_fwd ? m_uu_fwd->handle() : handle_t::INVALID), m_flags));
+      (m_uu_fwd ? m_uu_fwd->handle() : handle_t::INVALID),
+      (m_bm_flood ? m_bm_flood->handle() : handle_t::INVALID), m_flags));
   }
 }
 
@@ -200,7 +217,8 @@ gbp_bridge_domain::update(const gbp_bridge_domain& desired)
   if (rc_t::OK != m_id.rc()) {
     HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
       m_id, (m_bvi ? m_bvi->handle() : handle_t::INVALID),
-      (m_uu_fwd ? m_uu_fwd->handle() : handle_t::INVALID), m_flags));
+      (m_uu_fwd ? m_uu_fwd->handle() : handle_t::INVALID),
+      (m_bm_flood ? m_bm_flood->handle() : handle_t::INVALID), m_flags));
   }
 }
 
@@ -239,11 +257,13 @@ gbp_bridge_domain::event_handler::handle_populate(const client_db::key_t& key)
 
     std::shared_ptr<interface> uu_fwd =
       interface::find(payload.bd.uu_fwd_sw_if_index);
+    std::shared_ptr<interface> bm_flood =
+      interface::find(payload.bd.bm_flood_sw_if_index);
     std::shared_ptr<interface> bvi =
       interface::find(payload.bd.bvi_sw_if_index);
 
-    if (uu_fwd && bvi) {
-      gbp_bridge_domain bd(payload.bd.bd_id, bvi, uu_fwd);
+    if (uu_fwd && bm_flood && bvi) {
+      gbp_bridge_domain bd(payload.bd.bd_id, bvi, uu_fwd, bm_flood);
       OM::commit(key, bd);
       VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
     } else if (bvi) {
index 3fcb24c..2c470aa 100644 (file)
@@ -55,14 +55,17 @@ public:
   gbp_bridge_domain(const bridge_domain& bd,
                     const interface& bvi,
                     const interface& uu_fwd,
+                    const interface& bm_flood,
                     const flags_t& flags = flags_t::NONE);
   gbp_bridge_domain(const bridge_domain& bd,
                     const std::shared_ptr<interface> bvi,
                     const std::shared_ptr<interface> uu_fwd,
+                    const std::shared_ptr<interface> bm_flood,
                     const flags_t& flags = flags_t::NONE);
   gbp_bridge_domain(const bridge_domain& bd,
                     const interface& bvi,
                     const std::shared_ptr<interface> uu_fwd,
+                    const std::shared_ptr<interface> bm_flood,
                     const flags_t& flags = flags_t::NONE);
 
   /**
@@ -188,6 +191,7 @@ private:
   std::shared_ptr<bridge_domain> m_bd;
   std::shared_ptr<interface> m_bvi;
   std::shared_ptr<interface> m_uu_fwd;
+  std::shared_ptr<interface> m_bm_flood;
   const flags_t& m_flags;
 
   /**
index 8fc5250..f5a6888 100644 (file)
@@ -21,10 +21,12 @@ namespace gbp_bridge_domain_cmds {
 create_cmd::create_cmd(HW::item<uint32_t>& item,
                        const handle_t bvi,
                        const handle_t uu_fwd,
+                       const handle_t bm_flood,
                        const gbp_bridge_domain::flags_t& flags)
   : rpc_cmd(item)
   , m_bvi(bvi)
   , m_uu_fwd(uu_fwd)
+  , m_bm_flood(bm_flood)
   , m_flags(flags)
 {
 }
@@ -34,7 +36,7 @@ create_cmd::operator==(const create_cmd& other) const
 {
   return ((m_hw_item.data() == other.m_hw_item.data()) &&
           (m_bvi == other.m_bvi) && (m_uu_fwd == other.m_uu_fwd) &&
-          (m_flags == other.m_flags));
+          (m_bm_flood == other.m_bm_flood) && (m_flags == other.m_flags));
 }
 
 rc_t
@@ -47,6 +49,7 @@ create_cmd::issue(connection& con)
   payload.bd.bd_id = m_hw_item.data();
   payload.bd.bvi_sw_if_index = m_bvi.value();
   payload.bd.uu_fwd_sw_if_index = m_uu_fwd.value();
+  payload.bd.bm_flood_sw_if_index = m_bm_flood.value();
 
   payload.bd.flags = GBP_BD_API_FLAG_NONE;
   if (gbp_bridge_domain::flags_t::DO_NOT_LEARN == m_flags)
index ec6b0a4..a4fd0d5 100644 (file)
@@ -37,6 +37,7 @@ public:
   create_cmd(HW::item<uint32_t>& item,
              const handle_t bvi,
              const handle_t uu_fwd,
+             const handle_t bm_flood,
              const gbp_bridge_domain::flags_t& flags);
 
   /**
@@ -56,6 +57,7 @@ public:
 private:
   const handle_t m_bvi;
   const handle_t m_uu_fwd;
+  const handle_t m_bm_flood;
   const gbp_bridge_domain::flags_t& m_flags;
 };
 
index e63b09f..44bdcdb 100644 (file)
@@ -30,6 +30,7 @@ gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
                                        const gbp_bridge_domain& bd)
   : m_hw(false)
   , m_epg_id(epg_id)
+  , m_sclass(0xffff)
   , m_itf(itf.singular())
   , m_rd(rd.singular())
   , m_bd(bd.singular())
@@ -41,6 +42,34 @@ gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
                                        const gbp_bridge_domain& bd)
   : m_hw(false)
   , m_epg_id(epg_id)
+  , m_sclass(0xffff)
+  , m_itf()
+  , m_rd(rd.singular())
+  , m_bd(bd.singular())
+{
+}
+
+gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
+                                       uint16_t sclass,
+                                       const interface& itf,
+                                       const gbp_route_domain& rd,
+                                       const gbp_bridge_domain& bd)
+  : m_hw(false)
+  , m_epg_id(epg_id)
+  , m_sclass(sclass)
+  , m_itf(itf.singular())
+  , m_rd(rd.singular())
+  , m_bd(bd.singular())
+{
+}
+
+gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
+                                       uint16_t sclass,
+                                       const gbp_route_domain& rd,
+                                       const gbp_bridge_domain& bd)
+  : m_hw(false)
+  , m_epg_id(epg_id)
+  , m_sclass(sclass)
   , m_itf()
   , m_rd(rd.singular())
   , m_bd(bd.singular())
@@ -50,6 +79,7 @@ gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
 gbp_endpoint_group::gbp_endpoint_group(const gbp_endpoint_group& epg)
   : m_hw(epg.m_hw)
   , m_epg_id(epg.m_epg_id)
+  , m_sclass(epg.m_sclass)
   , m_itf(epg.m_itf)
   , m_rd(epg.m_rd)
   , m_bd(epg.m_bd)
@@ -77,8 +107,8 @@ gbp_endpoint_group::id() const
 bool
 gbp_endpoint_group::operator==(const gbp_endpoint_group& gg) const
 {
-  return (key() == gg.key() && (m_itf == gg.m_itf) && (m_rd == gg.m_rd) &&
-          (m_bd == gg.m_bd));
+  return (key() == gg.key() && (m_sclass == gg.m_sclass) &&
+          (m_itf == gg.m_itf) && (m_rd == gg.m_rd) && (m_bd == gg.m_bd));
 }
 
 void
@@ -95,7 +125,7 @@ gbp_endpoint_group::replay()
 {
   if (m_hw) {
     HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
-      m_hw, m_epg_id, m_bd->id(), m_rd->id(),
+      m_hw, m_epg_id, m_sclass, m_bd->id(), m_rd->id(),
       (m_itf ? m_itf->handle() : handle_t::INVALID)));
   }
 }
@@ -105,8 +135,9 @@ gbp_endpoint_group::to_string() const
 {
   std::ostringstream s;
   s << "gbp-endpoint-group:["
-    << "epg:" << m_epg_id << ", " << (m_itf ? m_itf->to_string() : "NULL")
-    << ", " << m_bd->to_string() << ", " << m_rd->to_string() << "]";
+    << "epg:" << m_epg_id << ", sclass:" << m_sclass << ", "
+    << (m_itf ? m_itf->to_string() : "NULL") << ", " << m_bd->to_string()
+    << ", " << m_rd->to_string() << "]";
 
   return (s.str());
 }
@@ -116,7 +147,7 @@ gbp_endpoint_group::update(const gbp_endpoint_group& r)
 {
   if (rc_t::OK != m_hw.rc()) {
     HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
-      m_hw, m_epg_id, m_bd->id(), m_rd->id(),
+      m_hw, m_epg_id, m_sclass, m_bd->id(), m_rd->id(),
       (m_itf ? m_itf->handle() : handle_t::INVALID)));
   }
 }
@@ -194,12 +225,13 @@ gbp_endpoint_group::event_handler::handle_populate(const client_db::key_t& key)
                                 << payload.epg.bd_id << "]";
 
     if (itf && bd && rd) {
-      gbp_endpoint_group gbpe(payload.epg.epg_id, *itf, *rd, *bd);
+      gbp_endpoint_group gbpe(payload.epg.epg_id, payload.epg.sclass, *itf, *rd,
+                              *bd);
       OM::commit(key, gbpe);
 
       VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
     } else if (bd && rd) {
-      gbp_endpoint_group gbpe(payload.epg.epg_id, *rd, *bd);
+      gbp_endpoint_group gbpe(payload.epg.epg_id, payload.epg.sclass, *rd, *bd);
       OM::commit(key, gbpe);
 
       VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
index 4957800..b60b155 100644 (file)
@@ -51,6 +51,15 @@ public:
   gbp_endpoint_group(epg_id_t epg_id,
                      const gbp_route_domain& rd,
                      const gbp_bridge_domain& bd);
+  gbp_endpoint_group(epg_id_t epg_id,
+                     uint16_t sclass,
+                     const interface& itf,
+                     const gbp_route_domain& rd,
+                     const gbp_bridge_domain& bd);
+  gbp_endpoint_group(epg_id_t epg_id,
+                     uint16_t sclass,
+                     const gbp_route_domain& rd,
+                     const gbp_bridge_domain& bd);
 
   /**
    * Copy Construct
@@ -177,6 +186,11 @@ private:
    */
   epg_id_t m_epg_id;
 
+  /**
+   * The SClass on the wire
+   */
+  uint16_t m_sclass;
+
   /**
    * The uplink interface for the endpoint group
    */
index 45523a6..8d0e48e 100644 (file)
@@ -20,11 +20,13 @@ namespace gbp_endpoint_group_cmds {
 
 create_cmd::create_cmd(HW::item<bool>& item,
                        epg_id_t epg_id,
+                       uint16_t sclass,
                        uint32_t bd_id,
                        route::table_id_t rd_id,
                        const handle_t& itf)
   : rpc_cmd(item)
   , m_epg_id(epg_id)
+  , m_sclass(sclass)
   , m_bd_id(bd_id)
   , m_rd_id(rd_id)
   , m_itf(itf)
@@ -46,6 +48,7 @@ create_cmd::issue(connection& con)
   auto& payload = req.get_request().get_payload();
   payload.epg.uplink_sw_if_index = m_itf.value();
   payload.epg.epg_id = m_epg_id;
+  payload.epg.sclass = m_sclass;
   payload.epg.bd_id = m_bd_id;
   payload.epg.rd_id = m_rd_id;
 
index 39f69e0..2294629 100644 (file)
@@ -35,6 +35,7 @@ public:
    */
   create_cmd(HW::item<bool>& item,
              epg_id_t epg_id,
+             uint16_t sclass,
              uint32_t bd_id,
              route::table_id_t rd_id,
              const handle_t& itf);
@@ -56,6 +57,7 @@ public:
 
 private:
   const epg_id_t m_epg_id;
+  const uint16_t m_sclass;
   const uint32_t m_bd_id;
   const route::table_id_t m_rd_id;
   const handle_t m_itf;
index 4b51141..ef25402 100644 (file)
@@ -29,6 +29,7 @@ add_vpp_plugin(gbp
   gbp_recirc.c
   gbp_route_domain.c
   gbp_scanner.c
+  gbp_sclass.c
   gbp_subnet.c
   gbp_vxlan.c
 
index e96cb50..a7a9a7e 100644 (file)
@@ -31,6 +31,7 @@ typedef gbp_bridge_domain
   vl_api_gbp_bridge_domain_flags_t flags;
   u32 bvi_sw_if_index;
   u32 uu_fwd_sw_if_index;
+  u32 bm_flood_sw_if_index;
 };
 
 autoreply define gbp_bridge_domain_add
@@ -159,6 +160,7 @@ define gbp_endpoint_details
 typeonly define gbp_endpoint_group
 {
   u16 epg_id;
+  u16 sclass;
   u32 bd_id;
   u32 rd_id;
   u32 uplink_sw_if_index;
index 8d80365..665d97e 100644 (file)
@@ -298,6 +298,7 @@ static void
   int rv = 0;
 
   rv = gbp_endpoint_group_add_and_lock (ntohs (mp->epg.epg_id),
+                                       ntohs (mp->epg.sclass),
                                        ntohl (mp->epg.bd_id),
                                        ntohl (mp->epg.rd_id),
                                        ntohl (mp->epg.uplink_sw_if_index));
@@ -341,7 +342,8 @@ vl_api_gbp_bridge_domain_add_t_handler (vl_api_gbp_bridge_domain_add_t * mp)
                                       gbp_bridge_domain_flags_from_api
                                       (mp->bd.flags),
                                       ntohl (mp->bd.bvi_sw_if_index),
-                                      ntohl (mp->bd.uu_fwd_sw_if_index));
+                                      ntohl (mp->bd.uu_fwd_sw_if_index),
+                                      ntohl (mp->bd.bm_flood_sw_if_index));
 
   REPLY_MACRO (VL_API_GBP_BRIDGE_DOMAIN_ADD_REPLY + GBP_MSG_BASE);
 }
@@ -523,6 +525,7 @@ gbp_endpoint_group_send_details (gbp_endpoint_group_t * gg, void *args)
 
   mp->epg.uplink_sw_if_index = ntohl (gg->gg_uplink_sw_if_index);
   mp->epg.epg_id = ntohs (gg->gg_id);
+  mp->epg.sclass = ntohs (gg->gg_sclass);
   mp->epg.bd_id = ntohl (gbp_endpoint_group_get_bd_id (gg));
   mp->epg.rd_id = ntohl (gbp_route_domain_get_rd_id (gg->gg_rd));
 
@@ -567,6 +570,7 @@ gbp_bridge_domain_send_details (gbp_bridge_domain_t * gb, void *args)
   mp->bd.bd_id = ntohl (gb->gb_bd_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);
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
index 21ffe9c..049c89b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <plugins/gbp/gbp_bridge_domain.h>
 #include <plugins/gbp/gbp_endpoint.h>
+#include <plugins/gbp/gbp_sclass.h>
 
 #include <vnet/dpo/dvr_dpo.h>
 #include <vnet/fib/fib_table.h>
@@ -147,7 +148,9 @@ format_gbp_bridge_domain (u8 * s, va_list * args)
 int
 gbp_bridge_domain_add_and_lock (u32 bd_id,
                                gbp_bridge_domain_flags_t flags,
-                               u32 bvi_sw_if_index, u32 uu_fwd_sw_if_index)
+                               u32 bvi_sw_if_index,
+                               u32 uu_fwd_sw_if_index,
+                               u32 bm_flood_sw_if_index)
 {
   gbp_bridge_domain_t *gb;
   index_t gbi;
@@ -175,6 +178,7 @@ gbp_bridge_domain_add_and_lock (u32 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;
       gb->gb_locks = 1;
       gb->gb_flags = flags;
 
@@ -185,9 +189,19 @@ gbp_bridge_domain_add_and_lock (u32 bd_id,
                       MODE_L2_BRIDGE, gb->gb_bvi_sw_if_index,
                       bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
       if (~0 != gb->gb_uu_fwd_sw_if_index)
-       set_int_l2_mode (vlib_get_main (), vnet_get_main (),
-                        MODE_L2_BRIDGE, gb->gb_uu_fwd_sw_if_index,
-                        bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
+       {
+         set_int_l2_mode (vlib_get_main (), vnet_get_main (),
+                          MODE_L2_BRIDGE, gb->gb_uu_fwd_sw_if_index,
+                          bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
+         gbp_sclass_enable_l2 (gb->gb_uu_fwd_sw_if_index);
+       }
+      if (~0 != gb->gb_bm_flood_sw_if_index)
+       {
+         set_int_l2_mode (vlib_get_main (), vnet_get_main (),
+                          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);
+       }
 
       /*
        * Add the BVI's MAC to the L2FIB
@@ -232,9 +246,19 @@ gbp_bridge_domain_unlock (index_t index)
                       MODE_L3, gb->gb_bvi_sw_if_index,
                       gb->gb_bd_index, L2_BD_PORT_TYPE_BVI, 0, 0);
       if (~0 != gb->gb_uu_fwd_sw_if_index)
-       set_int_l2_mode (vlib_get_main (), vnet_get_main (),
-                        MODE_L3, gb->gb_uu_fwd_sw_if_index,
-                        gb->gb_bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
+       {
+         set_int_l2_mode (vlib_get_main (), vnet_get_main (),
+                          MODE_L3, gb->gb_uu_fwd_sw_if_index,
+                          gb->gb_bd_index, L2_BD_PORT_TYPE_UU_FWD, 0, 0);
+         gbp_sclass_disable_l2 (gb->gb_uu_fwd_sw_if_index);
+       }
+      if (~0 != gb->gb_bm_flood_sw_if_index)
+       {
+         set_int_l2_mode (vlib_get_main (), vnet_get_main (),
+                          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_bridge_domain_db_remove (gb);
 
@@ -280,6 +304,7 @@ gbp_bridge_domain_cli (vlib_main_t * vm,
                       unformat_input_t * input, vlib_cli_command_t * cmd)
 {
   vnet_main_t *vnm = vnet_get_main ();
+  u32 bm_flood_sw_if_index = ~0;
   u32 uu_fwd_sw_if_index = ~0;
   u32 bvi_sw_if_index = ~0;
   u32 bd_id = ~0;
@@ -290,9 +315,12 @@ gbp_bridge_domain_cli (vlib_main_t * vm,
       if (unformat (input, "bvi %U", unformat_vnet_sw_interface,
                    vnm, &bvi_sw_if_index))
        ;
-      else if (unformat (input, "uu-flood %U", unformat_vnet_sw_interface,
+      else if (unformat (input, "uu-fwd %U", unformat_vnet_sw_interface,
                         vnm, &uu_fwd_sw_if_index))
        ;
+      else if (unformat (input, "bm-flood %U", unformat_vnet_sw_interface,
+                        vnm, &bm_flood_sw_if_index))
+       ;
       else if (unformat (input, "add"))
        add = 1;
       else if (unformat (input, "del"))
@@ -312,7 +340,9 @@ gbp_bridge_domain_cli (vlib_main_t * vm,
        return clib_error_return (0, "interface must be specified");
 
       gbp_bridge_domain_add_and_lock (bd_id, GBP_BD_FLAG_NONE,
-                                     bvi_sw_if_index, uu_fwd_sw_if_index);
+                                     bvi_sw_if_index,
+                                     uu_fwd_sw_if_index,
+                                     bm_flood_sw_if_index);
     }
   else
     gbp_bridge_domain_delete (bd_id);
index 65f133c..95b53dc 100644 (file)
@@ -57,6 +57,11 @@ typedef struct gbp_bridge_domain_t_
    */
   u32 gb_uu_fwd_sw_if_index;
 
+  /**
+   * The BD's interface to sned Broadcast and multicast packets
+   */
+  u32 gb_bm_flood_sw_if_index;
+
   /**
    * The BD's VNI interface on which packets from unkown endpoints
    * arrive
@@ -73,7 +78,9 @@ typedef struct gbp_bridge_domain_t_
 extern int gbp_bridge_domain_add_and_lock (u32 bd_id,
                                           gbp_bridge_domain_flags_t flags,
                                           u32 bvi_sw_if_index,
-                                          u32 uu_fwd_sw_if_index);
+                                          u32 uu_fwd_sw_if_index,
+                                          u32 bm_flood_sw_if_index);
+
 extern void gbp_bridge_domain_unlock (index_t gbi);
 extern index_t gbp_bridge_domain_find_and_lock (u32 bd_id);
 extern int gbp_bridge_domain_delete (u32 bd_id);
index 834f865..cefdbea 100644 (file)
@@ -33,6 +33,12 @@ gbp_endpoint_group_t *gbp_endpoint_group_pool;
  * DB of endpoint_groups
  */
 gbp_endpoint_group_db_t gbp_endpoint_group_db;
+
+/**
+ * Map sclass to EPG
+ */
+uword *gbp_epg_sclass_db;
+
 vlib_log_class_t gg_logger;
 
 #define GBP_EPG_DBG(...)                           \
@@ -68,6 +74,7 @@ gbp_endpoint_group_find (epg_id_t epg_id)
 
 int
 gbp_endpoint_group_add_and_lock (epg_id_t epg_id,
+                                u16 sclass,
                                 u32 bd_id, u32 rd_id, u32 uplink_sw_if_index)
 {
   gbp_endpoint_group_t *gg;
@@ -105,6 +112,10 @@ gbp_endpoint_group_add_and_lock (epg_id_t epg_id,
 
       gg->gg_uplink_sw_if_index = uplink_sw_if_index;
       gg->gg_locks = 1;
+      gg->gg_sclass = sclass;
+
+      if (SCLASS_INVALID != gg->gg_sclass)
+       hash_set (gbp_epg_sclass_db, gg->gg_sclass, gg->gg_id);
 
       /*
        * an egress DVR dpo for internal subnets to use when sending
@@ -179,6 +190,8 @@ gbp_endpoint_group_unlock (index_t ggi)
       gbp_bridge_domain_unlock (gg->gg_gbd);
       gbp_route_domain_unlock (gg->gg_rd);
 
+      if (SCLASS_INVALID != gg->gg_sclass)
+       hash_unset (gbp_epg_sclass_db, gg->gg_sclass);
       hash_unset (gbp_endpoint_group_db.gg_hash, gg->gg_id);
 
       pool_put (gbp_endpoint_group_pool, gg);
@@ -243,8 +256,8 @@ static clib_error_t *
 gbp_endpoint_group_cli (vlib_main_t * vm,
                        unformat_input_t * input, vlib_cli_command_t * cmd)
 {
+  epg_id_t epg_id = EPG_INVALID, sclass;
   vnet_main_t *vnm = vnet_get_main ();
-  epg_id_t epg_id = EPG_INVALID;
   u32 uplink_sw_if_index = ~0;
   u32 bd_id = ~0;
   u32 rd_id = ~0;
@@ -261,6 +274,8 @@ gbp_endpoint_group_cli (vlib_main_t * vm,
        add = 0;
       else if (unformat (input, "epg %d", &epg_id))
        ;
+      else if (unformat (input, "sclass %d", &sclass))
+       ;
       else if (unformat (input, "bd %d", &bd_id))
        ;
       else if (unformat (input, "rd %d", &rd_id))
@@ -281,7 +296,7 @@ gbp_endpoint_group_cli (vlib_main_t * vm,
       if (~0 == rd_id)
        return clib_error_return (0, "route-domain must be specified");
 
-      gbp_endpoint_group_add_and_lock (epg_id, bd_id, rd_id,
+      gbp_endpoint_group_add_and_lock (epg_id, sclass, bd_id, rd_id,
                                       uplink_sw_if_index);
     }
   else
index 763a80e..123954f 100644 (file)
@@ -30,6 +30,11 @@ typedef struct gpb_endpoint_group_t_
    */
   epg_id_t gg_id;
 
+  /**
+   * Sclass. Could be unset => ~0
+   */
+  u16 gg_sclass;
+
   /**
    * Bridge-domain ID the EPG is in
    */
@@ -71,6 +76,7 @@ typedef struct gbp_endpoint_group_db_t_
 } gbp_endpoint_group_db_t;
 
 extern int gbp_endpoint_group_add_and_lock (epg_id_t epg_id,
+                                           u16 sclass,
                                            u32 bd_id,
                                            u32 rd_id,
                                            u32 uplink_sw_if_index);
@@ -96,6 +102,19 @@ extern u8 *format_gbp_endpoint_group (u8 * s, va_list * args);
  */
 extern gbp_endpoint_group_db_t gbp_endpoint_group_db;
 extern gbp_endpoint_group_t *gbp_endpoint_group_pool;
+extern uword *gbp_epg_sclass_db;
+
+always_inline gbp_endpoint_group_t *
+gbp_epg_get (epg_id_t epg)
+{
+  uword *p;
+
+  p = hash_get (gbp_endpoint_group_db.gg_hash, epg);
+
+  if (NULL != p)
+    return (pool_elt_at_index (gbp_endpoint_group_pool, p[0]));
+  return (NULL);
+}
 
 always_inline u32
 gbp_epg_itf_lookup (epg_id_t epg)
@@ -114,6 +133,20 @@ gbp_epg_itf_lookup (epg_id_t epg)
   return (~0);
 }
 
+always_inline epg_id_t
+gbp_epg_sclass_2_id (u16 sclass)
+{
+  uword *p;
+
+  p = hash_get (gbp_epg_sclass_db, sclass);
+
+  if (NULL != p)
+    {
+      return (p[0]);
+    }
+  return (EPG_INVALID);
+}
+
 always_inline const dpo_id_t *
 gbp_epg_dpo_lookup (epg_id_t epg, fib_protocol_t fproto)
 {
index 762b463..514aca2 100644 (file)
@@ -706,7 +706,9 @@ void
 gbp_learn_enable (u32 sw_if_index, gbb_learn_mode_t mode)
 {
   if (GBP_LEARN_MODE_L2 == mode)
-    l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 1);
+    {
+      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 1);
+    }
   else
     {
       vnet_feature_enable_disable ("ip4-unicast",
@@ -720,7 +722,9 @@ void
 gbp_learn_disable (u32 sw_if_index, gbb_learn_mode_t mode)
 {
   if (GBP_LEARN_MODE_L2 == mode)
-    l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 0);
+    {
+      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_LEARN, 0);
+    }
   else
     {
       vnet_feature_enable_disable ("ip4-unicast",
index 67b6915..6a3f4fa 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <plugins/gbp/gbp_route_domain.h>
 #include <plugins/gbp/gbp_endpoint.h>
+#include <plugins/gbp/gbp_sclass.h>
 
 #include <vnet/dpo/dvr_dpo.h>
 #include <vnet/fib/fib_table.h>
@@ -182,6 +183,8 @@ gbp_route_domain_add_and_lock (u32 rd_id,
                                             &ADJ_BCAST_ADDR,
                                             grd->grd_uu_sw_if_index[fproto],
                                             rewrite);
+
+           gbp_sclass_enable_ip (grd->grd_uu_sw_if_index[fproto]);
          }
        else
          {
@@ -223,6 +226,8 @@ gbp_route_domain_unlock (index_t index)
                          fproto, FIB_SOURCE_PLUGIN_HI);
        if (INDEX_INVALID != grd->grd_adj[fproto])
          adj_unlock (grd->grd_adj[fproto]);
+       if (~0 != grd->grd_uu_sw_if_index[fproto])
+         gbp_sclass_disable_ip (grd->grd_uu_sw_if_index[fproto]);
       }
 
       gbp_route_domain_db_remove (grd);
diff --git a/src/plugins/gbp/gbp_sclass.c b/src/plugins/gbp/gbp_sclass.c
new file mode 100644 (file)
index 0000000..10ecf1f
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <plugins/gbp/gbp.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/l2/l2_output.h>
+
+/**
+ * Grouping of global data for the GBP source EPG classification feature
+ */
+typedef struct gbp_sclass_main_t_
+{
+  /**
+   * Next nodes for L2 output features
+   */
+  u32 gel_l2_input_feat_next[32];
+  u32 gel_l2_output_feat_next[32];
+} gbp_sclass_main_t;
+
+static gbp_sclass_main_t gbp_sclass_main;
+
+#define foreach_gbp_sclass                      \
+  _(DROP,    "drop")
+
+
+typedef enum
+{
+#define _(sym,str) GBP_SCLASS_NEXT_##sym,
+  foreach_gbp_sclass
+#undef _
+    GBP_SCLASS_N_NEXT,
+} gbp_sclass_next_t;
+
+typedef struct gbp_sclass_trace_t_
+{
+  /* per-pkt trace data */
+  u32 epg;
+  u32 sclass;
+} gbp_sclass_trace_t;
+
+always_inline uword
+gbp_sclass_inline (vlib_main_t * vm,
+                  vlib_node_runtime_t * node,
+                  vlib_frame_t * frame, int is_id_2_sclass, int is_l2)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  gbp_sclass_main_t *glm;
+
+  glm = &gbp_sclass_main;
+  next_index = 0;
+  n_left_from = frame->n_vectors;
+  from = vlib_frame_vector_args (frame);
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         gbp_sclass_next_t next0;
+         vlib_buffer_t *b0;
+         epg_id_t epg0;
+         u16 sclass0;
+         u32 bi0;
+
+         next0 = GBP_SCLASS_NEXT_DROP;
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         if (is_id_2_sclass)
+           {
+             // output direction - convert from the SRC-EPD to the sclass
+             gbp_endpoint_group_t *gg;
+
+             epg0 = vnet_buffer2 (b0)->gbp.src_epg;
+             gg = gbp_epg_get (epg0);
+
+             if (NULL != gg)
+               {
+                 sclass0 = vnet_buffer2 (b0)->gbp.sclass = gg->gg_sclass;
+                 if (is_l2)
+                   next0 =
+                     vnet_l2_feature_next (b0, glm->gel_l2_output_feat_next,
+                                           L2OUTPUT_FEAT_GBP_ID_2_SCLASS);
+                 else
+                   vnet_feature_next (&next0, b0);
+               }
+             else
+               sclass0 = 0;
+           }
+         else
+           {
+             /* input direction - convert from the sclass to the SRC-EGD */
+             sclass0 = vnet_buffer2 (b0)->gbp.sclass;
+             vnet_buffer2 (b0)->gbp.src_epg =
+               gbp_epg_sclass_2_id (vnet_buffer2 (b0)->gbp.sclass);
+             epg0 = vnet_buffer2 (b0)->gbp.src_epg;
+
+             if (EPG_INVALID != epg0)
+               {
+                 if (is_l2)
+                   next0 =
+                     vnet_l2_feature_next (b0, glm->gel_l2_input_feat_next,
+                                           L2INPUT_FEAT_GBP_SCLASS_2_ID);
+                 else
+                   vnet_feature_next (&next0, b0);
+               }
+           }
+
+         if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             gbp_sclass_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->epg = epg0;
+             t->sclass = sclass0;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  return frame->n_vectors;
+}
+
+always_inline uword
+l2_gbp_id_2_sclass (vlib_main_t * vm,
+                   vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 1, 1));
+}
+
+always_inline uword
+l2_gbp_sclass_2_id (vlib_main_t * vm,
+                   vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 0, 1));
+}
+
+always_inline uword
+ip4_gbp_id_2_sclass (vlib_main_t * vm,
+                    vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 1, 0));
+}
+
+always_inline uword
+ip4_gbp_sclass_2_id (vlib_main_t * vm,
+                    vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 0, 0));
+}
+
+always_inline uword
+ip6_gbp_id_2_sclass (vlib_main_t * vm,
+                    vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 1, 0));
+}
+
+always_inline uword
+ip6_gbp_sclass_2_id (vlib_main_t * vm,
+                    vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return (gbp_sclass_inline (vm, node, frame, 0, 0));
+}
+
+/* packet trace format function */
+static u8 *
+format_gbp_sclass_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  gbp_sclass_trace_t *t = va_arg (*args, gbp_sclass_trace_t *);
+
+  s = format (s, "epg:%d sclass:%d", t->epg, t->sclass);
+
+  return s;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (l2_gbp_id_2_sclass_node) = {
+  .function = l2_gbp_id_2_sclass,
+  .name = "l2-gbp-id-2-sclass",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+VLIB_REGISTER_NODE (l2_gbp_sclass_2_id_node) = {
+  .function = l2_gbp_sclass_2_id,
+  .name = "l2-gbp-sclass-2-id",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (ip4_gbp_id_2_sclass_node) = {
+  .function = ip4_gbp_id_2_sclass,
+  .name = "ip4-gbp-id-2-sclass",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+VLIB_REGISTER_NODE (ip4_gbp_sclass_2_id_node) = {
+  .function = ip4_gbp_sclass_2_id,
+  .name = "ip4-gbp-sclass-2-id",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (ip6_gbp_id_2_sclass_node) = {
+  .function = ip6_gbp_id_2_sclass,
+  .name = "ip6-gbp-id-2-sclass",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+VLIB_REGISTER_NODE (ip6_gbp_sclass_2_id_node) = {
+  .function = ip6_gbp_sclass_2_id,
+  .name = "ip6-gbp-sclass-2-id",
+  .vector_size = sizeof (u32),
+  .format_trace = format_gbp_sclass_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_next_nodes = GBP_SCLASS_N_NEXT,
+
+  .next_nodes = {
+    [GBP_SCLASS_NEXT_DROP] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (l2_gbp_id_2_sclass_node, l2_gbp_id_2_sclass);
+VLIB_NODE_FUNCTION_MULTIARCH (l2_gbp_sclass_2_id_node, l2_gbp_sclass_2_id);
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_id_2_sclass_node, ip4_gbp_id_2_sclass);
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_sclass_2_id_node, ip4_gbp_sclass_2_id);
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_id_2_sclass_node, ip6_gbp_id_2_sclass);
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_sclass_2_id_node, ip6_gbp_sclass_2_id);
+
+VNET_FEATURE_INIT (ip4_gbp_sclass_2_id_feat, static) =
+{
+  .arc_name = "ip4-unicast",
+  .node_name = "ip4-gbp-sclass-2-id",
+  .runs_before = VNET_FEATURES ("gbp-learn-ip4"),
+};
+VNET_FEATURE_INIT (ip6_gbp_sclass_2_id_feat, static) =
+{
+  .arc_name = "ip6-unicast",
+  .node_name = "ip6-gbp-sclass-2-id",
+  .runs_before = VNET_FEATURES ("gbp-learn-ip6"),
+};
+VNET_FEATURE_INIT (ip4_gbp_id_2_sclass_feat, static) =
+{
+  .arc_name = "ip4-output",
+  .node_name = "ip4-gbp-id-2-sclass",
+};
+VNET_FEATURE_INIT (ip6_gbp_id_2_sclass_feat, static) =
+{
+  .arc_name = "ip6-output",
+  .node_name = "ip6-gbp-id-2-sclass",
+};
+/* *INDENT-ON* */
+
+void
+gbp_sclass_enable_l2 (u32 sw_if_index)
+{
+  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SCLASS_2_ID, 1);
+  l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_ID_2_SCLASS, 1);
+}
+
+void
+gbp_sclass_disable_l2 (u32 sw_if_index)
+{
+  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SCLASS_2_ID, 0);
+  l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_ID_2_SCLASS, 0);
+}
+
+void
+gbp_sclass_enable_ip (u32 sw_if_index)
+{
+  vnet_feature_enable_disable ("ip4-unicast",
+                              "ip4-gbp-sclass-2-id", sw_if_index, 1, 0, 0);
+  vnet_feature_enable_disable ("ip6-unicast",
+                              "ip6-gbp-sclass-2-id", sw_if_index, 1, 0, 0);
+  vnet_feature_enable_disable ("ip4-output",
+                              "ip4-gbp-id-2-sclass", sw_if_index, 1, 0, 0);
+  vnet_feature_enable_disable ("ip6-output",
+                              "ip6-gbp-id-2-sclass", sw_if_index, 1, 0, 0);
+}
+
+void
+gbp_sclass_disable_ip (u32 sw_if_index)
+{
+  vnet_feature_enable_disable ("ip4-unicast",
+                              "ip4-gbp-sclass-2-id", sw_if_index, 0, 0, 0);
+  vnet_feature_enable_disable ("ip6-unicast",
+                              "ip6-gbp-sclass-2-id", sw_if_index, 0, 0, 0);
+  vnet_feature_enable_disable ("ip4-output",
+                              "ip4-gbp-id-2-sclass", sw_if_index, 0, 0, 0);
+  vnet_feature_enable_disable ("ip6-output",
+                              "ip6-gbp-id-2-sclass", sw_if_index, 0, 0, 0);
+}
+
+static clib_error_t *
+gbp_sclass_init (vlib_main_t * vm)
+{
+  gbp_sclass_main_t *glm = &gbp_sclass_main;
+
+  /* Initialize the feature next-node indices */
+  feat_bitmap_init_next_nodes (vm,
+                              l2_gbp_sclass_2_id_node.index,
+                              L2INPUT_N_FEAT,
+                              l2input_get_feat_names (),
+                              glm->gel_l2_input_feat_next);
+  feat_bitmap_init_next_nodes (vm,
+                              l2_gbp_id_2_sclass_node.index,
+                              L2OUTPUT_N_FEAT,
+                              l2output_get_feat_names (),
+                              glm->gel_l2_output_feat_next);
+
+  return (NULL);
+}
+
+VLIB_INIT_FUNCTION (gbp_sclass_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/gbp/gbp_sclass.h b/src/plugins/gbp/gbp_sclass.h
new file mode 100644 (file)
index 0000000..07c5fff
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GBP_SCLASS_H__
+#define __GBP_SCLASS_H__
+
+#include <plugins/gbp/gbp.h>
+
+extern void gbp_sclass_enable_ip (u32 sw_if_index);
+extern void gbp_sclass_enable_l2 (u32 sw_if_index);
+extern void gbp_sclass_disable_ip (u32 sw_if_index);
+extern void gbp_sclass_disable_l2 (u32 sw_if_index);
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index afb17e3..0faa74b 100644 (file)
@@ -20,6 +20,7 @@
 
 typedef u16 epg_id_t;
 #define EPG_INVALID ((u16)~0)
+#define SCLASS_INVALID ((u16)~0)
 
 #endif
 
index 2b264f8..7fbd7e9 100644 (file)
@@ -18,6 +18,7 @@
 #include <plugins/gbp/gbp_learn.h>
 #include <plugins/gbp/gbp_bridge_domain.h>
 #include <plugins/gbp/gbp_route_domain.h>
+#include <plugins/gbp/gbp_sclass.h>
 
 #include <vnet/vxlan-gbp/vxlan_gbp.h>
 #include <vlibmemory/api.h>
@@ -106,13 +107,12 @@ format_vxlan_tunnel_ref (u8 * s, va_list * args)
 
 static u32
 gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
-                  u32 vni,
                   const ip46_address_t * src, const ip46_address_t * dst)
 {
   vnet_vxlan_gbp_tunnel_add_del_args_t args = {
     .is_add = 1,
     .is_ip6 = !ip46_address_is_ip4 (src),
-    .vni = vni,
+    .vni = gt->gt_vni,
     .src = *src,
     .dst = *dst,
     .instance = ~0,
@@ -140,7 +140,7 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
       GBP_VXLAN_TUN_DBG ("add-dep:%U %U %U %d", format_vnet_sw_if_index_name,
                         vnet_get_main (), sw_if_index,
                         format_ip46_address, src, IP46_TYPE_ANY,
-                        format_ip46_address, dst, IP46_TYPE_ANY, vni);
+                        format_ip46_address, dst, IP46_TYPE_ANY, gt->gt_vni);
 
       pool_get_zero (vxlan_tunnel_ref_pool, vxr);
 
@@ -161,13 +161,25 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
 
       if (GBP_VXLAN_TUN_L2 == vxr->vxr_layer)
        {
+         l2output_feat_masks_t ofeat;
+         l2input_feat_masks_t ifeat;
+         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);
 
-         gbp_itf_set_l2_output_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
-                                        L2OUTPUT_FEAT_GBP_POLICY_MAC);
-         gbp_itf_set_l2_input_feature (vxr->vxr_itf, vxr->vxr_sw_if_index,
-                                       L2INPUT_FEAT_GBP_LEARN);
+         ofeat = (L2OUTPUT_FEAT_GBP_POLICY_MAC |
+                  L2OUTPUT_FEAT_GBP_ID_2_SCLASS);
+         ifeat = L2INPUT_FEAT_GBP_SCLASS_2_ID;
+
+         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);
        }
       else
        {
@@ -181,6 +193,7 @@ gdb_vxlan_dep_add (gbp_vxlan_tunnel_t * gt,
                           grd->grd_table_id[fproto], 1);
 
          gbp_learn_enable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
+         gbp_sclass_enable_ip (vxr->vxr_sw_if_index);
        }
     }
 
@@ -235,7 +248,7 @@ gbp_vxlan_tunnel_clone_and_lock (u32 sw_if_index,
 
   gt = pool_elt_at_index (gbp_vxlan_tunnel_pool, gti);
 
-  return (gdb_vxlan_dep_add (gt, gt->gt_vni, src, dst));
+  return (gdb_vxlan_dep_add (gt, src, dst));
 }
 
 static void
@@ -270,6 +283,8 @@ gdb_vxlan_dep_del (index_t vxri)
 
       FOR_EACH_FIB_IP_PROTOCOL (fproto)
        ip_table_bind (fproto, vxr->vxr_sw_if_index, 0, 0);
+      gbp_sclass_disable_ip (vxr->vxr_sw_if_index);
+      gbp_learn_disable (vxr->vxr_sw_if_index, GBP_LEARN_MODE_L3);
     }
 
   vnet_vxlan_gbp_tunnel_del (vxr->vxr_sw_if_index);
@@ -712,6 +727,7 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
          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);
+         gbp_sclass_enable_l2 (gt->gt_sw_if_index);
        }
       else
        {
@@ -724,6 +740,7 @@ gbp_vxlan_tunnel_add (u32 vni, gbp_vxlan_tunnel_layer_t layer,
          grd->grd_vni_sw_if_index = gt->gt_sw_if_index;
 
          gbp_learn_enable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
+         gbp_sclass_enable_ip (gt->gt_sw_if_index);
 
          ip4_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
          ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 1);
@@ -788,6 +805,7 @@ gbp_vxlan_tunnel_del (u32 vni)
       if (GBP_VXLAN_TUN_L2 == gt->gt_layer)
        {
          gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L2);
+         gbp_sclass_disable_l2 (gt->gt_sw_if_index);
          gbp_itf_unlock (gt->gt_itf);
          gbp_bridge_domain_unlock (gt->gt_gbd);
        }
@@ -802,6 +820,7 @@ gbp_vxlan_tunnel_del (u32 vni)
          ip6_sw_interface_enable_disable (gt->gt_sw_if_index, 0);
 
          gbp_learn_disable (gt->gt_sw_if_index, GBP_LEARN_MODE_L3);
+         gbp_sclass_disable_ip (gt->gt_sw_if_index);
          gbp_route_domain_unlock (gt->gt_grd);
        }
 
index 89dd845..0669651 100644 (file)
@@ -389,7 +389,11 @@ typedef struct
   {
     u8 __unused;
     u8 flags;
-    u16 src_epg;
+    union
+    {
+      u16 src_epg;
+      u16 sclass;
+    };
   } gbp;
 
   union
index 93da127..12e7e54 100644 (file)
@@ -114,6 +114,7 @@ l2input_bd_config (u32 bd_index)
  _(GBP_NULL_CLASSIFY, "gbp-null-classify")      \
  _(GBP_SRC_CLASSIFY,  "gbp-src-classify")       \
  _(GBP_LPM_CLASSIFY,  "l2-gbp-lpm-classify")    \
+ _(GBP_SCLASS_2_ID, "l2-gbp-sclass-2-id")         \
  _(VTR,           "l2-input-vtr")               \
  _(L2_IP_QOS_RECORD, "l2-ip-qos-record")        \
  _(VPATH,         "vpath-input-l2")             \
index 74d2829..fdb6167 100644 (file)
@@ -81,6 +81,7 @@ extern vlib_node_registration_t l2output_node;
 #define foreach_l2output_feat \
  _(OUTPUT,            "interface-output")           \
  _(SPAN,              "span-l2-output")             \
+ _(GBP_ID_2_SCLASS,   "l2-gbp-id-2-sclass")          \
  _(GBP_POLICY_PORT,   "gbp-policy-port")            \
  _(GBP_POLICY_MAC,    "gbp-policy-mac")             \
  _(CFM,               "feature-bitmap-drop")        \
index 613cb01..6c14ef7 100644 (file)
@@ -334,7 +334,7 @@ vxlan_gbp_input (vlib_main_t * vm,
            }
 
          vnet_buffer2 (b0)->gbp.flags = vxlan_gbp_get_gpflags (vxlan_gbp0);
-         vnet_buffer2 (b0)->gbp.src_epg = vxlan_gbp_get_sclass (vxlan_gbp0);
+         vnet_buffer2 (b0)->gbp.sclass = vxlan_gbp_get_sclass (vxlan_gbp0);
 
 
          if (PREDICT_FALSE
@@ -369,7 +369,7 @@ vxlan_gbp_input (vlib_main_t * vm,
            }
 
          vnet_buffer2 (b1)->gbp.flags = vxlan_gbp_get_gpflags (vxlan_gbp1);
-         vnet_buffer2 (b1)->gbp.src_epg = vxlan_gbp_get_sclass (vxlan_gbp1);
+         vnet_buffer2 (b1)->gbp.sclass = vxlan_gbp_get_sclass (vxlan_gbp1);
 
          vnet_update_l2_len (b0);
          vnet_update_l2_len (b1);
@@ -473,7 +473,7 @@ vxlan_gbp_input (vlib_main_t * vm,
                (rx_counter, thread_index, stats_t0->sw_if_index, 1, len0);
            }
          vnet_buffer2 (b0)->gbp.flags = vxlan_gbp_get_gpflags (vxlan_gbp0);
-         vnet_buffer2 (b0)->gbp.src_epg = vxlan_gbp_get_sclass (vxlan_gbp0);
+         vnet_buffer2 (b0)->gbp.sclass = vxlan_gbp_get_sclass (vxlan_gbp0);
 
          /* Required to make the l2 tag push / pop code work on l2 subifs */
          vnet_update_l2_len (b0);
index f1b839c..f8fc9b4 100644 (file)
@@ -260,9 +260,9 @@ vxlan_gbp_encap_inline (vlib_main_t * vm,
          vxlan_gbp0->gpflags = vnet_buffer2 (b0)->gbp.flags;
          vxlan_gbp1->gpflags = vnet_buffer2 (b1)->gbp.flags;
          vxlan_gbp0->sclass =
-           clib_host_to_net_u16 (vnet_buffer2 (b0)->gbp.src_epg);
+           clib_host_to_net_u16 (vnet_buffer2 (b0)->gbp.sclass);
          vxlan_gbp1->sclass =
-           clib_host_to_net_u16 (vnet_buffer2 (b1)->gbp.src_epg);
+           clib_host_to_net_u16 (vnet_buffer2 (b1)->gbp.sclass);
 
          if (csum_offload)
            {
@@ -324,7 +324,7 @@ vxlan_gbp_encap_inline (vlib_main_t * vm,
                vlib_add_trace (vm, node, b0, sizeof (*tr));
              tr->tunnel_index = t0 - vxm->tunnels;
              tr->vni = t0->vni;
-             tr->sclass = vnet_buffer2 (b0)->gbp.src_epg;
+             tr->sclass = vnet_buffer2 (b0)->gbp.sclass;
              tr->flags = vnet_buffer2 (b0)->gbp.flags;
            }
 
@@ -334,7 +334,7 @@ vxlan_gbp_encap_inline (vlib_main_t * vm,
                vlib_add_trace (vm, node, b1, sizeof (*tr));
              tr->tunnel_index = t1 - vxm->tunnels;
              tr->vni = t1->vni;
-             tr->sclass = vnet_buffer2 (b1)->gbp.src_epg;
+             tr->sclass = vnet_buffer2 (b1)->gbp.sclass;
              tr->flags = vnet_buffer2 (b1)->gbp.flags;
            }
 
@@ -426,7 +426,7 @@ vxlan_gbp_encap_inline (vlib_main_t * vm,
          /* set source class and gpflags */
          vxlan_gbp0->gpflags = vnet_buffer2 (b0)->gbp.flags;
          vxlan_gbp0->sclass =
-           clib_host_to_net_u16 (vnet_buffer2 (b0)->gbp.src_epg);
+           clib_host_to_net_u16 (vnet_buffer2 (b0)->gbp.sclass);
 
          if (csum_offload)
            {
@@ -469,7 +469,7 @@ vxlan_gbp_encap_inline (vlib_main_t * vm,
                vlib_add_trace (vm, node, b0, sizeof (*tr));
              tr->tunnel_index = t0 - vxm->tunnels;
              tr->vni = t0->vni;
-             tr->sclass = vnet_buffer2 (b0)->gbp.src_epg;
+             tr->sclass = vnet_buffer2 (b0)->gbp.sclass;
              tr->flags = vnet_buffer2 (b0)->gbp.flags;
            }
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
index 51df8d9..fd8b79b 100644 (file)
@@ -282,7 +282,7 @@ class VppGbpEndpointGroup(VppObject):
     GBP Endpoint Group
     """
 
-    def __init__(self, test, epg, rd, bd, uplink,
+    def __init__(self, test, epg, sclass, rd, bd, uplink,
                  bvi, bvi_ip4, bvi_ip6=None):
         self._test = test
         self.uplink = uplink
@@ -292,10 +292,14 @@ class VppGbpEndpointGroup(VppObject):
         self.epg = epg
         self.bd = bd
         self.rd = rd
+        self.sclass = sclass
+        if 0 == self.sclass:
+            self.sclass = 0xffff
 
     def add_vpp_config(self):
         self._test.vapi.gbp_endpoint_group_add(
             self.epg,
+            self.sclass,
             self.bd.bd.bd_id,
             self.rd.rd_id,
             self.uplink.sw_if_index if self.uplink else INDEX_INVALID)
@@ -324,10 +328,12 @@ class VppGbpBridgeDomain(VppObject):
     GBP Bridge Domain
     """
 
-    def __init__(self, test, bd, bvi, uu_flood=None, learn=True):
+    def __init__(self, test, bd, bvi, uu_fwd=None,
+                 bm_flood=None, learn=True):
         self._test = test
         self.bvi = bvi
-        self.uu_flood = uu_flood
+        self.uu_fwd = uu_fwd
+        self.bm_flood = bm_flood
         self.bd = bd
 
         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
@@ -341,7 +347,8 @@ class VppGbpBridgeDomain(VppObject):
             self.bd.bd_id,
             self.learn,
             self.bvi.sw_if_index,
-            self.uu_flood.sw_if_index if self.uu_flood else INDEX_INVALID)
+            self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID,
+            self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID)
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
@@ -731,23 +738,23 @@ class TestGBP(VppTestCase):
         # 3 EPGs, 2 of which share a BD.
         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
         #
-        epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
+        epgs = [VppGbpEndpointGroup(self, 220, 0, rd0, gbd1, self.pg4,
                                     self.loop0,
                                     "10.0.0.128",
                                     "2001:10::128"),
-                VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
+                VppGbpEndpointGroup(self, 221, 0, rd0, gbd1, self.pg5,
                                     self.loop0,
                                     "10.0.1.128",
                                     "2001:10:1::128"),
-                VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
+                VppGbpEndpointGroup(self, 222, 0, rd0, gbd2, self.pg6,
                                     self.loop1,
                                     "10.0.2.128",
                                     "2001:10:2::128"),
-                VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
+                VppGbpEndpointGroup(self, 333, 0, rd20, gbd20, self.pg7,
                                     self.loop2,
                                     "11.0.0.128",
                                     "3001::128"),
-                VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
+                VppGbpEndpointGroup(self, 444, 0, rd20, gbd20, self.pg8,
                                     self.loop2,
                                     "11.0.0.129",
                                     "3001::129")]
@@ -1484,12 +1491,20 @@ class TestGBP(VppTestCase):
         self.pg4.config_ip4()
         self.pg4.resolve_arp()
 
+        #
+        # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
+        #
+        tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
+                                   "239.1.1.1", 88,
+                                   mcast_itf=self.pg4)
+        tun_bm.add_vpp_config()
+
         #
         # a GBP bridge domain with a BVI and a UU-flood interface
         #
         bd1 = VppBridgeDomain(self, 1)
         bd1.add_vpp_config()
-        gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
+        gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm)
         gbd1.add_vpp_config()
 
         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
@@ -1502,12 +1517,12 @@ class TestGBP(VppTestCase):
         #
         # The Endpoint-group in which we are learning endpoints
         #
-        epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+        epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
                                       None, self.loop0,
                                       "10.0.0.128",
                                       "2001:10::128")
         epg_220.add_vpp_config()
-        epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
+        epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
                                       None, self.loop1,
                                       "10.0.1.128",
                                       "2001:11::128")
@@ -1569,7 +1584,7 @@ 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=220, flags=0x88) /
+                 VXLAN(vni=99, gpid=112, flags=0x88) /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1618,7 +1633,7 @@ 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=220, flags=0x88, gpflags="D") /
+                 VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1641,7 +1656,7 @@ 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=220, flags=0x88) /
+                 VXLAN(vni=99, gpid=112, flags=0x88) /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1670,7 +1685,7 @@ class TestGBP(VppTestCase):
                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
-                self.assertEqual(rx[VXLAN].gpid, 220)
+                self.assertEqual(rx[VXLAN].gpid, 112)
                 self.assertEqual(rx[VXLAN].vni, 99)
                 self.assertTrue(rx[VXLAN].flags.G)
                 self.assertTrue(rx[VXLAN].flags.Instance)
@@ -1693,7 +1708,7 @@ 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=330, flags=0x88, gpflags='A') /
+                 VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1726,7 +1741,7 @@ 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=330, flags=0x88, gpflags='A') /
+                 VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1773,18 +1788,7 @@ class TestGBP(VppTestCase):
                 IP(dst="10.0.0.133", src=ep.ip4.address) /
                 UDP(sport=1234, dport=1234) /
                 Raw('\xa5' * 100))
-        rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
-
-        #
-        # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
-        #
-        tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
-                                   "239.1.1.1", 88,
-                                   mcast_itf=self.pg4)
-        tun_bm.add_vpp_config()
-        bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
-                                    port_type=L2_PORT_TYPE.NORMAL)
-        bp_bm.add_vpp_config()
+        rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
 
         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
 
@@ -1794,6 +1798,18 @@ class TestGBP(VppTestCase):
                 Raw('\xa5' * 100))
         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
 
+        for rx in rxs:
+            self.assertEqual(rx[IP].src, self.pg4.local_ip4)
+            self.assertEqual(rx[IP].dst, "239.1.1.1")
+            self.assertEqual(rx[UDP].dport, 48879)
+            # the UDP source port is a random value for hashing
+            self.assertEqual(rx[VXLAN].gpid, 112)
+            self.assertEqual(rx[VXLAN].vni, 88)
+            self.assertTrue(rx[VXLAN].flags.G)
+            self.assertTrue(rx[VXLAN].flags.Instance)
+            self.assertFalse(rx[VXLAN].gpflags.A)
+            self.assertFalse(rx[VXLAN].gpflags.D)
+
         #
         # Check v6 Endpoints
         #
@@ -1804,7 +1820,7 @@ 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=330, flags=0x88, gpflags='A') /
+                 VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1907,7 +1923,7 @@ class TestGBP(VppTestCase):
         #
         # The Endpoint-group in which we are learning endpoints
         #
-        epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+        epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
                                       None, self.loop0,
                                       "10.0.0.128",
                                       "2001:10::128")
@@ -1945,7 +1961,7 @@ 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=220, flags=0x88) /
+                 VXLAN(vni=99, gpid=441, flags=0x88) /
                  Ether(src=l['mac'], dst=ep.mac) /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -1993,7 +2009,7 @@ class TestGBP(VppTestCase):
                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
-                self.assertEqual(rx[VXLAN].gpid, 220)
+                self.assertEqual(rx[VXLAN].gpid, 441)
                 self.assertEqual(rx[VXLAN].vni, 116)
                 self.assertTrue(rx[VXLAN].flags.G)
                 self.assertTrue(rx[VXLAN].flags.Instance)
@@ -2087,7 +2103,7 @@ class TestGBP(VppTestCase):
         #
         # The Endpoint-group in which we are learning endpoints
         #
-        epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+        epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
                                       None, self.loop0,
                                       "10.0.0.128",
                                       "2001:10::128")
@@ -2123,7 +2139,7 @@ class TestGBP(VppTestCase):
                  IP(src=self.pg2.remote_hosts[1].ip4,
                     dst=self.pg2.local_ip4) /
                  UDP(sport=1234, dport=48879) /
-                 VXLAN(vni=101, gpid=220, flags=0x88) /
+                 VXLAN(vni=101, gpid=441, flags=0x88) /
                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -2160,7 +2176,7 @@ class TestGBP(VppTestCase):
                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
-                self.assertEqual(rx[VXLAN].gpid, 220)
+                self.assertEqual(rx[VXLAN].gpid, 441)
                 self.assertEqual(rx[VXLAN].vni, 101)
                 self.assertTrue(rx[VXLAN].flags.G)
                 self.assertTrue(rx[VXLAN].flags.Instance)
@@ -2190,7 +2206,7 @@ class TestGBP(VppTestCase):
                  IP(src=self.pg2.remote_hosts[1].ip4,
                     dst=self.pg2.local_ip4) /
                  UDP(sport=1234, dport=48879) /
-                 VXLAN(vni=101, gpid=220, flags=0x88) /
+                 VXLAN(vni=101, gpid=441, flags=0x88) /
                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
                  UDP(sport=1234, dport=1234) /
@@ -2233,7 +2249,7 @@ class TestGBP(VppTestCase):
                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
-                self.assertEqual(rx[VXLAN].gpid, 220)
+                self.assertEqual(rx[VXLAN].gpid, 441)
                 self.assertEqual(rx[VXLAN].vni, 101)
                 self.assertTrue(rx[VXLAN].flags.G)
                 self.assertTrue(rx[VXLAN].flags.Instance)
@@ -2281,7 +2297,7 @@ class TestGBP(VppTestCase):
             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
             self.assertEqual(rx[UDP].dport, 48879)
             # the UDP source port is a random value for hashing
-            self.assertEqual(rx[VXLAN].gpid, 220)
+            self.assertEqual(rx[VXLAN].gpid, 441)
             self.assertEqual(rx[VXLAN].vni, 114)
             self.assertTrue(rx[VXLAN].flags.G)
             self.assertTrue(rx[VXLAN].flags.Instance)
@@ -2297,10 +2313,10 @@ class TestGBP(VppTestCase):
             # 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,
+                 IP(src=self.pg2.remote_hosts[2].ip4,
                     dst=self.pg2.local_ip4) /
                  UDP(sport=1234, dport=48879) /
-                 VXLAN(vni=101, gpid=220, flags=0x88) /
+                 VXLAN(vni=101, gpid=441, flags=0x88) /
                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
                  IP(src=l['ip'], dst=ep.ip4.address) /
                  UDP(sport=1234, dport=1234) /
@@ -2312,7 +2328,7 @@ class TestGBP(VppTestCase):
             tep1_sw_if_index = find_vxlan_gbp_tunnel(
                 self,
                 self.pg2.local_ip4,
-                self.pg2.remote_hosts[1].ip4,
+                self.pg2.remote_hosts[2].ip4,
                 vx_tun_l3.vni)
             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
 
@@ -2372,7 +2388,7 @@ class TestGBP(VppTestCase):
                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
                 self.assertEqual(rx[UDP].dport, 48879)
                 # the UDP source port is a random value for hashing
-                self.assertEqual(rx[VXLAN].gpid, 220)
+                self.assertEqual(rx[VXLAN].gpid, 441)
                 self.assertEqual(rx[VXLAN].vni, 101)
                 self.assertTrue(rx[VXLAN].flags.G)
                 self.assertTrue(rx[VXLAN].flags.Instance)
@@ -2425,7 +2441,7 @@ class TestGBP(VppTestCase):
              IP(src=self.pg2.remote_hosts[1].ip4,
                 dst=self.pg2.local_ip4) /
              UDP(sport=1234, dport=48879) /
-             VXLAN(vni=101, gpid=220, flags=0x88) /
+             VXLAN(vni=101, gpid=441, flags=0x88) /
              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
              UDP(sport=1234, dport=1234) /
@@ -2519,17 +2535,17 @@ class TestGBP(VppTestCase):
         #
         # The Endpoint-groups in which we are learning endpoints
         #
-        epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+        epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
                                       None, gbd1.bvi,
                                       "10.0.0.128",
                                       "2001:10::128")
         epg_220.add_vpp_config()
-        epg_221 = VppGbpEndpointGroup(self, 221, rd1, gbd2,
+        epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
                                       None, gbd2.bvi,
                                       "10.0.1.128",
                                       "2001:11::128")
         epg_221.add_vpp_config()
-        epg_222 = VppGbpEndpointGroup(self, 222, rd1, gbd1,
+        epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
                                       None, gbd1.bvi,
                                       "10.0.2.128",
                                       "2001:12::128")
@@ -2557,12 +2573,12 @@ class TestGBP(VppTestCase):
         #
         # EPGs in which the service endpoints exist
         #
-        epg_320 = VppGbpEndpointGroup(self, 320, rd1, gbd3,
+        epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
                                       None, gbd1.bvi,
                                       "12.0.0.128",
                                       "4001:10::128")
         epg_320.add_vpp_config()
-        epg_321 = VppGbpEndpointGroup(self, 321, rd1, gbd4,
+        epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
                                       None, gbd2.bvi,
                                       "12.0.1.128",
                                       "4001:11::128")
@@ -2915,7 +2931,7 @@ class TestGBP(VppTestCase):
              IP(src=self.pg7.remote_ip4,
                 dst=self.pg7.local_ip4) /
              UDP(sport=1234, dport=48879) /
-             VXLAN(vni=444, gpid=221, flags=0x88) /
+             VXLAN(vni=444, gpid=441, flags=0x88) /
              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
              IP(src="10.0.0.88", dst=ep1.ip4.address) /
              UDP(sport=1234, dport=1234) /
@@ -2933,7 +2949,7 @@ class TestGBP(VppTestCase):
              IP(src=self.pg7.remote_ip4,
                 dst=self.pg7.local_ip4) /
              UDP(sport=1234, dport=48879) /
-             VXLAN(vni=444, gpid=221, flags=0x88) /
+             VXLAN(vni=444, gpid=441, flags=0x88) /
              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
              UDP(sport=1234, dport=1234) /
@@ -3052,18 +3068,26 @@ class TestGBP(VppTestCase):
         self.pg7.config_ip4()
         self.pg7.resolve_arp()
 
+        #
+        # a multicast vxlan-gbp tunnel for broadcast in the BD
+        #
+        tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
+                                   "239.1.1.1", 88,
+                                   mcast_itf=self.pg7)
+        tun_bm.add_vpp_config()
+
         #
         # a GBP external bridge domains for the EPs
         #
         bd1 = VppBridgeDomain(self, 1)
         bd1.add_vpp_config()
-        gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
+        gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, None, tun_bm)
         gbd1.add_vpp_config()
 
         #
         # The Endpoint-groups in which the external endpoints exist
         #
-        epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+        epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
                                       None, gbd1.bvi,
                                       "10.0.0.128",
                                       "2001:10::128")
@@ -3079,7 +3103,7 @@ class TestGBP(VppTestCase):
         l3o_1 = VppGbpSubnet(
             self, rd1, "10.0.0.0", 24,
             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
-            epg=200)
+            epg=220)
         l3o_1.add_vpp_config()
 
         #
@@ -3092,18 +3116,7 @@ class TestGBP(VppTestCase):
         ext_itf.add_vpp_config()
 
         #
-        # a multicast vxlan-gbp tunnel for broadcast in the BD
-        #
-        tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
-                                   "239.1.1.1", 88,
-                                   mcast_itf=self.pg7)
-        tun_bm.add_vpp_config()
-        bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
-                                    port_type=L2_PORT_TYPE.NORMAL)
-        bp_bm.add_vpp_config()
-
-        #
-        # an unicast vxlan-gbp for inter-BD traffic
+        # an unicast vxlan-gbp for inter-RD traffic
         #
         vx_tun_l3 = VppGbpVxlanTunnel(
             self, 444, rd1.rd_id,
@@ -3136,7 +3149,7 @@ class TestGBP(VppTestCase):
             self.assertTrue(rx[VXLAN].flags.G)
             self.assertTrue(rx[VXLAN].flags.Instance)
             # policy was applied to the original IP packet
-            self.assertEqual(rx[VXLAN].gpid, 200)
+            self.assertEqual(rx[VXLAN].gpid, 113)
             self.assertTrue(rx[VXLAN].gpflags.A)
             self.assertFalse(rx[VXLAN].gpflags.D)
 
@@ -3175,7 +3188,7 @@ class TestGBP(VppTestCase):
              IP(src=self.pg7.remote_ip4,
                 dst=self.pg7.local_ip4) /
              UDP(sport=1234, dport=48879) /
-             VXLAN(vni=444, gpid=220, flags=0x88) /
+             VXLAN(vni=444, gpid=113, flags=0x88) /
              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
              IP(src="10.0.0.101", dst="10.0.0.1") /
              UDP(sport=1234, dport=1234) /
@@ -3203,7 +3216,7 @@ class TestGBP(VppTestCase):
              IP(src=self.pg7.remote_ip4,
                 dst=self.pg7.local_ip4) /
              UDP(sport=1234, dport=48879) /
-             VXLAN(vni=444, gpid=220, flags=0x88) /
+             VXLAN(vni=444, gpid=113, flags=0x88) /
              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
              IP(src="10.0.0.101", dst="10.220.0.1") /
              UDP(sport=1234, dport=1234) /
@@ -3211,102 +3224,6 @@ class TestGBP(VppTestCase):
 
         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
 
-        #
-        # another external subnet, this time in a different EPG
-        #
-        ip_200 = VppIpRoute(self, "10.200.0.0", 24,
-                            [VppRoutePath(eep.ip4.address,
-                                          eep.epg.bvi.sw_if_index)],
-                            table_id=t4.table_id)
-        ip_200.add_vpp_config()
-
-        l3o_200 = VppGbpSubnet(
-            self, rd1, "10.200.0.0", 24,
-            VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
-            epg=200)
-        l3o_200.add_vpp_config()
-
-        p = (Ether(src=self.pg7.remote_mac,
-                   dst=self.pg7.local_mac) /
-             IP(src=self.pg7.remote_ip4,
-                dst=self.pg7.local_ip4) /
-             UDP(sport=1234, dport=48879) /
-             VXLAN(vni=444, gpid=220, flags=0x88) /
-             Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
-             IP(src="10.0.0.101", dst="10.200.0.1") /
-             UDP(sport=1234, dport=1234) /
-             Raw('\xa5' * 100))
-
-        #
-        # packets dropped due to lack of contract.
-        #
-        rxs = self.send_and_assert_no_replies(self.pg7, p * 1)
-
-        #
-        # from the the subnet in EPG 220 beyond the external to remote
-        #
-        p4 = (Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
-              Dot1Q(vlan=100) /
-              IP(src="10.220.0.1", dst=rep.ip4.address) /
-              UDP(sport=1234, dport=1234) /
-              Raw('\xa5' * 100))
-
-        rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
-
-        for rx in rxs:
-            self.assertEqual(rx[Ether].src, self.pg7.local_mac)
-            self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
-            self.assertEqual(rx[IP].src, self.pg7.local_ip4)
-            self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
-            self.assertEqual(rx[VXLAN].vni, 444)
-            self.assertTrue(rx[VXLAN].flags.G)
-            self.assertTrue(rx[VXLAN].flags.Instance)
-            self.assertTrue(rx[VXLAN].gpflags.A)
-            self.assertFalse(rx[VXLAN].gpflags.D)
-
-        #
-        # from the the subnet in EPG 200 beyond the external to remote
-        # dropped due to no contract
-        #
-        p4 = (Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
-              Dot1Q(vlan=100) /
-              IP(src="10.200.0.1", dst=rep.ip4.address) /
-              UDP(sport=1234, dport=1234) /
-              Raw('\xa5' * 100))
-
-        rxs = self.send_and_assert_no_replies(self.pg0, p4 * 1)
-
-        #
-        # add a contract
-        #
-        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])
-        c1 = VppGbpContract(
-            self, 200, 220, acl_index,
-            [VppGbpContractRule(
-                VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
-                []),
-             VppGbpContractRule(
-                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
-                 [])],
-            [ETH_P_IP, ETH_P_IPV6])
-        c1.add_vpp_config()
-
-        rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
-
-        for rx in rxs:
-            self.assertEqual(rx[Ether].src, self.pg7.local_mac)
-            self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
-            self.assertEqual(rx[IP].src, self.pg7.local_ip4)
-            self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
-            self.assertEqual(rx[VXLAN].vni, 444)
-            self.assertTrue(rx[VXLAN].flags.G)
-            self.assertTrue(rx[VXLAN].flags.Instance)
-            self.assertTrue(rx[VXLAN].gpflags.A)
-            self.assertFalse(rx[VXLAN].gpflags.D)
-
         #
         # cleanup
         #
index 087424c..e5902c2 100644 (file)
@@ -3587,7 +3587,7 @@ class VppPapiProvider(object):
         return self.api(self.papi.gbp_endpoint_dump,
                         {'_no_type_conversion': True})
 
-    def gbp_endpoint_group_add(self, epg, bd,
+    def gbp_endpoint_group_add(self, epg, sclass, bd,
                                rd, uplink_sw_if_index):
         """ GBP endpoint group Add """
         return self.api(self.papi.gbp_endpoint_group_add,
@@ -3596,7 +3596,8 @@ class VppPapiProvider(object):
                              'uplink_sw_if_index': uplink_sw_if_index,
                              'bd_id': bd,
                              'rd_id': rd,
-                             'epg_id': epg
+                             'epg_id': epg,
+                             'sclass': sclass
                          }})
 
     def gbp_endpoint_group_del(self, epg):
@@ -3610,7 +3611,8 @@ class VppPapiProvider(object):
 
     def gbp_bridge_domain_add(self, bd_id, flags,
                               bvi_sw_if_index,
-                              uu_fwd_sw_if_index):
+                              uu_fwd_sw_if_index,
+                              bm_flood_sw_if_index):
         """ GBP bridge-domain Add """
         return self.api(self.papi.gbp_bridge_domain_add,
                         {'bd':
@@ -3618,6 +3620,7 @@ class VppPapiProvider(object):
                              'flags': flags,
                              'bvi_sw_if_index': bvi_sw_if_index,
                              'uu_fwd_sw_if_index': uu_fwd_sw_if_index,
+                             'bm_flood_sw_if_index': bm_flood_sw_if_index,
                              'bd_id': bd_id
                          }})